mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65e59ccf9b | |||
| 61641f9a7a | |||
| 996dc25180 | |||
| 77cf997595 | |||
| 453ae4e955 | |||
| f5602fa3c7 | |||
| 942f7f298b | |||
| 6a4fc260a1 |
@@ -22,4 +22,4 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build -j=2
|
run: cmake --build build -j=2
|
||||||
- name: Test
|
- name: Test
|
||||||
run: ctest --output-on-failure --test-dir build
|
run: ctest --output-on-failure --test-dir build
|
||||||
+8
-39
@@ -12,7 +12,7 @@ endif()
|
|||||||
project(
|
project(
|
||||||
simdjson
|
simdjson
|
||||||
# The version number is modified by tools/release.py
|
# The version number is modified by tools/release.py
|
||||||
VERSION 4.6.1
|
VERSION 4.6.3
|
||||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||||
HOMEPAGE_URL "https://simdjson.org/"
|
HOMEPAGE_URL "https://simdjson.org/"
|
||||||
LANGUAGES CXX C
|
LANGUAGES CXX C
|
||||||
@@ -167,37 +167,13 @@ if(MSVC)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(SIMDJSON_STATIC_REFLECTION)
|
if(SIMDJSON_STATIC_REFLECTION)
|
||||||
|
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION MATCHES "^21")
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${CMAKE_CXX_COMPILER} --version
|
|
||||||
OUTPUT_VARIABLE CLANG_VERSION_OUTPUT
|
|
||||||
ERROR_VARIABLE CLANG_VERSION_ERROR
|
|
||||||
RESULT_VARIABLE CLANG_VERSION_RESULT
|
|
||||||
)
|
|
||||||
if(CLANG_VERSION_RESULT EQUAL 0 AND CLANG_VERSION_OUTPUT MATCHES "https://github.com/bloomberg/clang-p2996.git")
|
|
||||||
set(IS_BLOOMBERG_P2996_CLANG ON)
|
|
||||||
message(STATUS "Using Bloomberg P2996 Clang fork")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# We would like to require C++26, but no compiler supports that!
|
# We would like to require C++26, but no compiler supports that!
|
||||||
# This is a hack:
|
# This is a hack:
|
||||||
if(IS_BLOOMBERG_P2996_CLANG)
|
|
||||||
simdjson_add_props(
|
simdjson_add_props(
|
||||||
target_compile_options PUBLIC
|
target_compile_options PUBLIC
|
||||||
-freflection -fexpansion-statements -stdlib=libc++ -std=c++26
|
-freflection -fexpansion-statements -stdlib=libc++ -std=c++26
|
||||||
)
|
)
|
||||||
else()
|
|
||||||
simdjson_add_props(
|
|
||||||
target_compile_options PUBLIC
|
|
||||||
-freflection -std=c++26
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
else()
|
else()
|
||||||
simdjson_add_props(target_compile_features PUBLIC cxx_std_11)
|
simdjson_add_props(target_compile_features PUBLIC cxx_std_11)
|
||||||
endif()
|
endif()
|
||||||
@@ -411,25 +387,18 @@ add_subdirectory(fuzz)
|
|||||||
#
|
#
|
||||||
# Source files should be just ASCII
|
# Source files should be just ASCII
|
||||||
#
|
#
|
||||||
find_program(FIND_CMD find)
|
find_program(FIND find)
|
||||||
find_program(FILE_CMD file)
|
find_program(FILE file)
|
||||||
find_program(GREP_CMD grep)
|
find_program(GREP grep)
|
||||||
if(FIND_CMD AND FILE_CMD AND GREP_CMD)
|
if(FIND AND FILE AND GREP)
|
||||||
add_test(
|
add_test(
|
||||||
NAME just_ascii
|
NAME just_ascii
|
||||||
COMMAND sh -c "\
|
COMMAND sh -c "\
|
||||||
non_ascii=$(${FIND_CMD} include src windows tools singleheader tests examples benchmark \
|
${FIND} include src windows tools singleheader tests examples benchmark \
|
||||||
-path benchmark/checkperf-reference -prune -name '*.h' -o -name '*.cpp' \
|
-path benchmark/checkperf-reference -prune -name '*.h' -o -name '*.cpp' \
|
||||||
-type f -exec ${FILE_CMD} '{}' \; | ${GREP_CMD} -v ASCII); \
|
-type f -exec ${FILE} '{}' \; | ${GREP} -qv ASCII || exit 0 && exit 1"
|
||||||
if [ -n \"$non_ascii\" ]; then \
|
|
||||||
echo 'The following files contain non-ASCII characters:'; \
|
|
||||||
echo \"$non_ascii\"; \
|
|
||||||
exit 1; \
|
|
||||||
fi"
|
|
||||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||||
)
|
)
|
||||||
else()
|
|
||||||
message(WARNING "just_ascii test disabled because required tools were not found: find='${FIND_CMD}', file='${FILE_CMD}', grep='${GREP_CMD}'")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = "4.6.1"
|
PROJECT_NUMBER = "4.6.3"
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace partial_tweets {
|
|||||||
// {
|
// {
|
||||||
// "created_at": "Sun Aug 31 00:29:15 +0000 2014",
|
// "created_at": "Sun Aug 31 00:29:15 +0000 2014",
|
||||||
// "id": 505874924095815700,
|
// "id": 505874924095815700,
|
||||||
// "text": "@aym0566x ...",
|
// "text": "@aym0566x \n\n名前:前田あゆみ\n第一印象:なんか怖っ!\n今の印象:とりあえずキモい。噛み合わない\n好きなところ:ぶすでキモいとこ😋✨✨\n思い出:んーーー、ありすぎ😊❤️\nLINE交換できる?:あぁ……ごめん✋\nトプ画をみて:照れますがな😘✨\n一言:お前は一生もんのダチ💖",
|
||||||
// "in_reply_to_status_id": null,
|
// "in_reply_to_status_id": null,
|
||||||
// "user": {
|
// "user": {
|
||||||
// "id": 1186275104,
|
// "id": 1186275104,
|
||||||
|
|||||||
+24
-25
@@ -28,6 +28,8 @@ separate document](https://github.com/simdjson/simdjson/blob/master/doc/builder.
|
|||||||
- [UTF-8 validation (alone)](#utf-8-validation-alone)
|
- [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||||
- [JSON Pointer](#json-pointer)
|
- [JSON Pointer](#json-pointer)
|
||||||
- [JSONPath](#jsonpath)
|
- [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)
|
- [Compile-Time JSONPath and JSON Pointer (C++26 Reflection)](#compile-time-jsonpath-and-json-pointer-c26-reflection)
|
||||||
- [Error handling](#error-handling)
|
- [Error handling](#error-handling)
|
||||||
* [Error handling examples without exceptions](#error-handling-examples-without-exceptions)
|
* [Error handling examples without exceptions](#error-handling-examples-without-exceptions)
|
||||||
@@ -379,8 +381,6 @@ tracking explicitly potential programming mistakes. Thus you should not relying
|
|||||||
size (`sizeof`) of our data structures to be constant: they may change depending on the
|
size (`sizeof`) of our data structures to be constant: they may change depending on the
|
||||||
compiler settings.
|
compiler settings.
|
||||||
|
|
||||||
When `SIMDJSON_DEVELOPMENT_CHECKS` is set at compile time, the global variable `simdjson_development_checks_enabled` is defined as true. It is false otherwise.
|
|
||||||
|
|
||||||
Once your code has been tested, you can then run it in
|
Once your code has been tested, you can then run it in
|
||||||
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
|
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
|
||||||
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
|
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
|
||||||
@@ -1302,6 +1302,10 @@ You can also use the custom `Car` type as part of a template such as `std::vecto
|
|||||||
simdjson::ondemand::parser parser;
|
simdjson::ondemand::parser parser;
|
||||||
simdjson::ondemand::document doc = parser.iterate(json);
|
simdjson::ondemand::document doc = parser.iterate(json);
|
||||||
std::vector<Car> cars(doc);
|
std::vector<Car> cars(doc);
|
||||||
|
// visual studio users need an explicit call:
|
||||||
|
// std::vector<Car> cars = doc.get<std::vector<Car>>();
|
||||||
|
// because the compiler does not know whether to convert
|
||||||
|
// doc to an unsigned int or to a vector.
|
||||||
for(Car& c : cars) {
|
for(Car& c : cars) {
|
||||||
std::cout << c.year << std::endl;
|
std::cout << c.year << std::endl;
|
||||||
}
|
}
|
||||||
@@ -1788,15 +1792,15 @@ int64_t x = obj.at_path("$.c.foo.a[1]"); // 20
|
|||||||
x = obj.at_path("$.d.foo2.a.2"); // 30
|
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
|
### 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
|
```cpp
|
||||||
simdjson::padded_string json_string = R"(
|
simdjson::padded_string json_string = R"(
|
||||||
@@ -1825,27 +1829,22 @@ ondemand::parser parser;
|
|||||||
ondemand::document doc = parser.iterate(json_string);
|
ondemand::document doc = parser.iterate(json_string);
|
||||||
|
|
||||||
// Fetch all fields in the address object
|
// Fetch all fields in the address object
|
||||||
std::vector<ondemand::value> values;
|
auto error = doc.for_each_at_path_with_wildcard("$.address.*",
|
||||||
auto error = doc.at_path_with_wildcard("$.address.*").get(values);
|
[](ondemand::value value) {
|
||||||
if (!error) {
|
std::string_view field;
|
||||||
for (auto value : values) {
|
if (value.get(field) == SUCCESS) {
|
||||||
std::string_view field;
|
std::cout << field << std::endl;
|
||||||
if (value.get(field) == SUCCESS) {
|
}
|
||||||
std::cout << field << std::endl;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch all phone numbers
|
// Fetch all phone numbers
|
||||||
error = doc.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values);
|
doc.for_each_at_path_with_wildcard("$.phoneNumbers[*].numbers[*]",
|
||||||
if (!error) {
|
[](ondemand::value value) {
|
||||||
for (auto value : values) {
|
std::string_view number;
|
||||||
std::string_view number;
|
if (value.get(number) == SUCCESS) {
|
||||||
if (value.get(number) == SUCCESS) {
|
std::cout << number << std::endl;
|
||||||
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.
|
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.
|
||||||
|
|||||||
@@ -297,15 +297,6 @@ namespace std {
|
|||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
#endif // SIMDJSON_DEVELOPMENT_CHECKS
|
#endif // SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
|
|
||||||
|
|
||||||
// Prevent ODR violations for the simdjson_development_checks_enabled variable.
|
|
||||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
|
||||||
extern const bool simdjson_development_checks_enabled = true;
|
|
||||||
#else
|
|
||||||
extern const bool simdjson_development_checks_enabled = false;
|
|
||||||
#endif // SIMDJSON_DEVELOPMENT_CHECKS
|
|
||||||
|
|
||||||
|
|
||||||
// The SIMDJSON_CHECK_EOF macro is a feature flag for the "don't require padding"
|
// The SIMDJSON_CHECK_EOF macro is a feature flag for the "don't require padding"
|
||||||
// feature.
|
// feature.
|
||||||
|
|
||||||
|
|||||||
@@ -266,12 +266,6 @@ consteval std::pair<double, size_t> parse_double(const char *src,
|
|||||||
}
|
}
|
||||||
} // namespace number_parsing
|
} // namespace number_parsing
|
||||||
|
|
||||||
consteval auto make_data_member_options(auto&& name_str) {
|
|
||||||
std::meta::data_member_options options{};
|
|
||||||
options.name = std::forward<decltype(name_str)>(name_str);
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON string may contain embedded nulls, and C++26 reflection does not yet
|
// JSON string may contain embedded nulls, and C++26 reflection does not yet
|
||||||
// support std::string_view as a data member type. As a workaround, we define
|
// support std::string_view as a data member type. As a workaround, we define
|
||||||
// a custom type that holds a const char* and a size.
|
// a custom type that holds a const char* and a size.
|
||||||
@@ -326,8 +320,7 @@ using class_type = type_builder<meta_info...>::constructed_type;
|
|||||||
/**
|
/**
|
||||||
* @brief Variable template for constructing instances with values
|
* @brief Variable template for constructing instances with values
|
||||||
*/
|
*/
|
||||||
template <typename T, auto... Vs> constexpr T construct_from = T{Vs...};
|
template <typename T, auto... Vs> constexpr auto construct_from = T{Vs...};
|
||||||
|
|
||||||
|
|
||||||
// in JSON, there are only a few whitespace characters that are allowed
|
// in JSON, there are only a few whitespace characters that are allowed
|
||||||
// outside of objects, arrays, strings, and numbers.
|
// outside of objects, arrays, strings, and numbers.
|
||||||
@@ -417,7 +410,7 @@ parse_number(std::string_view json,
|
|||||||
std::from_chars(json.data(), json.data() + json.size(), int_value);
|
std::from_chars(json.data(), json.data() + json.size(), int_value);
|
||||||
if (res.ec == std::errc()) {
|
if (res.ec == std::errc()) {
|
||||||
out = int_value;
|
out = int_value;
|
||||||
if (static_cast<std::size_t>(res.ptr - json.data()) != scope) {
|
if ((res.ptr - json.data()) != scope) {
|
||||||
simdjson_consteval_error(
|
simdjson_consteval_error(
|
||||||
"Internal error: cannot agree on the character range of the float");
|
"Internal error: cannot agree on the character range of the float");
|
||||||
}
|
}
|
||||||
@@ -431,7 +424,7 @@ parse_number(std::string_view json,
|
|||||||
std::from_chars(json.data(), json.data() + json.size(), uint_value);
|
std::from_chars(json.data(), json.data() + json.size(), uint_value);
|
||||||
if (res.ec == std::errc()) {
|
if (res.ec == std::errc()) {
|
||||||
out = uint_value;
|
out = uint_value;
|
||||||
if (static_cast<std::size_t>(res.ptr - json.data()) != scope) {
|
if ((res.ptr - json.data()) != scope) {
|
||||||
simdjson_consteval_error(
|
simdjson_consteval_error(
|
||||||
"Internal error: cannot agree on the character range of the float");
|
"Internal error: cannot agree on the character range of the float");
|
||||||
}
|
}
|
||||||
@@ -540,7 +533,7 @@ parse_string(std::string_view json) {
|
|||||||
// present, we have an error (isolated high surrogate), which we
|
// present, we have an error (isolated high surrogate), which we
|
||||||
// tolerate by substituting the substitution_code_point.
|
// tolerate by substituting the substitution_code_point.
|
||||||
if (end - cursor < 6 || *cursor != '\\' ||
|
if (end - cursor < 6 || *cursor != '\\' ||
|
||||||
*(cursor + 1) != 'u') {
|
*(cursor + 1) != 'u' > 0xFFFF) {
|
||||||
code_point = substitution_code_point;
|
code_point = substitution_code_point;
|
||||||
} else { // we have \u following the high surrogate
|
} else { // we have \u following the high surrogate
|
||||||
cursor += 2; // skip \u
|
cursor += 2; // skip \u
|
||||||
@@ -894,19 +887,10 @@ parse_json_array_impl(const std::string_view json) {
|
|||||||
std::size_t count = values.size() - 1;
|
std::size_t count = values.size() - 1;
|
||||||
// We assume all elements have the same type as the first element.
|
// We assume all elements have the same type as the first element.
|
||||||
// However, if the array is heterogeneous, we should use std::variant.
|
// However, if the array is heterogeneous, we should use std::variant.
|
||||||
auto elem_type = std::meta::type_of(values[1]);
|
|
||||||
// String literals reflected via reflect_constant_string have type const
|
|
||||||
// char[N], but when passed as template auto parameters they decay to
|
|
||||||
// const char*. Use const char* as the element type so that
|
|
||||||
// construct_from can aggregate-initialize the array.
|
|
||||||
if (std::meta::is_array_type(elem_type) &&
|
|
||||||
std::meta::remove_all_extents(elem_type) == ^^const char) {
|
|
||||||
elem_type = ^^const char *;
|
|
||||||
}
|
|
||||||
auto array_type = std::meta::substitute(
|
auto array_type = std::meta::substitute(
|
||||||
^^std::array,
|
^^std::array,
|
||||||
{
|
{
|
||||||
elem_type, std::meta::reflect_constant(count)});
|
std::meta::type_of(values[1]), std::meta::reflect_constant(count)});
|
||||||
|
|
||||||
// Create array instance with values
|
// Create array instance with values
|
||||||
values[0] = array_type;
|
values[0] = array_type;
|
||||||
@@ -973,7 +957,8 @@ parse_json_object_impl(std::string_view json) {
|
|||||||
simdjson_consteval_error("Expected '}'");
|
simdjson_consteval_error("Expected '}'");
|
||||||
}
|
}
|
||||||
cursor += object_size;
|
cursor += object_size;
|
||||||
auto dms = std::meta::data_member_spec(std::meta::type_of(parsed), make_data_member_options(field_name));
|
auto dms = std::meta::data_member_spec(std::meta::type_of(parsed),
|
||||||
|
{.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(parsed);
|
values.push_back(parsed);
|
||||||
|
|
||||||
@@ -982,7 +967,8 @@ parse_json_object_impl(std::string_view json) {
|
|||||||
case '[': {
|
case '[': {
|
||||||
std::string_view value(cursor, end);
|
std::string_view value(cursor, end);
|
||||||
auto [parsed, array_size] = parse_json_array_impl(value);
|
auto [parsed, array_size] = parse_json_array_impl(value);
|
||||||
auto dms = std::meta::data_member_spec(std::meta::type_of(parsed), make_data_member_options(field_name));
|
auto dms = std::meta::data_member_spec(std::meta::type_of(parsed),
|
||||||
|
{.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(parsed);
|
values.push_back(parsed);
|
||||||
if (*(cursor + array_size - 1) != ']') {
|
if (*(cursor + array_size - 1) != ']') {
|
||||||
@@ -1003,7 +989,8 @@ parse_json_object_impl(std::string_view json) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto dms =
|
auto dms =
|
||||||
std::meta::data_member_spec(^^const char *, make_data_member_options(field_name));
|
std::meta::data_member_spec(^^const char *, {
|
||||||
|
.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(std::meta::reflect_constant_string(value));
|
values.push_back(std::meta::reflect_constant_string(value));
|
||||||
break;
|
break;
|
||||||
@@ -1014,7 +1001,8 @@ parse_json_object_impl(std::string_view json) {
|
|||||||
}
|
}
|
||||||
cursor += 4;
|
cursor += 4;
|
||||||
|
|
||||||
auto dms = std::meta::data_member_spec(^^bool, make_data_member_options(field_name));
|
auto dms = std::meta::data_member_spec(^^bool, {
|
||||||
|
.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(std::meta::reflect_constant(true));
|
values.push_back(std::meta::reflect_constant(true));
|
||||||
break;
|
break;
|
||||||
@@ -1025,7 +1013,8 @@ parse_json_object_impl(std::string_view json) {
|
|||||||
}
|
}
|
||||||
cursor += 5;
|
cursor += 5;
|
||||||
|
|
||||||
auto dms = std::meta::data_member_spec(^^bool, make_data_member_options(field_name));
|
auto dms = std::meta::data_member_spec(^^bool, {
|
||||||
|
.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(std::meta::reflect_constant(false));
|
values.push_back(std::meta::reflect_constant(false));
|
||||||
break;
|
break;
|
||||||
@@ -1036,7 +1025,9 @@ parse_json_object_impl(std::string_view json) {
|
|||||||
}
|
}
|
||||||
cursor += 4;
|
cursor += 4;
|
||||||
|
|
||||||
auto dms = std::meta::data_member_spec(^^std::nullptr_t, make_data_member_options(field_name));
|
auto dms = std::meta::data_member_spec(^^std::nullptr_t,
|
||||||
|
{
|
||||||
|
.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(std::meta::reflect_constant(nullptr));
|
values.push_back(std::meta::reflect_constant(nullptr));
|
||||||
break;
|
break;
|
||||||
@@ -1060,19 +1051,22 @@ parse_json_object_impl(std::string_view json) {
|
|||||||
if (std::holds_alternative<int64_t>(out)) {
|
if (std::holds_alternative<int64_t>(out)) {
|
||||||
int64_t int_value = std::get<int64_t>(out);
|
int64_t int_value = std::get<int64_t>(out);
|
||||||
auto dms =
|
auto dms =
|
||||||
std::meta::data_member_spec(^^int64_t, make_data_member_options(field_name));
|
std::meta::data_member_spec(^^int64_t, {
|
||||||
|
.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(std::meta::reflect_constant(int_value));
|
values.push_back(std::meta::reflect_constant(int_value));
|
||||||
} else if (std::holds_alternative<uint64_t>(out)) {
|
} else if (std::holds_alternative<uint64_t>(out)) {
|
||||||
uint64_t uint_value = std::get<uint64_t>(out);
|
uint64_t uint_value = std::get<uint64_t>(out);
|
||||||
auto dms =
|
auto dms =
|
||||||
std::meta::data_member_spec(^^uint64_t, make_data_member_options(field_name));
|
std::meta::data_member_spec(^^uint64_t, {
|
||||||
|
.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(std::meta::reflect_constant(uint_value));
|
values.push_back(std::meta::reflect_constant(uint_value));
|
||||||
} else {
|
} else {
|
||||||
double float_value = std::get<double>(out);
|
double float_value = std::get<double>(out);
|
||||||
auto dms =
|
auto dms =
|
||||||
std::meta::data_member_spec(^^double, make_data_member_options(field_name));
|
std::meta::data_member_spec(^^double, {
|
||||||
|
.name = field_name});
|
||||||
members.push_back(std::meta::reflect_constant(dms));
|
members.push_back(std::meta::reflect_constant(dms));
|
||||||
values.push_back(std::meta::reflect_constant(float_value));
|
values.push_back(std::meta::reflect_constant(float_value));
|
||||||
}
|
}
|
||||||
@@ -1117,11 +1111,16 @@ template <constevalutil::fixed_string json_str> consteval auto parse_json() {
|
|||||||
"Only JSON objects and arrays are supported at the top level, this "
|
"Only JSON objects and arrays are supported at the top level, this "
|
||||||
"limitation will be lifted in the future.");*/
|
"limitation will be lifted in the future.");*/
|
||||||
|
|
||||||
if constexpr (json.front() == '[') {
|
constexpr auto result = json.front() == '['
|
||||||
return [: parse_json_array_impl(json).first :];
|
? parse_json_array_impl(json)
|
||||||
} else {
|
: parse_json_object_impl(json);
|
||||||
return [: parse_json_object_impl(json).first :];
|
return [: result.first :];
|
||||||
}
|
/*
|
||||||
|
if(json.front() == '[') {
|
||||||
|
return [:parse_json_array_impl(json).first:];
|
||||||
|
} else if(json.front() == '{') {
|
||||||
|
// return [:parse_json_object_impl(json).first:];
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace compile_time
|
} // namespace compile_time
|
||||||
|
|||||||
@@ -58,11 +58,6 @@ struct fixed_string {
|
|||||||
data[i] = str[i];
|
data[i] = str[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constexpr fixed_string(const unsigned char (&str)[N]) {
|
|
||||||
for (std::size_t i = 0; i < N; ++i) {
|
|
||||||
data[i] = static_cast<char>(str[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char data[N];
|
char data[N];
|
||||||
constexpr std::string_view view() const { return {data, N - 1}; }
|
constexpr std::string_view view() const { return {data, N - 1}; }
|
||||||
constexpr size_t size() const { return N ; }
|
constexpr size_t size() const { return N ; }
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace SIMDJSON_IMPLEMENTATION {
|
|||||||
namespace builder {
|
namespace builder {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
requires(concepts::container_but_not_string<T> && ! concepts::optional_type<T> && !require_custom_serialization<T>)
|
requires(concepts::container_but_not_string<T> && !require_custom_serialization<T>)
|
||||||
constexpr void atom(string_builder &b, const T &t) {
|
constexpr void atom(string_builder &b, const T &t) {
|
||||||
auto it = t.begin();
|
auto it = t.begin();
|
||||||
auto end = t.end();
|
auto end = t.end();
|
||||||
@@ -130,7 +130,7 @@ template <typename T>
|
|||||||
requires(std::is_enum_v<T> && !require_custom_serialization<T>)
|
requires(std::is_enum_v<T> && !require_custom_serialization<T>)
|
||||||
void atom(string_builder &b, const T &e) {
|
void atom(string_builder &b, const T &e) {
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
static constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
|
constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
|
||||||
template for (constexpr auto enum_val : enumerators) {
|
template for (constexpr auto enum_val : enumerators) {
|
||||||
constexpr auto enum_str = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(enum_val)));
|
constexpr auto enum_str = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(enum_val)));
|
||||||
if (e == [:enum_val:]) {
|
if (e == [:enum_val:]) {
|
||||||
@@ -294,23 +294,30 @@ string_builder& operator<<(string_builder& b, const Z& z) {
|
|||||||
template<constevalutil::fixed_string... FieldNames, typename T>
|
template<constevalutil::fixed_string... FieldNames, typename T>
|
||||||
requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
|
requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
|
||||||
void extract_from(string_builder &b, const T &obj) {
|
void extract_from(string_builder &b, const T &obj) {
|
||||||
|
// Helper to check if a field name matches any of the requested fields
|
||||||
|
auto should_extract = [](std::string_view field_name) constexpr -> bool {
|
||||||
|
return ((FieldNames.view() == field_name) || ...);
|
||||||
|
};
|
||||||
|
|
||||||
b.append('{');
|
b.append('{');
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
// Iterate through all members of T using reflection
|
// Iterate through all members of T using reflection
|
||||||
static constexpr auto members = std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()));
|
template for (constexpr auto mem : std::define_static_array(
|
||||||
template for (constexpr auto mem : members) {
|
std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
|
||||||
|
|
||||||
if constexpr (std::meta::is_public(mem)) {
|
if constexpr (std::meta::is_public(mem)) {
|
||||||
static constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
|
constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
|
||||||
|
|
||||||
// Only serialize this field if it's in our list of requested fields
|
// Only serialize this field if it's in our list of requested fields
|
||||||
if constexpr (((FieldNames.view() == key) || ...)) {
|
if constexpr (should_extract(key)) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
b.append(',');
|
b.append(',');
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
// Serialize the key
|
// Serialize the key
|
||||||
static constexpr auto quoted_key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(mem)));
|
constexpr auto quoted_key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(mem)));
|
||||||
b.append_raw(quoted_key);
|
b.append_raw(quoted_key);
|
||||||
b.append(':');
|
b.append(':');
|
||||||
|
|
||||||
|
|||||||
@@ -505,7 +505,7 @@ simdjson_inline bool string_builder::capacity_check(size_t upcoming_bytes) {
|
|||||||
return is_valid;
|
return is_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void string_builder::grow_buffer(size_t desired_capacity) {
|
simdjson_inline void string_builder::grow_buffer(size_t desired_capacity) {
|
||||||
if (!is_valid) {
|
if (!is_valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -842,7 +842,7 @@ simdjson_inline void string_builder::append(const T &value) {
|
|||||||
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// Support for range-based appending (std::ranges::view, etc.)
|
// Support for range-based appending (std::ranges::view, etc.)
|
||||||
template <std::ranges::range R>
|
template <std::ranges::range R>
|
||||||
requires(!std::is_convertible<R, std::string_view>::value && !concepts::optional_type<R> && !require_custom_serialization<R>)
|
requires(!std::is_convertible<R, std::string_view>::value && !require_custom_serialization<R>)
|
||||||
simdjson_inline void string_builder::append(const R &range) noexcept {
|
simdjson_inline void string_builder::append(const R &range) noexcept {
|
||||||
auto it = std::ranges::begin(range);
|
auto it = std::ranges::begin(range);
|
||||||
auto end = std::ranges::end(range);
|
auto end = std::ranges::end(range);
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ public:
|
|||||||
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// Support for range-based appending (std::ranges::view, etc.)
|
// Support for range-based appending (std::ranges::view, etc.)
|
||||||
template <std::ranges::range R>
|
template <std::ranges::range R>
|
||||||
requires (!std::is_convertible<R, std::string_view>::value && !concepts::optional_type<R> && !require_custom_serialization<R>)
|
requires (!std::is_convertible<R, std::string_view>::value && !require_custom_serialization<R>)
|
||||||
simdjson_inline void append(const R &range) noexcept;
|
simdjson_inline void append(const R &range) noexcept;
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
@@ -249,7 +249,7 @@ private:
|
|||||||
* If the allocation fails, is_valid is set to false. We expect
|
* If the allocation fails, is_valid is set to false. We expect
|
||||||
* that this function would not be repeatedly called.
|
* that this function would not be repeatedly called.
|
||||||
*/
|
*/
|
||||||
inline void grow_buffer(size_t desired_capacity);
|
simdjson_inline void grow_buffer(size_t desired_capacity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use this helper function to make sure that is_valid is kept consistent.
|
* We use this helper function to make sure that is_valid is kept consistent.
|
||||||
|
|||||||
@@ -170,46 +170,34 @@ inline simdjson_result<value> array::at_path(std::string_view json_path) noexcep
|
|||||||
return at_pointer(json_pointer);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<std::vector<value>> array::at_path_with_wildcard(std::string_view json_path) noexcept {
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
std::vector<value> result;
|
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);
|
auto result_pair = get_next_key_and_json_path(json_path);
|
||||||
std::string_view key = result_pair.first;
|
std::string_view key = result_pair.first;
|
||||||
std::string_view remaining_path = result_pair.second;
|
std::string_view remaining_path = result_pair.second;
|
||||||
// Wildcard case
|
// Wildcard case
|
||||||
if(key=="*"){
|
if (key=="*"){
|
||||||
for(auto element: *this){
|
for(auto element: *this) {
|
||||||
|
value val;
|
||||||
if(element.error()){
|
SIMDJSON_TRY(element.get(val));
|
||||||
return element.error();
|
if (remaining_path.empty()) {
|
||||||
}
|
callback(val);
|
||||||
|
} else {
|
||||||
if(remaining_path.empty()){
|
error_code err = element.for_each_at_path_with_wildcard(remaining_path, callback);
|
||||||
// Use value_unsafe() because we've already checked for errors above.
|
if(err) { return err; }
|
||||||
// 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()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return SUCCESS;
|
||||||
}else{
|
} else {
|
||||||
// Specific index case in which we access the element at the given index
|
// 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'){
|
if(c < '0' || c > '9'){
|
||||||
return INVALID_JSON_POINTER;
|
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);
|
auto element = at(idx);
|
||||||
|
value val;
|
||||||
if(element.error()){
|
SIMDJSON_TRY(element.get(val));
|
||||||
return element.error();
|
if (remaining_path.empty()){
|
||||||
}
|
callback(val);
|
||||||
|
return SUCCESS;
|
||||||
if(remaining_path.empty()){
|
} else {
|
||||||
result.push_back(std::move(element).value_unsafe());
|
return element.for_each_at_path_with_wildcard(remaining_path, callback);
|
||||||
return result;
|
|
||||||
}else{
|
|
||||||
return element.at_path_with_wildcard(remaining_path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -289,9 +274,15 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdj
|
|||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.at_path(json_path);
|
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(); }
|
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 {
|
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::raw_json() noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
|
|||||||
@@ -119,13 +119,21 @@ public:
|
|||||||
inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
|
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.
|
* Supports wildcard patterns like "[*]" to match all array elements.
|
||||||
*
|
*
|
||||||
* @param json_path JSONPath expression with wildcards
|
* @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
|
* 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(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_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<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;
|
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// TODO: move this code into object-inl.h
|
// TODO: move this code into object-inl.h
|
||||||
|
|||||||
@@ -365,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 {
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
rewind(); // Rewind the document each time at_path_with_wildcard is called
|
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()) {
|
if (json_path.empty()) {
|
||||||
return INVALID_JSON_POINTER;
|
return INVALID_JSON_POINTER;
|
||||||
}
|
}
|
||||||
@@ -374,9 +380,9 @@ simdjson_inline simdjson_result<std::vector<value>> document::at_path_with_wildc
|
|||||||
SIMDJSON_TRY(type().get(t));
|
SIMDJSON_TRY(type().get(t));
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case json_type::array:
|
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:
|
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:
|
default:
|
||||||
return INVALID_JSON_POINTER;
|
return INVALID_JSON_POINTER;
|
||||||
}
|
}
|
||||||
@@ -653,27 +659,27 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::op
|
|||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator uint64_t() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator uint64_t() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_uint64();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator int64_t() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator int64_t() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_int64();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator double() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator double() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_double();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator std::string_view() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator std::string_view() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_string();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_raw_json_string();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator bool() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator bool() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_bool();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
@@ -713,9 +719,15 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
|||||||
return first.at_path(json_path);
|
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(); }
|
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
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
@@ -826,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<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_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<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 simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
|
||||||
simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
|
simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
|
||||||
#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
|
||||||
@@ -1042,27 +1060,27 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_refe
|
|||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator uint64_t() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator uint64_t() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_uint64();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator int64_t() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator int64_t() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_int64();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator double() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator double() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_double();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator std::string_view() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator std::string_view() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_string();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_raw_json_string();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator bool() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator bool() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
return first.get_bool();
|
return first;
|
||||||
}
|
}
|
||||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false) {
|
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false) {
|
||||||
if (error()) { throw simdjson_error(error()); }
|
if (error()) { throw simdjson_error(error()); }
|
||||||
@@ -1091,11 +1109,17 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
|||||||
}
|
}
|
||||||
return first.at_path(json_path);
|
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()) {
|
if (error()) {
|
||||||
return 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
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
template<constevalutil::fixed_string... FieldNames, typename T>
|
template<constevalutil::fixed_string... FieldNames, typename T>
|
||||||
|
|||||||
@@ -319,21 +319,21 @@ public:
|
|||||||
* @returns A signed 64-bit integer.
|
* @returns A signed 64-bit integer.
|
||||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
|
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
|
||||||
*/
|
*/
|
||||||
explicit simdjson_inline operator uint64_t() noexcept(false);
|
simdjson_inline operator uint64_t() noexcept(false);
|
||||||
/**
|
/**
|
||||||
* Cast this JSON value to a signed integer.
|
* Cast this JSON value to a signed integer.
|
||||||
*
|
*
|
||||||
* @returns A signed 64-bit integer.
|
* @returns A signed 64-bit integer.
|
||||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
|
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
|
||||||
*/
|
*/
|
||||||
explicit simdjson_inline operator int64_t() noexcept(false);
|
simdjson_inline operator int64_t() noexcept(false);
|
||||||
/**
|
/**
|
||||||
* Cast this JSON value to a double.
|
* Cast this JSON value to a double.
|
||||||
*
|
*
|
||||||
* @returns A double.
|
* @returns A double.
|
||||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
|
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
|
||||||
*/
|
*/
|
||||||
explicit simdjson_inline operator double() noexcept(false);
|
simdjson_inline operator double() noexcept(false);
|
||||||
/**
|
/**
|
||||||
* Cast this JSON value to a string.
|
* Cast this JSON value to a string.
|
||||||
*
|
*
|
||||||
@@ -343,7 +343,7 @@ public:
|
|||||||
* time it parses a document or when it is destroyed.
|
* time it parses a document or when it is destroyed.
|
||||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
|
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
|
||||||
*/
|
*/
|
||||||
explicit simdjson_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound;
|
simdjson_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound;
|
||||||
/**
|
/**
|
||||||
* Cast this JSON value to a raw_json_string.
|
* Cast this JSON value to a raw_json_string.
|
||||||
*
|
*
|
||||||
@@ -352,14 +352,14 @@ public:
|
|||||||
* @returns A pointer to the raw JSON for the given string.
|
* @returns A pointer to the raw JSON for the given string.
|
||||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
|
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
|
||||||
*/
|
*/
|
||||||
explicit simdjson_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound;
|
simdjson_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound;
|
||||||
/**
|
/**
|
||||||
* Cast this JSON value to a bool.
|
* Cast this JSON value to a bool.
|
||||||
*
|
*
|
||||||
* @returns A bool value.
|
* @returns A bool value.
|
||||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
|
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
|
||||||
*/
|
*/
|
||||||
explicit simdjson_inline operator bool() noexcept(false);
|
simdjson_inline operator bool() noexcept(false);
|
||||||
/**
|
/**
|
||||||
* Cast this JSON value to a value when the document is an object or an array.
|
* Cast this JSON value to a value when the document is an object or an array.
|
||||||
*
|
*
|
||||||
@@ -744,21 +744,24 @@ public:
|
|||||||
simdjson_inline simdjson_result<value> at_path(std::string_view json_path) noexcept;
|
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.
|
* 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.
|
* The document will be consumed after this call.
|
||||||
*
|
*
|
||||||
* @param json_path JSONPath expression with wildcards
|
* @param json_path JSONPath expression with wildcards
|
||||||
* @return Vector of values matching the wildcard pattern, or:
|
* @param callback Function called for each matching value
|
||||||
* - INVALID_JSON_POINTER if the JSONPath cannot be parsed
|
* @return error_code indicating success or failure
|
||||||
* - 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
|
|
||||||
*/
|
*/
|
||||||
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
|
* Consumes the document and returns a string_view instance corresponding to the
|
||||||
@@ -945,12 +948,12 @@ public:
|
|||||||
explicit simdjson_inline operator T() noexcept(false);
|
explicit simdjson_inline operator T() noexcept(false);
|
||||||
simdjson_inline operator array() & noexcept(false);
|
simdjson_inline operator array() & noexcept(false);
|
||||||
simdjson_inline operator object() & noexcept(false);
|
simdjson_inline operator object() & noexcept(false);
|
||||||
explicit simdjson_inline operator uint64_t() noexcept(false);
|
simdjson_inline operator uint64_t() noexcept(false);
|
||||||
explicit simdjson_inline operator int64_t() noexcept(false);
|
simdjson_inline operator int64_t() noexcept(false);
|
||||||
explicit simdjson_inline operator double() noexcept(false);
|
simdjson_inline operator double() noexcept(false);
|
||||||
explicit simdjson_inline operator std::string_view() noexcept(false);
|
simdjson_inline operator std::string_view() noexcept(false);
|
||||||
explicit simdjson_inline operator raw_json_string() noexcept(false);
|
simdjson_inline operator raw_json_string() noexcept(false);
|
||||||
explicit simdjson_inline operator bool() noexcept(false);
|
simdjson_inline operator bool() noexcept(false);
|
||||||
simdjson_inline operator value() noexcept(false);
|
simdjson_inline operator value() noexcept(false);
|
||||||
#endif
|
#endif
|
||||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||||
@@ -979,7 +982,13 @@ public:
|
|||||||
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
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_pointer(std::string_view json_pointer) noexcept;
|
||||||
simdjson_inline simdjson_result<value> at_path(std::string_view json_path) 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:
|
private:
|
||||||
document *doc{nullptr};
|
document *doc{nullptr};
|
||||||
@@ -1030,12 +1039,12 @@ public:
|
|||||||
explicit simdjson_inline operator T() noexcept(false);
|
explicit simdjson_inline operator T() noexcept(false);
|
||||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
||||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
|
||||||
explicit simdjson_inline operator uint64_t() noexcept(false);
|
simdjson_inline operator uint64_t() noexcept(false);
|
||||||
explicit simdjson_inline operator int64_t() noexcept(false);
|
simdjson_inline operator int64_t() noexcept(false);
|
||||||
explicit simdjson_inline operator double() noexcept(false);
|
simdjson_inline operator double() noexcept(false);
|
||||||
explicit simdjson_inline operator std::string_view() noexcept(false);
|
simdjson_inline operator std::string_view() noexcept(false);
|
||||||
explicit simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false);
|
||||||
explicit simdjson_inline operator bool() noexcept(false);
|
simdjson_inline operator bool() noexcept(false);
|
||||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false);
|
||||||
#endif
|
#endif
|
||||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||||
@@ -1065,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_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<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
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
template<constevalutil::fixed_string... FieldNames, typename T>
|
template<constevalutil::fixed_string... FieldNames, typename T>
|
||||||
requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
|
requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
|
||||||
@@ -1116,12 +1131,12 @@ public:
|
|||||||
explicit simdjson_inline operator T() noexcept(false);
|
explicit simdjson_inline operator T() noexcept(false);
|
||||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
||||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
|
||||||
explicit simdjson_inline operator uint64_t() noexcept(false);
|
simdjson_inline operator uint64_t() noexcept(false);
|
||||||
explicit simdjson_inline operator int64_t() noexcept(false);
|
simdjson_inline operator int64_t() noexcept(false);
|
||||||
explicit simdjson_inline operator double() noexcept(false);
|
simdjson_inline operator double() noexcept(false);
|
||||||
explicit simdjson_inline operator std::string_view() noexcept(false);
|
simdjson_inline operator std::string_view() noexcept(false);
|
||||||
explicit simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false);
|
||||||
explicit simdjson_inline operator bool() noexcept(false);
|
simdjson_inline operator bool() noexcept(false);
|
||||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false);
|
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false);
|
||||||
#endif
|
#endif
|
||||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||||
@@ -1150,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_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<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
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
template<constevalutil::fixed_string... FieldNames, typename T>
|
template<constevalutil::fixed_string... FieldNames, typename T>
|
||||||
requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
|
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);
|
return at_pointer(json_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline simdjson_result<std::vector<value>> object::at_path_with_wildcard(std::string_view json_path) noexcept {
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
std::vector<value> result;
|
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);
|
auto result_pair = get_next_key_and_json_path(json_path);
|
||||||
std::string_view key = result_pair.first;
|
std::string_view key = result_pair.first;
|
||||||
std::string_view remaining_path = result_pair.second;
|
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) {
|
for (auto field : *this) {
|
||||||
value val;
|
value val;
|
||||||
SIMDJSON_TRY(field.value().get(val));
|
SIMDJSON_TRY(field.value().get(val));
|
||||||
|
|
||||||
if (remaining_path.empty()) {
|
if (remaining_path.empty()) {
|
||||||
result.push_back(std::move(val));
|
callback(val);
|
||||||
} else {
|
} else {
|
||||||
auto nested_result = val.at_path_with_wildcard(remaining_path);
|
SIMDJSON_TRY(val.for_each_at_path_with_wildcard(remaining_path, callback));
|
||||||
|
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
value val;
|
value val;
|
||||||
SIMDJSON_TRY(find_field(key).get(val));
|
SIMDJSON_TRY(find_field(key).get(val));
|
||||||
|
|
||||||
if (remaining_path.empty()) {
|
if (remaining_path.empty()) {
|
||||||
result.push_back(std::move(val));
|
callback(val);
|
||||||
return result;
|
return SUCCESS;
|
||||||
} else {
|
} 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);
|
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(); }
|
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 {
|
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;
|
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.
|
* Supports wildcard patterns like ".*" to match all object fields.
|
||||||
*
|
*
|
||||||
* @param json_path JSONPath expression with wildcards
|
* @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
|
* 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> 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_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<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> reset() noexcept;
|
||||||
inline simdjson_result<bool> is_empty() noexcept;
|
inline simdjson_result<bool> is_empty() noexcept;
|
||||||
inline simdjson_result<size_t> count_fields() & noexcept;
|
inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ simdjson_inline simdjson_warn_unused ondemand::parser& parser::get_parser() {
|
|||||||
return *parser::get_parser_instance();
|
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();
|
auto &parser_instance = parser::get_threadlocal_parser_if_exists();
|
||||||
if (parser_instance) {
|
if (parser_instance) {
|
||||||
parser_instance.reset();
|
parser_instance.reset();
|
||||||
|
|||||||
@@ -388,8 +388,6 @@ public:
|
|||||||
static simdjson_inline bool release_parser();
|
static simdjson_inline bool release_parser();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend bool release_parser();
|
|
||||||
friend ondemand::parser& get_parser();
|
|
||||||
/** Get the thread-local parser instance, allocates it if needed */
|
/** Get the thread-local parser instance, allocates it if needed */
|
||||||
static simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& get_parser_instance();
|
static simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& get_parser_instance();
|
||||||
/** Get the thread-local parser instance, it might be null */
|
/** Get the thread-local parser instance, it might be null */
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
|
|||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
std::string_view str;
|
std::string_view str;
|
||||||
SIMDJSON_TRY(val.get_string().get(str));
|
SIMDJSON_TRY(val.get_string().get(str));
|
||||||
static constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
|
constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
|
||||||
template for (constexpr auto enum_val : enumerators) {
|
template for (constexpr auto enum_val : enumerators) {
|
||||||
if (str == std::meta::identifier_of(enum_val)) {
|
if (str == std::meta::identifier_of(enum_val)) {
|
||||||
out = [:enum_val:];
|
out = [:enum_val:];
|
||||||
|
|||||||
@@ -314,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;
|
json_type t;
|
||||||
SIMDJSON_TRY(type().get(t));
|
SIMDJSON_TRY(type().get(t));
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case json_type::array:
|
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:
|
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:
|
default:
|
||||||
return INVALID_JSON_POINTER;
|
return INVALID_JSON_POINTER;
|
||||||
}
|
}
|
||||||
@@ -585,12 +591,18 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
|||||||
return first.at_path(json_path);
|
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(
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
std::string_view json_path) noexcept {
|
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()) {
|
if (error()) {
|
||||||
return 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
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -698,13 +698,21 @@ public:
|
|||||||
simdjson_inline simdjson_result<value> at_path(std::string_view at_path) noexcept;
|
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.
|
* Supports wildcard character (*) for arrays or ".*" for objects.
|
||||||
*
|
*
|
||||||
* @param json_path JSONPath expression with wildcards
|
* @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:
|
protected:
|
||||||
/**
|
/**
|
||||||
@@ -897,9 +905,23 @@ public:
|
|||||||
simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
|
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_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<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
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
|
#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_H
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||||
|
|
||||||
/** The version of simdjson being used (major.minor.revision) */
|
/** The version of simdjson being used (major.minor.revision) */
|
||||||
#define SIMDJSON_VERSION "4.6.1"
|
#define SIMDJSON_VERSION "4.6.3"
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
enum {
|
enum {
|
||||||
@@ -19,7 +19,7 @@ enum {
|
|||||||
/**
|
/**
|
||||||
* The revision (major.minor.REVISION) of simdjson being used.
|
* The revision (major.minor.REVISION) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_REVISION = 1
|
SIMDJSON_VERSION_REVISION = 3
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"app_name": "MyApp",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"port": 8080,
|
|
||||||
"debug": true,
|
|
||||||
"features": ["logging", "caching"],
|
|
||||||
"database": {
|
|
||||||
"host": "localhost",
|
|
||||||
"port": 5432
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* auto-generated on 2026-04-02 19:14:16 -0400. version 4.6.1 Do not edit! */
|
/* auto-generated on 2026-04-17 17:22:06 -0400. version 4.6.3 Do not edit! */
|
||||||
/* including simdjson.cpp: */
|
/* including simdjson.cpp: */
|
||||||
/* begin file simdjson.cpp */
|
/* begin file simdjson.cpp */
|
||||||
#define SIMDJSON_SRC_SIMDJSON_CPP
|
#define SIMDJSON_SRC_SIMDJSON_CPP
|
||||||
@@ -3168,11 +3168,6 @@ struct fixed_string {
|
|||||||
data[i] = str[i];
|
data[i] = str[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constexpr fixed_string(const unsigned char (&str)[N]) {
|
|
||||||
for (std::size_t i = 0; i < N; ++i) {
|
|
||||||
data[i] = static_cast<char>(str[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char data[N];
|
char data[N];
|
||||||
constexpr std::string_view view() const { return {data, N - 1}; }
|
constexpr std::string_view view() const { return {data, N - 1}; }
|
||||||
constexpr size_t size() const { return N ; }
|
constexpr size_t size() const { return N ; }
|
||||||
|
|||||||
+2350
-1447
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -6,40 +6,40 @@
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
struct Car {
|
struct Car {
|
||||||
std::string make{};
|
std::string make;
|
||||||
std::string model{};
|
std::string model;
|
||||||
int64_t year{};
|
int64_t year;
|
||||||
std::vector<double> tire_pressure{};
|
std::vector<double> tire_pressure;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kid {
|
struct kid {
|
||||||
int age{};
|
int age;
|
||||||
std::string name{};
|
std::string name;
|
||||||
std::vector<std::string> toys{};
|
std::vector<std::string> toys;
|
||||||
bool operator<=> (const kid&) const = default;
|
bool operator<=> (const kid&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Z {
|
struct Z {
|
||||||
int x{};
|
int x;
|
||||||
bool operator<=> (const Z&) const = default;
|
bool operator<=> (const Z&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Y {
|
struct Y {
|
||||||
int g{};
|
int g;
|
||||||
std::string h{};
|
std::string h;
|
||||||
std::vector<int> i{};
|
std::vector<int> i;
|
||||||
Z z{};
|
Z z;
|
||||||
bool operator<=> (const Y&) const = default;
|
bool operator<=> (const Y&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct X {
|
struct X {
|
||||||
char a{};
|
char a;
|
||||||
int b{};
|
int b;
|
||||||
int c{};
|
int c;
|
||||||
std::string d{};
|
std::string d;
|
||||||
std::vector<int> e{};
|
std::vector<int> e;
|
||||||
std::vector<std::string> f{};
|
std::vector<std::string> f;
|
||||||
Y y{};
|
Y y;
|
||||||
bool operator<=> (const X&) const = default;
|
bool operator<=> (const X&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ namespace builder_tests {
|
|||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
// Custom type for testing tag_invoke with extract_into
|
// Custom type for testing tag_invoke with extract_into
|
||||||
struct Price {
|
struct Price {
|
||||||
double amount{};
|
double amount;
|
||||||
std::string currency{};
|
std::string currency;
|
||||||
|
|
||||||
// Custom deserializer that applies currency conversion
|
// Custom deserializer that applies currency conversion
|
||||||
friend error_code tag_invoke(deserialize_tag,
|
friend error_code tag_invoke(deserialize_tag,
|
||||||
@@ -46,37 +46,17 @@ namespace builder_tests {
|
|||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
struct Car {
|
|
||||||
std::string make{};
|
|
||||||
std::string model{};
|
|
||||||
int year{};
|
|
||||||
double price{};
|
|
||||||
bool electric{};
|
|
||||||
};
|
|
||||||
struct CarOpt {
|
|
||||||
std::string make;
|
|
||||||
std::string model;
|
|
||||||
int year;
|
|
||||||
double price;
|
|
||||||
std::optional<std::string> color;
|
|
||||||
};
|
|
||||||
struct CarColor {
|
|
||||||
std::string make;
|
|
||||||
std::string model;
|
|
||||||
int year;
|
|
||||||
double price;
|
|
||||||
std::string color;
|
|
||||||
};
|
|
||||||
struct Product {
|
struct Product {
|
||||||
std::string name{};
|
std::string name;
|
||||||
Price price{}; // Custom deserializable type
|
Price price; // Custom deserializable type
|
||||||
int stock{};
|
int stock;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Another custom type for testing
|
// Another custom type for testing
|
||||||
struct Dimensions {
|
struct Dimensions {
|
||||||
double value{};
|
double value;
|
||||||
std::string unit{};
|
std::string unit;
|
||||||
|
|
||||||
// Custom deserializer that converts to metric
|
// Custom deserializer that converts to metric
|
||||||
friend error_code tag_invoke(deserialize_tag,
|
friend error_code tag_invoke(deserialize_tag,
|
||||||
@@ -109,13 +89,6 @@ namespace builder_tests {
|
|||||||
Dimensions weight;
|
Dimensions weight;
|
||||||
Dimensions length;
|
Dimensions length;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Person {
|
|
||||||
std::string name;
|
|
||||||
int age;
|
|
||||||
std::optional<std::string> email;
|
|
||||||
std::optional<std::string> phone;
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool test_primitive_types() {
|
bool test_primitive_types() {
|
||||||
@@ -159,8 +132,8 @@ namespace builder_tests {
|
|||||||
TEST_START();
|
TEST_START();
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
struct StringTypes {
|
struct StringTypes {
|
||||||
std::string string_val{};
|
std::string string_val;
|
||||||
std::string_view string_view_val{};
|
std::string_view string_view_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
StringTypes test{"hello world", "test_view"};
|
StringTypes test{"hello world", "test_view"};
|
||||||
@@ -186,10 +159,10 @@ namespace builder_tests {
|
|||||||
TEST_START();
|
TEST_START();
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
struct OptionalTypes {
|
struct OptionalTypes {
|
||||||
std::optional<int> opt_int_with_value{};
|
std::optional<int> opt_int_with_value;
|
||||||
std::optional<std::string> opt_string_with_value{};
|
std::optional<std::string> opt_string_with_value;
|
||||||
std::optional<int> opt_int_null{};
|
std::optional<int> opt_int_null;
|
||||||
std::optional<std::string> opt_string_null{};
|
std::optional<std::string> opt_string_null;
|
||||||
};
|
};
|
||||||
|
|
||||||
OptionalTypes test;
|
OptionalTypes test;
|
||||||
@@ -227,11 +200,11 @@ namespace builder_tests {
|
|||||||
TEST_START();
|
TEST_START();
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
struct SmartPointerTypes {
|
struct SmartPointerTypes {
|
||||||
std::unique_ptr<int> unique_int_with_value{};
|
std::unique_ptr<int> unique_int_with_value;
|
||||||
std::shared_ptr<std::string> shared_string_with_value{};
|
std::shared_ptr<std::string> shared_string_with_value;
|
||||||
std::unique_ptr<bool> unique_bool_with_value{};
|
std::unique_ptr<bool> unique_bool_with_value;
|
||||||
std::unique_ptr<int> unique_int_null{};
|
std::unique_ptr<int> unique_int_null;
|
||||||
std::shared_ptr<std::string> shared_string_null{};
|
std::shared_ptr<std::string> shared_string_null;
|
||||||
};
|
};
|
||||||
|
|
||||||
SmartPointerTypes test;
|
SmartPointerTypes test;
|
||||||
@@ -272,9 +245,9 @@ namespace builder_tests {
|
|||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
// Test basic container types
|
// Test basic container types
|
||||||
struct ContainerTypes {
|
struct ContainerTypes {
|
||||||
std::vector<int> int_vector{};
|
std::vector<int> int_vector;
|
||||||
std::set<std::string> string_set{};
|
std::set<std::string> string_set;
|
||||||
std::map<std::string, int> string_map{};
|
std::map<std::string, int> string_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
ContainerTypes test;
|
ContainerTypes test;
|
||||||
@@ -305,8 +278,8 @@ namespace builder_tests {
|
|||||||
|
|
||||||
// Test std::list with iterator-based serialization
|
// Test std::list with iterator-based serialization
|
||||||
struct ListContainer {
|
struct ListContainer {
|
||||||
std::list<int> int_list{};
|
std::list<int> int_list;
|
||||||
std::list<std::string> string_list{};
|
std::list<std::string> string_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
ListContainer list_test;
|
ListContainer list_test;
|
||||||
@@ -346,7 +319,13 @@ namespace builder_tests {
|
|||||||
bool test_extract_into() {
|
bool test_extract_into() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int year;
|
||||||
|
double price;
|
||||||
|
std::optional<std::string> color;
|
||||||
|
};
|
||||||
|
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
|
|
||||||
@@ -362,7 +341,7 @@ namespace builder_tests {
|
|||||||
"transmission": "Automatic"
|
"transmission": "Automatic"
|
||||||
})"_padded;
|
})"_padded;
|
||||||
|
|
||||||
CarOpt car{};
|
Car car{};
|
||||||
ondemand::document doc;
|
ondemand::document doc;
|
||||||
ASSERT_SUCCESS( parser.iterate(padded).get(doc) );
|
ASSERT_SUCCESS( parser.iterate(padded).get(doc) );
|
||||||
|
|
||||||
@@ -398,7 +377,7 @@ namespace builder_tests {
|
|||||||
"color": "Red"
|
"color": "Red"
|
||||||
})"_padded;
|
})"_padded;
|
||||||
|
|
||||||
CarOpt car{};
|
Car car{};
|
||||||
ondemand::document doc;
|
ondemand::document doc;
|
||||||
ASSERT_SUCCESS(parser.iterate(padded).get(doc));
|
ASSERT_SUCCESS(parser.iterate(padded).get(doc));
|
||||||
|
|
||||||
@@ -423,7 +402,7 @@ namespace builder_tests {
|
|||||||
"price": 35999.99
|
"price": 35999.99
|
||||||
})"_padded;
|
})"_padded;
|
||||||
|
|
||||||
CarOpt car{};
|
Car car{};
|
||||||
ondemand::document doc;
|
ondemand::document doc;
|
||||||
ASSERT_SUCCESS(parser.iterate(padded).get(doc));
|
ASSERT_SUCCESS(parser.iterate(padded).get(doc));
|
||||||
|
|
||||||
@@ -516,6 +495,13 @@ namespace builder_tests {
|
|||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
// Test 1: Extract specific fields from Car struct
|
// Test 1: Extract specific fields from Car struct
|
||||||
{
|
{
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int year;
|
||||||
|
double price;
|
||||||
|
bool electric;
|
||||||
|
};
|
||||||
|
|
||||||
Car car{"Tesla", "Model 3", 2023, 42000.0, true};
|
Car car{"Tesla", "Model 3", 2023, 42000.0, true};
|
||||||
|
|
||||||
@@ -547,7 +533,13 @@ namespace builder_tests {
|
|||||||
|
|
||||||
// Test 2: Extract different field combination
|
// Test 2: Extract different field combination
|
||||||
{
|
{
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int year;
|
||||||
|
double price;
|
||||||
|
bool electric;
|
||||||
|
};
|
||||||
|
|
||||||
Car car{"Ford", "F-150", 2024, 55000.0, false};
|
Car car{"Ford", "F-150", 2024, 55000.0, false};
|
||||||
|
|
||||||
@@ -574,6 +566,13 @@ namespace builder_tests {
|
|||||||
|
|
||||||
// Test 3: Extract from struct with optional fields
|
// Test 3: Extract from struct with optional fields
|
||||||
{
|
{
|
||||||
|
struct Person {
|
||||||
|
std::string name;
|
||||||
|
int age;
|
||||||
|
std::optional<std::string> email;
|
||||||
|
std::optional<std::string> phone;
|
||||||
|
};
|
||||||
|
|
||||||
Person person{"John Doe", 30, "john@example.com", std::nullopt};
|
Person person{"John Doe", 30, "john@example.com", std::nullopt};
|
||||||
|
|
||||||
// Extract name and email
|
// Extract name and email
|
||||||
@@ -595,6 +594,13 @@ namespace builder_tests {
|
|||||||
|
|
||||||
// Test 4: Extract with optional that has value
|
// Test 4: Extract with optional that has value
|
||||||
{
|
{
|
||||||
|
struct Person {
|
||||||
|
std::string name;
|
||||||
|
int age;
|
||||||
|
std::optional<std::string> email;
|
||||||
|
std::optional<std::string> phone;
|
||||||
|
};
|
||||||
|
|
||||||
Person person{"Jane Smith", 25, "jane@example.com", "555-1234"};
|
Person person{"Jane Smith", 25, "jane@example.com", "555-1234"};
|
||||||
|
|
||||||
// Extract name, age, and phone
|
// Extract name, age, and phone
|
||||||
@@ -623,21 +629,21 @@ namespace builder_tests {
|
|||||||
|
|
||||||
// Test 5: Round-trip test - serialize with extract_from, deserialize with extract_into
|
// Test 5: Round-trip test - serialize with extract_from, deserialize with extract_into
|
||||||
{
|
{
|
||||||
struct MyProduct {
|
struct Product {
|
||||||
std::string id{};
|
std::string id;
|
||||||
std::string name{};
|
std::string name;
|
||||||
double price{};
|
double price;
|
||||||
int stock{};
|
int stock;
|
||||||
};
|
};
|
||||||
|
|
||||||
MyProduct original{"P123", "Widget", 19.99, 100};
|
Product original{"P123", "Widget", 19.99, 100};
|
||||||
|
|
||||||
// Extract specific fields to JSON
|
// Extract specific fields to JSON
|
||||||
std::string json;
|
std::string json;
|
||||||
ASSERT_SUCCESS((extract_from<"id", "name", "price">(original).get(json)));
|
ASSERT_SUCCESS((extract_from<"id", "name", "price">(original).get(json)));
|
||||||
|
|
||||||
// Parse and extract back
|
// Parse and extract back
|
||||||
MyProduct restored{"", "", 0.0, 0};
|
Product restored{"", "", 0.0, 0};
|
||||||
auto padded = pad(json);
|
auto padded = pad(json);
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(padded);
|
auto doc = parser.iterate(padded);
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ using namespace simdjson;
|
|||||||
// Suppose that we want to serialize/deserialize Car using
|
// Suppose that we want to serialize/deserialize Car using
|
||||||
// strings for the year
|
// strings for the year
|
||||||
struct Car {
|
struct Car {
|
||||||
std::string make{};
|
std::string make;
|
||||||
std::string model{};
|
std::string model;
|
||||||
int64_t year{};
|
int64_t year;
|
||||||
std::vector<float> tire_pressure{};
|
std::vector<float> tire_pressure;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ namespace builder_tests {
|
|||||||
TEST_START();
|
TEST_START();
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
struct EmptyValues {
|
struct EmptyValues {
|
||||||
std::string empty_string{};
|
std::string empty_string;
|
||||||
std::vector<int> empty_vector{};
|
std::vector<int> empty_vector;
|
||||||
std::optional<int> null_optional{};
|
std::optional<int> null_optional;
|
||||||
std::unique_ptr<int> null_unique_ptr{};
|
std::unique_ptr<int> null_unique_ptr;
|
||||||
std::shared_ptr<std::string> null_shared_ptr{};
|
std::shared_ptr<std::string> null_shared_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
EmptyValues test;
|
EmptyValues test;
|
||||||
@@ -56,18 +56,18 @@ namespace builder_tests {
|
|||||||
TEST_START();
|
TEST_START();
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
struct SpecialChars {
|
struct SpecialChars {
|
||||||
std::string quotes{};
|
std::string quotes;
|
||||||
std::string backslashes{};
|
std::string backslashes;
|
||||||
std::string newlines{};
|
std::string newlines;
|
||||||
std::string unicode{};
|
std::string unicode;
|
||||||
char null_char{};
|
char null_char;
|
||||||
};
|
};
|
||||||
|
|
||||||
SpecialChars test;
|
SpecialChars test;
|
||||||
test.quotes = "He said \"Hello\"";
|
test.quotes = "He said \"Hello\"";
|
||||||
test.backslashes = "Path\\to\\file";
|
test.backslashes = "Path\\to\\file";
|
||||||
test.newlines = "Line1\nLine2\tTabbed";
|
test.newlines = "Line1\nLine2\tTabbed";
|
||||||
test.unicode = "Caf\xc3\xa9 r\xc3\xa9sum\xc3\xa9";
|
test.unicode = "Café résumé";
|
||||||
test.null_char = '\0';
|
test.null_char = '\0';
|
||||||
|
|
||||||
std::string json;
|
std::string json;
|
||||||
@@ -82,10 +82,10 @@ namespace builder_tests {
|
|||||||
|
|
||||||
// Test round-trip (excluding null char which has special handling)
|
// Test round-trip (excluding null char which has special handling)
|
||||||
struct SpecialCharsNoNull {
|
struct SpecialCharsNoNull {
|
||||||
std::string quotes{};
|
std::string quotes;
|
||||||
std::string backslashes{};
|
std::string backslashes;
|
||||||
std::string newlines{};
|
std::string newlines;
|
||||||
std::string unicode{};
|
std::string unicode;
|
||||||
};
|
};
|
||||||
|
|
||||||
SpecialCharsNoNull test_no_null;
|
SpecialCharsNoNull test_no_null;
|
||||||
@@ -157,15 +157,15 @@ namespace builder_tests {
|
|||||||
TEST_START();
|
TEST_START();
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
struct Inner {
|
struct Inner {
|
||||||
int value{};
|
int value;
|
||||||
std::string name{};
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Outer {
|
struct Outer {
|
||||||
Inner inner_obj{};
|
Inner inner_obj;
|
||||||
std::vector<Inner> inner_vector{};
|
std::vector<Inner> inner_vector;
|
||||||
std::optional<Inner> optional_inner{};
|
std::optional<Inner> optional_inner;
|
||||||
std::unique_ptr<Inner> unique_inner{};
|
std::unique_ptr<Inner> unique_inner;
|
||||||
};
|
};
|
||||||
|
|
||||||
Outer test;
|
Outer test;
|
||||||
@@ -213,4 +213,4 @@ namespace builder_tests {
|
|||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
return test_main(argc, argv, builder_tests::run);
|
return test_main(argc, argv, builder_tests::run);
|
||||||
}
|
}
|
||||||
@@ -51,8 +51,8 @@ namespace builder_tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct StatusStruct {
|
struct StatusStruct {
|
||||||
Status status{};
|
Status status;
|
||||||
std::string name{};
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Test deserialization of different enum values with string representation
|
// Test deserialization of different enum values with string representation
|
||||||
@@ -104,9 +104,9 @@ namespace builder_tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Task {
|
struct Task {
|
||||||
Priority priority{};
|
Priority priority;
|
||||||
std::string description{};
|
std::string description;
|
||||||
int id{};
|
int id;
|
||||||
};
|
};
|
||||||
|
|
||||||
Task original{Priority::High, "Important task", 123};
|
Task original{Priority::High, "Important task", 123};
|
||||||
@@ -144,8 +144,8 @@ namespace builder_tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Response {
|
struct Response {
|
||||||
ErrorCode error{};
|
ErrorCode error;
|
||||||
std::string message{};
|
std::string message;
|
||||||
};
|
};
|
||||||
|
|
||||||
Response test{ErrorCode::NotFound, "Resource not found"};
|
Response test{ErrorCode::NotFound, "Resource not found"};
|
||||||
|
|||||||
@@ -8,26 +8,26 @@ using namespace simdjson;
|
|||||||
|
|
||||||
// Test structures for FracturedJson builder integration
|
// Test structures for FracturedJson builder integration
|
||||||
struct SimpleUser {
|
struct SimpleUser {
|
||||||
int id{};
|
int id;
|
||||||
std::string name{};
|
std::string name;
|
||||||
bool active{};
|
bool active;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UserWithEmail {
|
struct UserWithEmail {
|
||||||
int id{};
|
int id;
|
||||||
std::string name{};
|
std::string name;
|
||||||
std::string email{};
|
std::string email;
|
||||||
bool active{};
|
bool active;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NestedData {
|
struct NestedData {
|
||||||
std::string title{};
|
std::string title;
|
||||||
std::vector<SimpleUser> users{};
|
std::vector<SimpleUser> users;
|
||||||
int count{};
|
int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TableTestData {
|
struct TableTestData {
|
||||||
std::vector<SimpleUser> records{};
|
std::vector<SimpleUser> records;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace fractured_json_builder_tests {
|
namespace fractured_json_builder_tests {
|
||||||
|
|||||||
@@ -666,27 +666,27 @@ bool test_array_of_objects_with_concept() {
|
|||||||
/**
|
/**
|
||||||
* Test: #embed support for external JSON files (C++26)
|
* Test: #embed support for external JSON files (C++26)
|
||||||
*/
|
*/
|
||||||
bool test_embed_example_config_json() {
|
bool test_embed_twitter_json() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
|
|
||||||
// C++26 #embed allows embedding files directly into the binary at compile time
|
// C++26 #embed allows embedding files directly into the binary at compile time
|
||||||
// This creates a const char array with the file contents plus null terminator
|
// This creates a const char array with the file contents plus null terminator
|
||||||
constexpr const unsigned char example_config_json[] = {
|
constexpr const char twitter_json[] = {
|
||||||
#embed "../../jsonexamples/example_config.json"
|
#embed TWITTER_JSON
|
||||||
, 0
|
, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse the embedded JSON at compile time
|
// Parse the embedded JSON at compile time
|
||||||
constexpr auto parsed_example_config = simdjson::compile_time::parse_json<example_config_json>();
|
constexpr auto parsed_twitter = simdjson::compile_time::parse_json<twitter_json>();
|
||||||
|
|
||||||
// Verify the structure - example_config.json should have an "app_name" field
|
// Verify the structure - twitter.json should have a "statuses" array
|
||||||
static_assert(std::string_view(parsed_example_config.app_name) == "MyApp");
|
static_assert(parsed_twitter.statuses.size() > 0);
|
||||||
|
|
||||||
// Runtime verification
|
// Runtime verification
|
||||||
ASSERT_TRUE(std::string_view(parsed_example_config.app_name) == "MyApp");
|
ASSERT_TRUE(parsed_twitter.statuses.size() > 0);
|
||||||
|
|
||||||
std::cout << "Successfully parsed embedded example_config.json with "
|
std::cout << "Successfully parsed embedded twitter.json with "
|
||||||
<< parsed_example_config.app_name << " as app_name" << std::endl;
|
<< parsed_twitter.statuses.size() << " statuses" << std::endl;
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -718,10 +718,11 @@ bool run() {
|
|||||||
test_top_level_array_example() &&
|
test_top_level_array_example() &&
|
||||||
test_array_of_objects_with_concept()
|
test_array_of_objects_with_concept()
|
||||||
#ifdef TEST_EMBED_SUPPORTED
|
#ifdef TEST_EMBED_SUPPORTED
|
||||||
&& test_embed_example_config_json()
|
&& test_embed_twitter_json()
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace compile_time_json_tests
|
} // namespace compile_time_json_tests
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace big_integer_tests {
|
|||||||
std::string output = simdjson::to_string(doc);
|
std::string output = simdjson::to_string(doc);
|
||||||
// Raw digits should appear
|
// Raw digits should appear
|
||||||
ASSERT_TRUE(output.find("123456789012345678901") != std::string::npos);
|
ASSERT_TRUE(output.find("123456789012345678901") != std::string::npos);
|
||||||
// Must not be quoted - it's a number, not a string
|
// Must not be quoted — it's a number, not a string
|
||||||
ASSERT_EQUAL(output.find("\"123456789012345678901\""), std::string::npos);
|
ASSERT_EQUAL(output.find("\"123456789012345678901\""), std::string::npos);
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -475,11 +475,11 @@ bool unicode_test() {
|
|||||||
std::cout << "Running " << __func__ << std::endl;
|
std::cout << "Running " << __func__ << std::endl;
|
||||||
|
|
||||||
const char* json = R"({
|
const char* json = R"({
|
||||||
"greeting": "Hello, \u4e16\u754c!",
|
"greeting": "Hello, 世界!",
|
||||||
"emoji": "\ud83c\udf89\ud83d\ude80\u2728",
|
"emoji": "🎉🚀✨",
|
||||||
"arabic": "\u0645\u0631\u062d\u0628\u0627",
|
"arabic": "مرحبا",
|
||||||
"russian": "\u041f\u0440\u0438\u0432\u0435\u0442",
|
"russian": "Привет",
|
||||||
"mixed": "caf\u00e9 r\u00e9sum\u00e9 na\u00efve"
|
"mixed": "café résumé naïve"
|
||||||
})";
|
})";
|
||||||
|
|
||||||
simdjson::dom::parser parser;
|
simdjson::dom::parser parser;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public:
|
|||||||
return date_str;
|
return date_str;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::string date_str{};
|
std::string date_str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -52,8 +52,8 @@ auto tag_invoke(deserialize_tag, simdjson_value &val, MyDate& date) {
|
|||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
struct complicated_weather_data {
|
struct complicated_weather_data {
|
||||||
std::vector<MyDate> time{};
|
std::vector<MyDate> time;
|
||||||
std::vector<float> temperature{};
|
std::vector<float> temperature;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -152,19 +152,19 @@ simdjson::padded_string json_cars =
|
|||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
struct Player {
|
struct Player {
|
||||||
std::string username{};
|
std::string username;
|
||||||
int level{};
|
int level;
|
||||||
double health{};
|
double health;
|
||||||
};
|
};
|
||||||
struct BadPlayer {
|
struct BadPlayer {
|
||||||
int username{}; // Oops, should be string!
|
int username; // Oops, should be string!
|
||||||
int level{};
|
int level;
|
||||||
double health{};
|
double health;
|
||||||
};
|
};
|
||||||
struct OptionalPlayer {
|
struct OptionalPlayer {
|
||||||
std::string username{};
|
std::string username;
|
||||||
std::optional<int> level{};
|
std::optional<int> level;
|
||||||
double health{};
|
double health;
|
||||||
};
|
};
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
bool missing_key_player() {
|
bool missing_key_player() {
|
||||||
|
|||||||
@@ -177,6 +177,68 @@ simdjson_inline simdjson_result<Car> simdjson::ondemand::document::get() & noexc
|
|||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#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() {
|
void main_capture() {
|
||||||
padded_string json_padded = "{\"a\":[1,2,3], \"b\": 2, \"c\": \"hello\"}"_padded;
|
padded_string json_padded = "{\"a\":[1,2,3], \"b\": 2, \"c\": \"hello\"}"_padded;
|
||||||
std::vector<std::string_view> fields;
|
std::vector<std::string_view> fields;
|
||||||
@@ -2016,6 +2078,7 @@ bool value_raw_json_object() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
return true
|
return true
|
||||||
&& fatal_error()
|
&& fatal_error()
|
||||||
@@ -2075,6 +2138,7 @@ bool run() {
|
|||||||
&& current_location_no_error()
|
&& current_location_no_error()
|
||||||
&& to_string_example_no_except()
|
&& to_string_example_no_except()
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
&& wildcard_basics_example()
|
||||||
&& issue2215()
|
&& issue2215()
|
||||||
&& to_string_example()
|
&& to_string_example()
|
||||||
&& raw_string()
|
&& raw_string()
|
||||||
|
|||||||
@@ -21,18 +21,16 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> titles;
|
std::vector<std::string_view> titles;
|
||||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.books[*].title").get(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);
|
ASSERT_EQUAL(titles.size(), 3);
|
||||||
|
ASSERT_EQUAL(titles[0], "Book A");
|
||||||
std::string_view title;
|
ASSERT_EQUAL(titles[1], "Book B");
|
||||||
ASSERT_SUCCESS(titles[0].get_string().get(title));
|
ASSERT_EQUAL(titles[2], "Book C");
|
||||||
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");
|
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -46,18 +44,16 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> prices;
|
std::vector<uint64_t> prices;
|
||||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.prices[*]").get(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);
|
ASSERT_EQUAL(prices.size(), 5);
|
||||||
|
ASSERT_EQUAL(prices[0], 10);
|
||||||
uint64_t price;
|
ASSERT_EQUAL(prices[2], 30);
|
||||||
ASSERT_SUCCESS(prices[0].get_uint64().get(price));
|
ASSERT_EQUAL(prices[4], 50);
|
||||||
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);
|
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -75,19 +71,14 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> names;
|
std::set<std::string_view> name_set;
|
||||||
auto error = doc.at_path_with_wildcard("$.users.*.name").get(names);
|
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_SUCCESS(error);
|
||||||
|
|
||||||
ASSERT_EQUAL(names.size(), 3);
|
ASSERT_EQUAL(name_set.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_TRUE(name_set.count("Alice") > 0);
|
ASSERT_TRUE(name_set.count("Alice") > 0);
|
||||||
ASSERT_TRUE(name_set.count("Bob") > 0);
|
ASSERT_TRUE(name_set.count("Bob") > 0);
|
||||||
ASSERT_TRUE(name_set.count("Charlie") > 0);
|
ASSERT_TRUE(name_set.count("Charlie") > 0);
|
||||||
@@ -117,19 +108,15 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> salaries;
|
uint64_t total = 0;
|
||||||
auto error = doc.at_path_with_wildcard("$.departments.*.employees[*].salary").get(salaries);
|
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_SUCCESS(error);
|
||||||
|
|
||||||
ASSERT_EQUAL(salaries.size(), 4);
|
ASSERT_EQUAL(count, 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(total, 360000);
|
ASSERT_EQUAL(total, 360000);
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
@@ -142,11 +129,12 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> items;
|
size_t count = 0;
|
||||||
auto error = doc.at_path_with_wildcard("$.items[*].name").get(items);
|
auto error = doc.for_each_at_path_with_wildcard("$.items[*].name", [&](ondemand::value) {
|
||||||
|
count++;
|
||||||
|
});
|
||||||
ASSERT_SUCCESS(error);
|
ASSERT_SUCCESS(error);
|
||||||
|
ASSERT_EQUAL(count, 0);
|
||||||
ASSERT_EQUAL(items.size(), 0);
|
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -158,11 +146,12 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> names;
|
size_t count = 0;
|
||||||
auto error = doc.at_path_with_wildcard("$.users.*.name").get(names);
|
auto error = doc.for_each_at_path_with_wildcard("$.users.*.name", [&](ondemand::value) {
|
||||||
|
count++;
|
||||||
|
});
|
||||||
ASSERT_SUCCESS(error);
|
ASSERT_SUCCESS(error);
|
||||||
|
ASSERT_EQUAL(count, 0);
|
||||||
ASSERT_EQUAL(names.size(), 0);
|
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -175,8 +164,7 @@ namespace wildcard_tests {
|
|||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
// Can't use array wildcard on scalar
|
// Can't use array wildcard on scalar
|
||||||
std::vector<ondemand::value> values;
|
auto error = doc.for_each_at_path_with_wildcard("$.data[*]", [](ondemand::value) {});
|
||||||
auto error = doc.at_path_with_wildcard("$.data[*]").get(values);
|
|
||||||
ASSERT_ERROR(error, INVALID_JSON_POINTER);
|
ASSERT_ERROR(error, INVALID_JSON_POINTER);
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
@@ -195,12 +183,12 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
// Get all nested arrays
|
size_t count = 0;
|
||||||
std::vector<ondemand::value> arrays;
|
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$.matrix[*]", [&](ondemand::value) {
|
||||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.matrix[*]").get(arrays));
|
count++;
|
||||||
|
}));
|
||||||
|
|
||||||
// Verify we got 3 arrays
|
ASSERT_EQUAL(count, 3);
|
||||||
ASSERT_EQUAL(arrays.size(), 3);
|
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -218,18 +206,16 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> statuses;
|
std::vector<std::string_view> statuses;
|
||||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.data[*].info.status").get(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);
|
ASSERT_EQUAL(statuses.size(), 3);
|
||||||
|
ASSERT_EQUAL(statuses[0], "active");
|
||||||
std::string_view status;
|
ASSERT_EQUAL(statuses[1], "inactive");
|
||||||
ASSERT_SUCCESS(statuses[0].get_string().get(status));
|
ASSERT_EQUAL(statuses[2], "active");
|
||||||
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");
|
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -250,13 +236,12 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> values;
|
size_t count = 0;
|
||||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$.mixed[*]").get(values));
|
ASSERT_SUCCESS(doc.for_each_at_path_with_wildcard("$.mixed[*]", [&](ondemand::value) {
|
||||||
|
count++;
|
||||||
|
}));
|
||||||
|
|
||||||
// Just verify we got all 6 elements
|
ASSERT_EQUAL(count, 6);
|
||||||
ASSERT_EQUAL(values.size(), 6);
|
|
||||||
|
|
||||||
// Don't try to access the values - they've been consumed by the OnDemand API
|
|
||||||
|
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -275,8 +260,11 @@ namespace wildcard_tests {
|
|||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
// Third element doesn't have "name" field
|
// Third element doesn't have "name" field
|
||||||
std::vector<ondemand::value> names;
|
std::vector<std::string_view> names;
|
||||||
auto error = doc.at_path_with_wildcard("$.data[*].name").get(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
|
// This might error or return partial results
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -301,18 +289,47 @@ namespace wildcard_tests {
|
|||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto doc = parser.iterate(json);
|
auto doc = parser.iterate(json);
|
||||||
|
|
||||||
std::vector<ondemand::value> names;
|
std::vector<std::string_view> names;
|
||||||
ASSERT_SUCCESS(doc.at_path_with_wildcard("$[*].name").get(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.size(), 3);
|
||||||
|
ASSERT_EQUAL(names[0], "Item 1");
|
||||||
|
ASSERT_EQUAL(names[1], "Item 2");
|
||||||
|
ASSERT_EQUAL(names[2], "Item 3");
|
||||||
|
|
||||||
std::string_view name;
|
TEST_SUCCEED();
|
||||||
ASSERT_SUCCESS(names[0].get_string().get(name));
|
}
|
||||||
ASSERT_EQUAL(name, "Item 1");
|
|
||||||
ASSERT_SUCCESS(names[1].get_string().get(name));
|
// https://github.com/simdjson/simdjson/issues/2684
|
||||||
ASSERT_EQUAL(name, "Item 2");
|
bool wildcard_raw_json_issue_2684() {
|
||||||
ASSERT_SUCCESS(names[2].get_string().get(name));
|
TEST_START();
|
||||||
ASSERT_EQUAL(name, "Item 3");
|
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();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -329,10 +346,11 @@ namespace wildcard_tests {
|
|||||||
wildcard_with_nested_objects() &&
|
wildcard_with_nested_objects() &&
|
||||||
mixed_types_in_array() &&
|
mixed_types_in_array() &&
|
||||||
wildcard_nonexistent_field() &&
|
wildcard_nonexistent_field() &&
|
||||||
root_array_wildcard();
|
root_array_wildcard() &&
|
||||||
|
wildcard_raw_json_issue_2684();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
return test_main(argc, argv, wildcard_tests::run);
|
return test_main(argc, argv, wildcard_tests::run);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ namespace wrong_type_error_tests {
|
|||||||
return false; \
|
return false; \
|
||||||
} \
|
} \
|
||||||
{ \
|
{ \
|
||||||
std::string a_json(R"({ "a": )"); a_json += JSON; a_json += " }"; \
|
padded_string a_json(std::string(R"({ "a": )") + JSON + " }"); \
|
||||||
std::cout << R"(- Subtest: get_)" << (#TYPE) << "() - JSON: " << a_json << std::endl; \
|
std::cout << R"(- Subtest: get_)" << (#TYPE) << "() - JSON: " << a_json << std::endl; \
|
||||||
if (!test_ondemand_doc(simdjson::pad(a_json), [&](auto doc_result) { \
|
if (!test_ondemand_doc(a_json, [&](auto doc_result) { \
|
||||||
ASSERT_ERROR( doc_result["a"].get_##TYPE(), (ERROR) ); \
|
ASSERT_ERROR( doc_result["a"].get_##TYPE(), (ERROR) ); \
|
||||||
return true; \
|
return true; \
|
||||||
})) { \
|
})) { \
|
||||||
|
|||||||
Reference in New Issue
Block a user