mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 956661f800 | |||
| a306d2bd73 | |||
| 9627831b5f | |||
| 6c5ada32b9 | |||
| f576354342 | |||
| 1589d15361 | |||
| c58f5dda2d | |||
| 5753f54f6c | |||
| f0cdafa857 | |||
| 29ef75c783 | |||
| c3d45c7758 | |||
| 3fda1b9c7d | |||
| fdcea9ad22 | |||
| 7b3168bfc8 | |||
| 3350ce97ba | |||
| 61ec1fb659 | |||
| bfc8b89e6b | |||
| 1382432686 | |||
| bebbf830fb | |||
| e7dda647e2 | |||
| ec46aace3b | |||
| 1dfe1bd350 | |||
| 0b1d69938e | |||
| 120e69f13c | |||
| 14922fa6c4 | |||
| 8fa2629c84 | |||
| c51c2d2ce9 | |||
| 3c9cde5ec1 | |||
| 651c982d26 | |||
| 3634cdbf94 | |||
| 3b47ae6a77 | |||
| 07daf0a92e | |||
| 9f74c0e958 | |||
| 7a336e560c | |||
| c6e7c89b59 | |||
| ed838ffab9 | |||
| 5981ca18e4 | |||
| 1a11e19d07 | |||
| 671a81f4e3 | |||
| 008d89eb56 | |||
| a71655120a | |||
| 531567ae94 | |||
| 46ae2d250f | |||
| c35122bcb4 | |||
| f380604de5 | |||
| 00d01ea0f5 | |||
| 68bef810aa | |||
| e328bad696 | |||
| c9ccb2d139 | |||
| d99072982f | |||
| 6b7f987cd5 | |||
| d32cd20ce6 | |||
| 2013a46518 | |||
| 6cb1911d3a | |||
| 9ff7d2ccbe | |||
| fa4a4ad8f0 | |||
| de6ad3c60c | |||
| 005133c555 | |||
| 78025fdd64 |
+1
-1
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 3.12.3
|
||||
VERSION 3.12.2
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ We welcome contributions from women and less represented groups. If you need hel
|
||||
|
||||
Consider the following points when engaging with the project:
|
||||
|
||||
- We discourage arguments from authority: ideas are discussed on their own merits and not based on who stated it.
|
||||
- We discourage arguments from authority: ideas are discusssed on their own merits and not based on who stated it.
|
||||
- Be mindful that what you may view as an aggression is maybe merely a difference of opinion or a misunderstanding.
|
||||
- Be mindful that a collection of small aggressions, even if mild in isolation, can become harmful.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "3.12.3"
|
||||
PROJECT_NUMBER = "3.12.2"
|
||||
|
||||
# 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
|
||||
|
||||
@@ -173,8 +173,7 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
||||
- [simdjsone](https://github.com/saleyn/simdjsone): erlang bindings.
|
||||
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
||||
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
|
||||
- [zimdjson](https://github.com/EzequielRamis/zimdjson): Zig port.
|
||||
- [simdjzon](https://github.com/travisstaloch/simdjzon): Zig port.
|
||||
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
|
||||
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
|
||||
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
|
||||
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim JSON parser based on simdjson bindings.
|
||||
|
||||
+3
-49
@@ -1243,6 +1243,7 @@ int main() {
|
||||
You may also conditionally fill in `std::optional` values.
|
||||
|
||||
```C++
|
||||
|
||||
padded_string json =
|
||||
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] }
|
||||
@@ -1257,23 +1258,6 @@ You may also conditionally fill in `std::optional` values.
|
||||
// error is simdjson::SUCCESS
|
||||
```
|
||||
|
||||
You can also deserialized to map-like types with keys that can be constructed
|
||||
from `std::string_view` instances:
|
||||
|
||||
|
||||
```C++
|
||||
padded_string json =
|
||||
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] }
|
||||
})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
std:map<std::string,Car> cars;
|
||||
error = doc.get<std:map<std::string,Car>>().get(cars);
|
||||
// car has value car1->Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}}
|
||||
// error is simdjson::SUCCESS
|
||||
```
|
||||
|
||||
And so forth.
|
||||
|
||||
Advanced users may want to overwrite the defaults provided by the simdjson library.
|
||||
@@ -1547,20 +1531,7 @@ Some errors are recoverable:
|
||||
* You may get the error `simdjson::INCORRECT_TYPE` after trying to convert a value to an incorrect type: e.g., you expected a number and try to convert the value to a number, but it is an array.
|
||||
* You may query a key from an object, but the key is missing in which case you get the error `simdjson::NO_SUCH_FIELD`: e.g., you call `obj["myname"]` and the object does not have a key `"myname"`.
|
||||
|
||||
Other errors (`simdjson::INCOMPLETE_ARRAY_OR_OBJECT` and `simdjson::TAPE_ERROR`) indicate a fatal error and follow from the fact that the document is not valid JSON. These errors are not recoverable: you cannot continue. In which case, it is no longer safe to continue accessing the document: calling the method `is_alive()` on the document instance returns false. It is your responsibility as a user to stop using the simdjson
|
||||
document after encountering these fatal errors. Consider the following example, after
|
||||
the fatal error, the document instance cannot be used. Observe how the JSON input is invalid.
|
||||
```cpp
|
||||
simdjson::padded_string badjson = R"( { "make": "Toyota", "model": "Camry", "year"})"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc;
|
||||
auto errordoc = parser.iterate(badjson).get(doc);
|
||||
// errordoc == simdjson::SUCCESS
|
||||
simdjson::ondemand::value v;
|
||||
auto error = doc.get_object()["year"].get(v);
|
||||
// simdjson::is_fatal(error)) is true!
|
||||
// doc.is_alive() is false
|
||||
```
|
||||
Other errors (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`) may indicate a fatal error and often follow from the fact that the document is not valid JSON. In which case, it is no longer possible to continue accessing the document: calling the method `is_alive()` on the document instance returns false. All following accesses will keep returning the same fatal error (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`).
|
||||
|
||||
When you use the code without exceptions, it is your responsibility to check for error before using the
|
||||
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
||||
@@ -1949,8 +1920,6 @@ conclude that you have trailing content and that your document is not valid JSON
|
||||
You may then use `doc.current_location()` to obtain a pointer to the start of the trailing
|
||||
content.
|
||||
|
||||
Example 1.
|
||||
|
||||
```C++
|
||||
auto json = R"([1, 2] foo ])"_padded;
|
||||
ondemand::parser parser;
|
||||
@@ -1965,21 +1934,6 @@ Example 1.
|
||||
}
|
||||
```
|
||||
|
||||
Example 2.
|
||||
|
||||
```cpp
|
||||
auto json = R"(["extra close"]])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
ondemand::array array = doc.get_array();
|
||||
for (std::string_view values : array) {
|
||||
std::cout << values << std::endl;
|
||||
}
|
||||
if(!doc.at_end()) {
|
||||
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
The `at_end()` method is equivalent to `doc.current_location().error() == simdjson::SUCCESS` but
|
||||
more convenient.
|
||||
|
||||
@@ -2591,7 +2545,7 @@ The CPU detection, which runs the first time parsing is attempted and switches t
|
||||
parser for your CPU, is transparent and thread-safe.
|
||||
Our runtime dispatching is based on global objects that are instantiated at the beginning of the
|
||||
main thread and may be discarded at the end of the main thread. If you have multiple threads running
|
||||
and some threads use the library while the main thread is cleaning up resources, you may encounter
|
||||
and some threads use the library while the main thread is cleaning up ressources, you may encounter
|
||||
issues. If you expect such problems, you may consider using [std::quick_exit](https://en.cppreference.com/w/cpp/utility/program/quick_exit).
|
||||
|
||||
In a threaded environment, stack space is often limited. Running code like simdjson in debug mode may require hundreds of kilobytes of stack memory. Thus stack overflows are a possibility. We recommend you turn on optimization when working in an environment where stack space is limited. If you must run your code in debug mode, we recommend you configure your system to have more stack space. We discourage you from running production code based on a debug build.
|
||||
|
||||
+69
-1
@@ -323,6 +323,74 @@ if(error) { /*won't happen*/ }
|
||||
```
|
||||
|
||||
|
||||
## Using `at_path_with_wildcard` for JSONPath Queries
|
||||
|
||||
The `at_path_with_wildcard` function in simdjson extends the JSONPath querying capabilities by supporting wildcard expressions (`*`) in JSON paths. This allows users to retrieve multiple elements from a JSON document in a single query. For example, you can use `$.address.*` to fetch all fields within the `address` object or `$.phoneNumbers[*].numbers[*]` to retrieve all phone numbers across multiple objects in an array.
|
||||
|
||||
The `*` wildcard matches all elements at a specific level. For instance, `$.address.*` retrieves all key-value pairs in the `address` object, while `$.*.streetAddress` fetches all `streetAddress` fields across objects at the root level. You can combine wildcards with array indexing. For example, `$.phoneNumbers[*].numbers[1]` retrieves the second number from each `numbers` array in the `phoneNumbers` array. If no elements match the wildcard query, the function returns an empty result. For instance, querying `$.empty_object.*` or `$.empty_array.*` will yield an empty set.
|
||||
|
||||
### Example Usage
|
||||
|
||||
Here is an example demonstrating the use of `at_path_with_wildcard`:
|
||||
|
||||
```cpp
|
||||
simdjson::padded_string json_string = R"(
|
||||
{
|
||||
"firstName": "John",
|
||||
"lastName": "doe",
|
||||
"age": 26,
|
||||
"address": {
|
||||
"streetAddress": "naist street",
|
||||
"city": "Nara",
|
||||
"postalCode": "630-0192"
|
||||
},
|
||||
"phoneNumbers": [
|
||||
{
|
||||
"type": "iPhone",
|
||||
"numbers": ["0123-4567-8888", "0123-4567-8788"]
|
||||
},
|
||||
{
|
||||
"type": "home",
|
||||
"numbers": ["0123-4567-8910"]
|
||||
}
|
||||
]
|
||||
})"_padded;
|
||||
|
||||
dom::parser parser;
|
||||
dom::element parsed_json = parser.parse(json_string);
|
||||
std::vector<dom::element> values;
|
||||
|
||||
// Fetch all fields in the address object
|
||||
auto error = parsed_json.at_path_with_wildcard("$.address.*").get(values);
|
||||
if(error) {
|
||||
// do something
|
||||
}
|
||||
for (auto &value : values) {
|
||||
std::string_view field;
|
||||
error = value.get(field);
|
||||
if(error) {
|
||||
// do something
|
||||
}
|
||||
std::cout << field << std::endl;
|
||||
}
|
||||
|
||||
// Fetch all phone numbers
|
||||
error = parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values);
|
||||
if(error) {
|
||||
// do something
|
||||
}
|
||||
for (auto &value : values) {
|
||||
std::string_view number;
|
||||
error = value.get(number);
|
||||
if(error) {
|
||||
// do something
|
||||
}
|
||||
std::cout << number << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
This function is particularly useful for extracting data from complex JSON structures with nested arrays and objects. By leveraging wildcards, you can simplify your queries and reduce the need for multiple iterations.
|
||||
|
||||
Error Handling
|
||||
--------------
|
||||
|
||||
@@ -733,5 +801,5 @@ Setting the `realloc_if_needed` parameter `false` in this manner may lead to bet
|
||||
Performance Tips
|
||||
---------------------
|
||||
|
||||
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directive, you must set it manually (e.g., `-DNDEBUG`).
|
||||
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directrive, you must set it manually (e.g., `-DNDEBUG`).
|
||||
- For long streams of JSON documents, consider [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) for better performance.
|
||||
|
||||
+1
-1
@@ -367,7 +367,7 @@ Please see our main documentation (`basics.md`) under
|
||||
"Use `tag_invoke` for custom types (C++20)" for details about
|
||||
tag_invoke functions.
|
||||
|
||||
Given a stream of JSON documents, you can add them to a data structure
|
||||
Given a stream of JSON documents, you can add them to a data struture
|
||||
such as a `std::vector<Car>` like so if you support exceptions:
|
||||
|
||||
```C++
|
||||
|
||||
@@ -32,30 +32,14 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
|
||||
#undef SIMDJSON_IMPL_CONCEPT
|
||||
} // namespace details
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
|
||||
!std::is_convertible_v<T, const char*>;
|
||||
|
||||
template<typename T>
|
||||
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
|
||||
&& !std::is_same_v<T, std::string_view>
|
||||
&& std::is_default_constructible_v<T>;
|
||||
|
||||
template<typename M>
|
||||
concept string_view_keyed_map = string_view_like<typename M::key_type>
|
||||
&& requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
|
||||
{ m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
|
||||
};
|
||||
|
||||
/// Check if T is a container that we can append to, including:
|
||||
/// std::vector, std::deque, std::list, std::string, ...
|
||||
template <typename T>
|
||||
concept appendable_containers =
|
||||
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||
details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||
details::supports_push_back<T> || details::supports_push<T> ||
|
||||
details::supports_add<T> || details::supports_append<T> ||
|
||||
details::supports_insert<T>) && !string_view_keyed_map<T>;
|
||||
details::supports_insert<T>;
|
||||
|
||||
/// Insert into the container however possible
|
||||
template <appendable_containers T, typename... Args>
|
||||
@@ -123,8 +107,6 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
||||
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace concepts
|
||||
} // namespace simdjson
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
@@ -52,11 +52,22 @@ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std
|
||||
return at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::array>::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||
if (error()) {
|
||||
return error();
|
||||
}
|
||||
return first.at_path_with_wildcard(json_path);
|
||||
}
|
||||
|
||||
inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
}
|
||||
|
||||
inline std::vector<dom::element>& simdjson_result<dom::array>::get_values(std::vector<dom::element>& out) const noexcept {
|
||||
return first.get_values(out);
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
//
|
||||
@@ -127,6 +138,91 @@ inline simdjson_result<element> array::at_path(std::string_view json_path) const
|
||||
return at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
inline void array::process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept {
|
||||
if (current == end) {
|
||||
return;
|
||||
}
|
||||
|
||||
simdjson_result<std::vector<element>> result;
|
||||
|
||||
|
||||
for (auto it = current; it != end; ++it) {
|
||||
result = it->at_path_with_wildcard(path_suffix);
|
||||
|
||||
if (!result.error()) {
|
||||
std::vector<element> child_result = result.value();
|
||||
|
||||
accumulator.reserve(accumulator.size() + child_result.size());
|
||||
accumulator.insert(accumulator.end(),
|
||||
std::make_move_iterator(child_result.begin()),
|
||||
std::make_move_iterator(child_result.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline simdjson_result<std::vector<element>> array::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
|
||||
size_t i = 0;
|
||||
// json_path.starts_with('$') requires C++20.
|
||||
if (!json_path.empty() && json_path.front() == '$') {
|
||||
i = 1;
|
||||
}
|
||||
|
||||
if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) {
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
|
||||
if (json_path.find("*") != std::string::npos) {
|
||||
std::vector<element> child_values;
|
||||
|
||||
if (
|
||||
(json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) ||
|
||||
(json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2)
|
||||
) {
|
||||
get_values(child_values);
|
||||
return child_values;
|
||||
}
|
||||
|
||||
std::pair<std::string_view, std::string_view> key_and_json_path = get_next_key_and_json_path(json_path);
|
||||
|
||||
std::string_view key = key_and_json_path.first;
|
||||
json_path = key_and_json_path.second;
|
||||
|
||||
if (key.size() > 0) {
|
||||
if (key == "*") {
|
||||
get_values(child_values);
|
||||
} else {
|
||||
auto pointer_result = at_pointer("/" + std::string(key));
|
||||
|
||||
if (!pointer_result.error()) {
|
||||
child_values.emplace_back(pointer_result.value());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<element> result = {};
|
||||
|
||||
if (child_values.size() > 0) {
|
||||
std::vector<element>::iterator child_values_begin = child_values.begin();
|
||||
std::vector<element>::iterator child_values_end = child_values.end();
|
||||
|
||||
process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
} else {
|
||||
auto result = at_path(json_path);
|
||||
if (result.error()) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
return std::vector{std::move(result.value())};
|
||||
}
|
||||
}
|
||||
|
||||
inline simdjson_result<element> array::at(size_t index) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
size_t i=0;
|
||||
@@ -137,6 +233,15 @@ inline simdjson_result<element> array::at(size_t index) const noexcept {
|
||||
return INDEX_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
inline std::vector<element>& array::get_values(std::vector<element>& out) const noexcept {
|
||||
out.reserve(this->size());
|
||||
for (auto element : *this) {
|
||||
out.emplace_back(element);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
inline array::operator element() const noexcept {
|
||||
return element(tape);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef SIMDJSON_DOM_ARRAY_H
|
||||
#define SIMDJSON_DOM_ARRAY_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/internal/tape_ref.h"
|
||||
|
||||
@@ -108,6 +110,17 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||
|
||||
/**
|
||||
* Recursive function which processes the json path of each child element
|
||||
*/
|
||||
inline void process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* Adds support for JSONPath expression with wildcards '*'
|
||||
*/
|
||||
inline simdjson_result<std::vector<element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSONPath expression. We only support
|
||||
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
||||
@@ -141,6 +154,15 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> at(size_t index) const noexcept;
|
||||
|
||||
/**
|
||||
* Gets the values of items in an array element
|
||||
* This function has linear-time complexity: the values are checked one by one.
|
||||
*
|
||||
* @return The child elements of an array
|
||||
*/
|
||||
|
||||
inline std::vector<element>& get_values(std::vector<element>& out) const noexcept;
|
||||
|
||||
/**
|
||||
* Implicitly convert object to element
|
||||
*/
|
||||
@@ -167,8 +189,11 @@ public:
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
|
||||
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||
inline void process_json_path_of_child_elements(std::vector<dom::element>::iterator& current, std::vector<dom::element>::iterator& end, const std::string_view& path_suffix, std::vector<dom::element>& accumulator) const noexcept;
|
||||
inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
|
||||
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
||||
inline simdjson_result<dom::element> at(size_t index) const noexcept;
|
||||
inline std::vector<dom::element>& get_values(std::vector<dom::element>& out) const noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline dom::array::iterator begin() const noexcept(false);
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
* The memory allocation is strict: you
|
||||
* can you use this function to increase
|
||||
* or lower the amount of allocated memory.
|
||||
* Passing zero clears the memory.
|
||||
* Passsing zero clears the memory.
|
||||
*/
|
||||
error_code allocate(size_t len) noexcept;
|
||||
/** @private Capacity in bytes, in terms
|
||||
|
||||
@@ -128,6 +128,12 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
|
||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||
return at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::element>::at_path_with_wildcard(const std::string_view json_path) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_path_with_wildcard(json_path);
|
||||
}
|
||||
|
||||
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
|
||||
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
||||
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
|
||||
@@ -418,6 +424,20 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline simdjson_result<std::vector<element>> element::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
|
||||
switch (tape.tape_ref_type()) {
|
||||
case internal::tape_type::START_OBJECT:
|
||||
return object(tape).at_path_with_wildcard(json_path);
|
||||
case internal::tape_type::START_ARRAY:
|
||||
return array(tape).at_path_with_wildcard(json_path);
|
||||
default:
|
||||
return std::vector<element>{};
|
||||
}
|
||||
}
|
||||
|
||||
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
|
||||
auto json_pointer = json_path_to_pointer_conversion(json_path);
|
||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef SIMDJSON_DOM_ELEMENT_H
|
||||
#define SIMDJSON_DOM_ELEMENT_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/array.h"
|
||||
|
||||
@@ -399,6 +401,8 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
|
||||
|
||||
inline simdjson_result<std::vector<element>> at_path_with_wildcard(const std::string_view json_path) const noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSONPath expression. We only support
|
||||
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
||||
@@ -544,6 +548,7 @@ public:
|
||||
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
||||
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
|
||||
simdjson_inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(const std::string_view json_path) const noexcept;
|
||||
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
|
||||
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
||||
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
|
||||
|
||||
@@ -40,10 +40,19 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_path(std::
|
||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||
return at_pointer(json_pointer);
|
||||
}
|
||||
inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::object>::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||
if (error()) {
|
||||
return error();
|
||||
}
|
||||
return first.at_path_with_wildcard(json_path);
|
||||
}
|
||||
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_key(key);
|
||||
}
|
||||
inline std::vector<dom::element>& simdjson_result<dom::object>::get_values(std::vector<dom::element>& out) const noexcept {
|
||||
return first.get_values(out);
|
||||
}
|
||||
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key_case_insensitive(std::string_view key) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_key_case_insensitive(key);
|
||||
@@ -143,6 +152,97 @@ inline simdjson_result<element> object::at_path(std::string_view json_path) cons
|
||||
return at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
inline void object::process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept {
|
||||
if (current == end) {
|
||||
return;
|
||||
}
|
||||
|
||||
simdjson_result<std::vector<element>> result;
|
||||
|
||||
for (auto it = current; it != end; ++it) {
|
||||
result = it->at_path_with_wildcard(path_suffix);
|
||||
|
||||
if (!result.error()) {
|
||||
std::vector<element> child_result = result.value();
|
||||
|
||||
accumulator.reserve(accumulator.size() + child_result.size());
|
||||
accumulator.insert(accumulator.end(),
|
||||
std::make_move_iterator(child_result.begin()),
|
||||
std::make_move_iterator(child_result.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline simdjson_result<std::vector<element>> object::at_path_with_wildcard(std::string_view json_path) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
|
||||
size_t i = 0;
|
||||
if (json_path.empty()) {
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
// if JSONPath starts with $, skip it
|
||||
// json_path.starts_with('$') requires C++20.
|
||||
if (json_path.front() == '$') {
|
||||
i = 1;
|
||||
}
|
||||
|
||||
if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) {
|
||||
// expect json path to always start with $ but this isn't currently
|
||||
// expected in jsonpathutil.h.
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
|
||||
if (json_path.find("*") != std::string::npos) {
|
||||
|
||||
std::vector<element> child_values;
|
||||
|
||||
if (
|
||||
(json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) ||
|
||||
(json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2)
|
||||
) {
|
||||
get_values(child_values);
|
||||
return child_values;
|
||||
}
|
||||
|
||||
std::pair<std::string_view, std::string_view> key_and_json_path = get_next_key_and_json_path(json_path);
|
||||
|
||||
std::string_view key = key_and_json_path.first;
|
||||
json_path = key_and_json_path.second;
|
||||
|
||||
if (key.size() > 0) {
|
||||
if (key == "*") {
|
||||
get_values(child_values);
|
||||
} else {
|
||||
auto pointer_result = at_pointer("/" + std::string(key));
|
||||
|
||||
if (!pointer_result.error()) {
|
||||
child_values.emplace_back(pointer_result.value());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<element> result = {};
|
||||
if (child_values.size() > 0) {
|
||||
|
||||
std::vector<element>::iterator child_values_begin = child_values.begin();
|
||||
std::vector<element>::iterator child_values_end = child_values.end();
|
||||
|
||||
process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
} else {
|
||||
auto at_path_result = this->at_path(json_path);
|
||||
if (at_path_result.error()) {
|
||||
return at_path_result.error();
|
||||
}
|
||||
std::vector<element> result{std::move(at_path_result.value())};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
|
||||
iterator end_field = end();
|
||||
for (iterator field = begin(); field != end_field; ++field) {
|
||||
@@ -152,6 +252,18 @@ inline simdjson_result<element> object::at_key(std::string_view key) const noexc
|
||||
}
|
||||
return NO_SUCH_FIELD;
|
||||
}
|
||||
|
||||
inline std::vector<element>& object::get_values(std::vector<element>& out) const noexcept {
|
||||
iterator end_field = end();
|
||||
iterator begin_field = begin();
|
||||
|
||||
out.reserve(std::distance(begin_field, end_field));
|
||||
for (iterator field = begin_field; field != end_field; ++field) {
|
||||
out.emplace_back(field.value());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
// In case you wonder why we need this, please see
|
||||
// https://github.com/simdjson/simdjson/issues/323
|
||||
// People do seek keys in a case-insensitive manner.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef SIMDJSON_DOM_OBJECT_H
|
||||
#define SIMDJSON_DOM_OBJECT_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "simdjson/dom/base.h"
|
||||
#include "simdjson/dom/element.h"
|
||||
#include "simdjson/internal/tape_ref.h"
|
||||
@@ -172,6 +174,16 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||
|
||||
/**
|
||||
* Recursive function which processes the json path of each child element
|
||||
*/
|
||||
inline void process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept;
|
||||
|
||||
/**
|
||||
* Adds support for JSONPath expression with wildcards '*'
|
||||
*/
|
||||
inline simdjson_result<std::vector<element>> at_path_with_wildcard(std::string_view json_path) const noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSONPath expression. We only support
|
||||
* JSONPath queries that trivially convertible to JSON Pointer queries: key
|
||||
@@ -203,6 +215,14 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> at_key(std::string_view key) const noexcept;
|
||||
|
||||
/**
|
||||
* Gets the values associated with keys of an object
|
||||
* This function has linear-time complexity: the keys are checked one by one.
|
||||
*
|
||||
* @return the values associated with each key of an object
|
||||
*/
|
||||
inline std::vector<element>& get_values(std::vector<element>& out) const noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given key in a case-insensitive manner.
|
||||
* It is only guaranteed to work over ASCII inputs.
|
||||
@@ -261,8 +281,11 @@ public:
|
||||
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
||||
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||
inline void process_json_path_of_child_elements(std::vector<dom::element>::iterator& current, std::vector<dom::element>::iterator& end, const std::string_view& path_suffix, std::vector<dom::element>& accumulator) const noexcept;
|
||||
inline simdjson_result<std::vector<dom::element>> at_path_with_wildcard(std::string_view json_path_new) const noexcept;
|
||||
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
||||
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
|
||||
inline std::vector<dom::element>& get_values(std::vector<dom::element>& out) const noexcept;
|
||||
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
@@ -340,7 +340,7 @@ public:
|
||||
* arrays or objects) MUST be separated with whitespace.
|
||||
*
|
||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
||||
* performance.
|
||||
*
|
||||
* ### Error Handling
|
||||
@@ -434,7 +434,7 @@ public:
|
||||
* arrays or objects) MUST be separated with whitespace.
|
||||
*
|
||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
||||
* performance.
|
||||
*
|
||||
* ### Error Handling
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
#include <iostream>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
inline bool is_fatal(error_code error) noexcept {
|
||||
return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
// We store the error code so we can validate the error message is associated with the right code
|
||||
struct error_code_info {
|
||||
|
||||
@@ -20,7 +20,7 @@ enum error_code {
|
||||
SUCCESS = 0, ///< No error
|
||||
CAPACITY, ///< This parser can't support a document that big
|
||||
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
||||
TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
|
||||
TAPE_ERROR, ///< Something went wrong, this is a generic error
|
||||
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
||||
STRING_ERROR, ///< Problem while parsing a string
|
||||
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
||||
@@ -45,21 +45,13 @@ enum error_code {
|
||||
PARSER_IN_USE, ///< parser is already in use.
|
||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
||||
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
||||
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
||||
NUM_ERROR_CODES
|
||||
};
|
||||
|
||||
/**
|
||||
* Some errors are fatal and invalidate the document. This function returns true if the
|
||||
* error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
|
||||
* Once a fatal error is encountered, the on-demand document is no longer valid and
|
||||
* processing should stop.
|
||||
*/
|
||||
inline bool is_fatal(error_code error) noexcept;
|
||||
|
||||
/**
|
||||
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
||||
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
||||
|
||||
@@ -137,7 +137,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
|
||||
@@ -239,27 +239,20 @@ public:
|
||||
if constexpr (custom_deserializable<T, document>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||
"And you do not seem to have added support for it. Indeed, we have that "
|
||||
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, or bool.");
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||
template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
|
||||
|
||||
@@ -821,27 +814,20 @@ public:
|
||||
if constexpr (custom_deserializable<T, document_reference>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||
"And you do not seem to have added support for it. Indeed, we have that "
|
||||
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, or bool.");
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
@@ -55,16 +55,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
template <concepts::constructible_from_string_view T, typename ValT>
|
||||
requires(!require_custom_serialization<T>)
|
||||
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v<T, std::string_view>) {
|
||||
std::string_view str;
|
||||
SIMDJSON_TRY(val.get_string().get(str));
|
||||
out = T{str};
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* STL containers have several constructors including one that takes a single
|
||||
* size argument. Thus, some compilers (Visual Studio) will not be able to
|
||||
@@ -110,39 +100,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* We want to support std::map and std::unordered_map but only for
|
||||
* string-keyed types.
|
||||
*/
|
||||
template <concepts::string_view_keyed_map T, typename ValT>
|
||||
requires(!require_custom_serialization<T>)
|
||||
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
||||
using value_type = typename std::remove_cvref_t<T>::mapped_type;
|
||||
static_assert(
|
||||
deserializable<value_type, ValT>,
|
||||
"The specified value type inside the container must itself be deserializable");
|
||||
static_assert(
|
||||
std::is_default_constructible_v<value_type>,
|
||||
"The specified value type inside the container must default constructible.");
|
||||
SIMDJSON_IMPLEMENTATION::ondemand::object obj;
|
||||
SIMDJSON_TRY(val.get_object().get(obj));
|
||||
for (auto field : obj) {
|
||||
std::string_view key;
|
||||
SIMDJSON_TRY(field.unescaped_key().get(key));
|
||||
value_type this_value;
|
||||
SIMDJSON_TRY(field.value().get<value_type>().get(this_value));
|
||||
[[maybe_unused]] std::pair<typename T::iterator, bool> result = out.emplace(key, this_value);
|
||||
// unclear what to do if the key already exists
|
||||
// if (result.second == false) {
|
||||
// // key already exists
|
||||
// }
|
||||
}
|
||||
(void)out;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This CPO (Customization Point Object) will help deserialize into
|
||||
|
||||
@@ -70,28 +70,22 @@ public:
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
if constexpr (custom_deserializable<T, value>) {
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
if constexpr (custom_deserializable<T, value>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||
"And you do not seem to have added support for it. Indeed, we have that "
|
||||
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, or bool.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
}
|
||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
} else {
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -778,23 +778,19 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("bool");
|
||||
// We have a boolean if we have either "true" or "false" and the next character is either
|
||||
// a structural character or whitespace. We also check that the length is correct:
|
||||
// "true" and "false" are 4 and 5 characters long, respectively.
|
||||
bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") &&
|
||||
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
|
||||
bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") &&
|
||||
(max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5])));
|
||||
if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); }
|
||||
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||
advance_root_scalar("bool");
|
||||
return value_true;
|
||||
uint8_t tmpbuf[5+1+1]; // +1 for null termination
|
||||
tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
|
||||
auto result = parse_bool(tmpbuf);
|
||||
if(result.error() == SUCCESS) {
|
||||
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||
advance_root_scalar("bool");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("null");
|
||||
|
||||
@@ -125,8 +125,7 @@ public:
|
||||
*
|
||||
* @returns Whether the object had any fields (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||
* invalidates the document.
|
||||
* array or object is incomplete).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
|
||||
/**
|
||||
@@ -136,8 +135,7 @@ public:
|
||||
*
|
||||
* @returns Whether the object had any fields (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||
* invalidates the document.
|
||||
* array or object is incomplete).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
|
||||
|
||||
@@ -259,8 +257,7 @@ public:
|
||||
*
|
||||
* @returns Whether the array had any elements (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||
* invalidates the document.
|
||||
* array or object is incomplete).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
|
||||
/**
|
||||
@@ -270,8 +267,7 @@ public:
|
||||
*
|
||||
* @returns Whether the array had any elements (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||
* invalidates the document.
|
||||
* array or object is incomplete).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Converts JSONPath to JSON Pointer.
|
||||
@@ -12,12 +14,12 @@ namespace simdjson {
|
||||
*/
|
||||
inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
|
||||
size_t i = 0;
|
||||
|
||||
// if JSONPath starts with $, skip it
|
||||
// json_path.starts_with('$') requires C++20.
|
||||
if (!json_path.empty() && json_path.front() == '$') {
|
||||
i = 1;
|
||||
}
|
||||
if (json_path.empty() || (json_path[i] != '.' &&
|
||||
if (i >= json_path.size() || (json_path[i] != '.' &&
|
||||
json_path[i] != '[')) {
|
||||
return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
|
||||
}
|
||||
@@ -60,5 +62,48 @@ inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::pair<std::string_view, std::string_view> get_next_key_and_json_path(std::string_view& json_path) {
|
||||
std::string_view key;
|
||||
|
||||
if (json_path.empty()) {
|
||||
return {key, json_path};
|
||||
}
|
||||
size_t i = 0;
|
||||
|
||||
// if JSONPath starts with $, skip it
|
||||
if (json_path.front() == '$') {
|
||||
i = 1;
|
||||
}
|
||||
|
||||
|
||||
if (i < json_path.length() && json_path[i] == '.') {
|
||||
i += 1;
|
||||
size_t key_start = i;
|
||||
|
||||
while (i < json_path.length() && json_path[i] != '[' && json_path[i] != '.') {
|
||||
++i;
|
||||
}
|
||||
|
||||
key = json_path.substr(key_start, i - key_start);
|
||||
} else if ((i+1 < json_path.size()) && json_path[i] == '[' && (json_path[i+1] == '\'' || json_path[i+1] == '"')) {
|
||||
i += 2;
|
||||
size_t key_start = i;
|
||||
while (i < json_path.length() && json_path[i] != '\'' && json_path[i] != '"') {
|
||||
++i;
|
||||
}
|
||||
|
||||
key = json_path.substr(key_start, i - key_start);
|
||||
|
||||
i += 2;
|
||||
} else if ((i+2 < json_path.size()) && json_path[i] == '[' && json_path[i+1] == '*' && json_path[i+2] == ']') { // i.e [*].additional_keys or [*]["additional_keys"]
|
||||
key = "*";
|
||||
i += 3;
|
||||
}
|
||||
|
||||
|
||||
return std::make_pair(key, json_path.substr(i));
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
#endif // SIMDJSON_JSONPATHUTIL_H
|
||||
#endif // SIMDJSON_JSONPATHUTIL_H
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION "3.12.3"
|
||||
#define SIMDJSON_VERSION "3.12.2"
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
@@ -19,7 +19,7 @@ enum {
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 3
|
||||
SIMDJSON_VERSION_REVISION = 2
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+16
-47
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2025-03-27 15:01:10 -0400. Do not edit! */
|
||||
/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */
|
||||
/* including simdjson.cpp: */
|
||||
/* begin file simdjson.cpp */
|
||||
#define SIMDJSON_SRC_SIMDJSON_CPP
|
||||
@@ -2431,7 +2431,7 @@ enum error_code {
|
||||
SUCCESS = 0, ///< No error
|
||||
CAPACITY, ///< This parser can't support a document that big
|
||||
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
||||
TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
|
||||
TAPE_ERROR, ///< Something went wrong, this is a generic error
|
||||
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
||||
STRING_ERROR, ///< Problem while parsing a string
|
||||
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
||||
@@ -2456,21 +2456,13 @@ enum error_code {
|
||||
PARSER_IN_USE, ///< parser is already in use.
|
||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
||||
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
||||
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
||||
NUM_ERROR_CODES
|
||||
};
|
||||
|
||||
/**
|
||||
* Some errors are fatal and invalidate the document. This function returns true if the
|
||||
* error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
|
||||
* Once a fatal error is encountered, the on-demand document is no longer valid and
|
||||
* processing should stop.
|
||||
*/
|
||||
inline bool is_fatal(error_code error) noexcept;
|
||||
|
||||
/**
|
||||
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
||||
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
||||
@@ -2773,30 +2765,14 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
|
||||
#undef SIMDJSON_IMPL_CONCEPT
|
||||
} // namespace details
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
|
||||
!std::is_convertible_v<T, const char*>;
|
||||
|
||||
template<typename T>
|
||||
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
|
||||
&& !std::is_same_v<T, std::string_view>
|
||||
&& std::is_default_constructible_v<T>;
|
||||
|
||||
template<typename M>
|
||||
concept string_view_keyed_map = string_view_like<typename M::key_type>
|
||||
&& requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
|
||||
{ m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
|
||||
};
|
||||
|
||||
/// Check if T is a container that we can append to, including:
|
||||
/// std::vector, std::deque, std::list, std::string, ...
|
||||
template <typename T>
|
||||
concept appendable_containers =
|
||||
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||
details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||
details::supports_push_back<T> || details::supports_push<T> ||
|
||||
details::supports_add<T> || details::supports_append<T> ||
|
||||
details::supports_insert<T>) && !string_view_keyed_map<T>;
|
||||
details::supports_insert<T>;
|
||||
|
||||
/// Insert into the container however possible
|
||||
template <appendable_containers T, typename... Args>
|
||||
@@ -2864,8 +2840,6 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
||||
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace concepts
|
||||
} // namespace simdjson
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
@@ -4537,11 +4511,6 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint32_t digit_to_val32[886];
|
||||
#include <iostream>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
inline bool is_fatal(error_code error) noexcept {
|
||||
return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
// We store the error code so we can validate the error message is associated with the right code
|
||||
struct error_code_info {
|
||||
@@ -4727,7 +4696,7 @@ namespace internal {
|
||||
{ SUCCESS, "SUCCESS: No error" },
|
||||
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
|
||||
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
|
||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." },
|
||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." },
|
||||
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
|
||||
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
|
||||
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
|
||||
@@ -4752,7 +4721,7 @@ namespace internal {
|
||||
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
|
||||
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
|
||||
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." },
|
||||
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
||||
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
|
||||
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
|
||||
@@ -6818,7 +6787,7 @@ public:
|
||||
* The memory allocation is strict: you
|
||||
* can you use this function to increase
|
||||
* or lower the amount of allocated memory.
|
||||
* Passing zero clears the memory.
|
||||
* Passsing zero clears the memory.
|
||||
*/
|
||||
error_code allocate(size_t len) noexcept;
|
||||
/** @private Capacity in bytes, in terms
|
||||
@@ -9216,7 +9185,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -15576,7 +15545,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -21800,7 +21769,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -28180,7 +28149,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -34922,7 +34891,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -41488,7 +41457,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -47499,7 +47468,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -53109,7 +53078,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximately equal to log(5)/log(2).
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
|
||||
+404
-1002
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ namespace internal {
|
||||
{ SUCCESS, "SUCCESS: No error" },
|
||||
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
|
||||
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
|
||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." },
|
||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." },
|
||||
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
|
||||
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
|
||||
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
|
||||
@@ -36,7 +36,7 @@ namespace internal {
|
||||
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
|
||||
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
|
||||
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." },
|
||||
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
||||
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
|
||||
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
|
||||
|
||||
@@ -292,6 +292,157 @@ bool json_path_invalidation() {
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool json_path_with_wildcard() {
|
||||
TEST_START();
|
||||
|
||||
simdjson::padded_string json_string = R"(
|
||||
{
|
||||
"firstName": "John",
|
||||
"lastName" : "doe",
|
||||
"age" : 26,
|
||||
"address" : {
|
||||
"streetAddress": "naist street",
|
||||
"city" : "Nara",
|
||||
"postalCode" : "630-0192"
|
||||
},
|
||||
"phoneNumbers": [
|
||||
{
|
||||
"type" : "iPhone",
|
||||
"numbers": [
|
||||
"0123-4567-8888",
|
||||
"0123-4567-8788",
|
||||
"0123-4567-8887"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type" : "home",
|
||||
"numbers": [
|
||||
"0123-4567-8910",
|
||||
"0123-4267-8910",
|
||||
"0103-4567-8910"
|
||||
]
|
||||
},
|
||||
{ },
|
||||
{
|
||||
"type": "office",
|
||||
"numbers": [ ]
|
||||
}
|
||||
],
|
||||
"empty_object": { },
|
||||
"empty_array": [ ]
|
||||
})"_padded;
|
||||
|
||||
dom::parser parser;
|
||||
dom::element parsed_json = parser.parse(json_string);
|
||||
std::vector<dom::element> values;
|
||||
|
||||
|
||||
std::string_view string_value;
|
||||
std::uint64_t num_value;
|
||||
dom::object obj;
|
||||
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("$").error(), INVALID_JSON_POINTER);
|
||||
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("1").error(), INVALID_JSON_POINTER);
|
||||
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("2").error(), INVALID_JSON_POINTER);
|
||||
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("a").error(), INVALID_JSON_POINTER);
|
||||
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("$2").error(), INVALID_JSON_POINTER);
|
||||
ASSERT_EQUAL(parsed_json.at_path_with_wildcard("$a").error(), INVALID_JSON_POINTER);
|
||||
// $.*
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.*").get(values));
|
||||
|
||||
ASSERT_SUCCESS(values[0].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "John");
|
||||
|
||||
ASSERT_SUCCESS(values[1].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "doe");
|
||||
|
||||
ASSERT_SUCCESS(values[2].get(num_value));
|
||||
ASSERT_EQUAL(num_value, 26);
|
||||
|
||||
ASSERT_SUCCESS(values[3].get(obj));
|
||||
ASSERT_SUCCESS(obj["streetAddress"].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "naist street");
|
||||
|
||||
ASSERT_SUCCESS(obj["city"].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "Nara");
|
||||
|
||||
// $[*]
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$[*]").get(values));
|
||||
|
||||
ASSERT_SUCCESS(values[0].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "John");
|
||||
|
||||
ASSERT_SUCCESS(values[1].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "doe");
|
||||
|
||||
ASSERT_SUCCESS(values[2].get(num_value));
|
||||
ASSERT_EQUAL(num_value, 26);
|
||||
|
||||
ASSERT_SUCCESS(values[3].get(obj));
|
||||
ASSERT_SUCCESS(obj["streetAddress"].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "naist street");
|
||||
|
||||
ASSERT_SUCCESS(obj["city"].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "Nara");
|
||||
|
||||
// $.address.*
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.address.*").get(values));
|
||||
|
||||
std::vector<std::string> expected = {"naist street", "Nara", "630-0192"};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ASSERT_SUCCESS(values[i].get(string_value));
|
||||
ASSERT_EQUAL(string_value, expected[i]);
|
||||
}
|
||||
|
||||
// $.*.streetAddress
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.*.streetAddress").get(values));
|
||||
|
||||
ASSERT_SUCCESS(values[0].get(string_value));
|
||||
ASSERT_EQUAL(string_value, "naist street");
|
||||
|
||||
// $.phoneNumbers[*].numbers[*]
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values));
|
||||
|
||||
std::vector<std::string> expected_numbers = {
|
||||
"0123-4567-8888",
|
||||
"0123-4567-8788",
|
||||
"0123-4567-8887",
|
||||
"0123-4567-8910",
|
||||
"0123-4267-8910",
|
||||
"0103-4567-8910"
|
||||
};
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
ASSERT_SUCCESS(values[i].get(string_value));
|
||||
ASSERT_EQUAL(string_value, expected_numbers[i]);
|
||||
}
|
||||
|
||||
// $.phoneNumbers[*].numbers[1]
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[1]").get(values));
|
||||
|
||||
ASSERT_SUCCESS(values[0].get(string_value));
|
||||
ASSERT_EQUAL(string_value, expected_numbers[1]);
|
||||
|
||||
ASSERT_SUCCESS(values[1].get(string_value));
|
||||
ASSERT_EQUAL(string_value, expected_numbers[4]);
|
||||
|
||||
// $.empty_object.*
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.empty_object.*").get(values));
|
||||
|
||||
ASSERT_EQUAL(values.size(), 0);
|
||||
|
||||
// $.empty_array.*
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.empty_array.*").get(values));
|
||||
ASSERT_EQUAL(values.size(), 0);
|
||||
|
||||
// $.phoneNumbers.*.numbers[3]
|
||||
ASSERT_SUCCESS(parsed_json.at_path_with_wildcard("$.phoneNumbers.*.numbers[3]").get(values));
|
||||
|
||||
ASSERT_EQUAL(values.size(), 0);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
// for 0.5 version and following (standard compliant)
|
||||
bool modern_support() {
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
@@ -314,7 +465,7 @@ bool modern_support() {
|
||||
}
|
||||
|
||||
int main() {
|
||||
if (true && demo() && modern_support() &&
|
||||
if (true && json_path_with_wildcard() && demo() && modern_support() &&
|
||||
run_success_test(TEST_RFC_JSON, "$.foo", "[\"bar\",\"baz\"]") &&
|
||||
run_success_test(TEST_RFC_JSON, "$.foo[0]", "\"bar\"") &&
|
||||
run_success_test(TEST_RFC_JSON, "$.", "0") &&
|
||||
|
||||
@@ -21,6 +21,62 @@ void basics_2() {
|
||||
cout << doc;
|
||||
}
|
||||
|
||||
void wild() {
|
||||
simdjson::padded_string json_string = R"(
|
||||
{
|
||||
"firstName": "John",
|
||||
"lastName": "doe",
|
||||
"age": 26,
|
||||
"address": {
|
||||
"streetAddress": "naist street",
|
||||
"city": "Nara",
|
||||
"postalCode": "630-0192"
|
||||
},
|
||||
"phoneNumbers": [
|
||||
{
|
||||
"type": "iPhone",
|
||||
"numbers": ["0123-4567-8888", "0123-4567-8788"]
|
||||
},
|
||||
{
|
||||
"type": "home",
|
||||
"numbers": ["0123-4567-8910"]
|
||||
}
|
||||
]
|
||||
})"_padded;
|
||||
|
||||
dom::parser parser;
|
||||
dom::element parsed_json = parser.parse(json_string);
|
||||
std::vector<dom::element> values;
|
||||
|
||||
// Fetch all fields in the address object
|
||||
auto error = parsed_json.at_path_with_wildcard("$.address.*").get(values);
|
||||
if(error) {
|
||||
// do something
|
||||
}
|
||||
for (auto &value : values) {
|
||||
std::string_view field;
|
||||
error = value.get(field);
|
||||
if(error) {
|
||||
// do something
|
||||
}
|
||||
std::cout << field << std::endl;
|
||||
}
|
||||
|
||||
// Fetch all phone numbers
|
||||
error = parsed_json.at_path_with_wildcard("$.phoneNumbers[*].numbers[*]").get(values);
|
||||
if(error) {
|
||||
// do something
|
||||
}
|
||||
for (auto &value : values) {
|
||||
std::string_view number;
|
||||
error = value.get(number);
|
||||
if(error) {
|
||||
// do something
|
||||
}
|
||||
std::cout << number << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void basics_dom_1() {
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
@@ -240,40 +238,6 @@ bool optional_car_deserialize() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool car_deserialize_to_map() {
|
||||
TEST_START();
|
||||
std::map<std::string,std::string> expected = { {"make", "Toyota"}, {"model", "Camry"}};
|
||||
padded_string json =
|
||||
R"( { "make": "Toyota", "model": "Camry" })"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
|
||||
static_assert(simdjson::concepts::string_view_keyed_map<std::map<std::string, std::string>>, "should be custom deserializable");
|
||||
using map_type = typename std::map<std::string,std::string>;
|
||||
static_assert(simdjson::custom_deserializable<map_type,simdjson::ondemand::value>, "should be custom deserializable");
|
||||
map_type brands;
|
||||
error = doc.get<map_type>().get(brands);
|
||||
ASSERT_TRUE(brands == expected);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool car_deserialize_with_map() {
|
||||
TEST_START();
|
||||
padded_string json =
|
||||
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] }
|
||||
})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
|
||||
std::map<std::string,Car> car;
|
||||
error = doc.get<std::map<std::string,Car>>().get(car);
|
||||
std::optional<Car> expected = Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}};
|
||||
ASSERT_TRUE(car["car1"] == expected);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool car_doc_deserialize() {
|
||||
TEST_START();
|
||||
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
@@ -356,9 +320,7 @@ bool car_unique_ptr_deserialize() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() { return car_deserialize_with_map()
|
||||
&& car_deserialize_to_map()
|
||||
&& list_car_deserialize()
|
||||
bool run() { return list_car_deserialize()
|
||||
&& optional_car_deserialize()
|
||||
&& car_unique_ptr_deserialize()
|
||||
&& vector_car_deserialize()
|
||||
|
||||
@@ -5,51 +5,23 @@ using namespace simdjson;
|
||||
|
||||
namespace misc_tests {
|
||||
using namespace std;
|
||||
bool issue2354() {
|
||||
TEST_START();
|
||||
auto json = "true "_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
bool b;
|
||||
ASSERT_SUCCESS(doc.get_bool().get(b));
|
||||
ASSERT_TRUE(b);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool issue2355() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser parser;
|
||||
auto json = "[\"extra close\"]]"_padded;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
simdjson::ondemand::array test;
|
||||
ASSERT_SUCCESS(doc.get_array().get(test));
|
||||
for(auto vale : test) {
|
||||
std::string_view str;
|
||||
ASSERT_SUCCESS(vale.get_string().get(str));
|
||||
ASSERT_EQUAL(str, "extra close");
|
||||
}
|
||||
ASSERT_FALSE(doc.at_end());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue2322() {
|
||||
TEST_START();
|
||||
std::vector<std::pair<std::string, bool>> examples = {{R"("hello")", false},
|
||||
{R"(\"hello)", true},
|
||||
{R"("hello\")", true},
|
||||
{R"("hel\"lo")", false},
|
||||
{R"("hel\\lo")", false},
|
||||
{R"(\"hel\\\"lo\")", true},
|
||||
{R"(\\"hel\\\"lo\")", false}};
|
||||
for (std::pair<std::string, bool> v : examples) {
|
||||
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first),
|
||||
v.second);
|
||||
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first.c_str()),
|
||||
v.second);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
bool issue2322() {
|
||||
TEST_START();
|
||||
std::vector<std::pair<std::string, bool>> examples = {{R"("hello")", false},
|
||||
{R"(\"hello)", true},
|
||||
{R"("hello\")", true},
|
||||
{R"("hel\"lo")", false},
|
||||
{R"("hel\\lo")", false},
|
||||
{R"(\"hel\\\"lo\")", true},
|
||||
{R"(\\"hel\\\"lo\")", false}};
|
||||
for (std::pair<std::string, bool> v : examples) {
|
||||
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first),
|
||||
v.second);
|
||||
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first.c_str()),
|
||||
v.second);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
// user reported an asan error:
|
||||
bool issue2199() {
|
||||
@@ -683,8 +655,6 @@ namespace misc_tests {
|
||||
|
||||
bool run() {
|
||||
return
|
||||
issue2355() &&
|
||||
issue2354() &&
|
||||
issue2322() &&
|
||||
issue2312() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
@@ -10,20 +10,6 @@ using namespace std;
|
||||
using namespace simdjson;
|
||||
using error_code = simdjson::error_code;
|
||||
|
||||
bool fatal_error() {
|
||||
TEST_START();
|
||||
padded_string badjson = R"( { "make": "Toyota", "model": "Camry", "year"})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
auto errordoc = parser.iterate(badjson).get(doc);
|
||||
if(errordoc != simdjson::SUCCESS) { return false; }
|
||||
simdjson::ondemand::value v;
|
||||
auto error = doc.get_object()["year"].get(v);
|
||||
ASSERT_TRUE(simdjson::is_fatal(error));
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool simplepad() {
|
||||
std::string json = "[1]";
|
||||
ondemand::parser parser;
|
||||
@@ -36,14 +22,14 @@ bool string1() {
|
||||
const char * data = "my data"; // 7 bytes
|
||||
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
||||
std::cout << my_padded_data << std::endl;
|
||||
TEST_SUCCEED();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string2() {
|
||||
std::string data = "my data";
|
||||
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
||||
std::cout << my_padded_data << std::endl;
|
||||
TEST_SUCCEED();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool to_string_example_no_except() {
|
||||
@@ -286,22 +272,6 @@ bool at_end() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool at_end_array() {
|
||||
TEST_START();
|
||||
auto json = R"(["extra close"]])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
ondemand::array array = doc.get_array();
|
||||
for (std::string_view values : array) {
|
||||
std::cout << values << std::endl;
|
||||
}
|
||||
if(!doc.at_end()) {
|
||||
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool examplecrt() {
|
||||
TEST_START();
|
||||
padded_string padded_input_json = R"([
|
||||
@@ -1923,7 +1893,6 @@ bool value_raw_json_object() {
|
||||
#endif
|
||||
bool run() {
|
||||
return true
|
||||
&& fatal_error()
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
#if SIMDJSON_CPLUSPLUS17
|
||||
&& big_int_array()
|
||||
@@ -1987,9 +1956,8 @@ bool run() {
|
||||
&& current_location_tape_error_with_except()
|
||||
&& examplecrt()
|
||||
&& examplecrt_realloc()
|
||||
&& at_end_array()
|
||||
#endif
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
Reference in New Issue
Block a user