mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
14 Commits
riscv_develop
...
v4.0.6
| Author | SHA1 | Date | |
|---|---|---|---|
| b2932d1b8f | |||
| a7811090ef | |||
| 3320885fac | |||
| 786c68b158 | |||
| 703ef54bd9 | |||
| 2526068e2f | |||
| ddc7b8c7dd | |||
| d8f90bdd14 | |||
| e38a4923e5 | |||
| e6dfa2e0ed | |||
| 1f369ef210 | |||
| 22dcdc9f1e | |||
| dda2dafa30 | |||
| 72e9d44e10 |
@@ -31,4 +31,4 @@ jobs:
|
|||||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||||
mkdir testfindpackage &&
|
mkdir testfindpackage &&
|
||||||
cd testfindpackage &&
|
cd testfindpackage &&
|
||||||
echo -e 'cmake_minimum_required(VERSION 3.1)\nproject(simdjsontester)\nset(CMAKE_CXX_STANDARD 17)\nfind_package(simdjson REQUIRED)'> CMakeLists.txt && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../destination .. && cmake --build .
|
echo -e 'cmake_minimum_required(VERSION 3.14)\nproject(simdjsontester)\nset(CMAKE_CXX_STANDARD 17)\nfind_package(simdjson REQUIRED)'> CMakeLists.txt && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../destination .. && cmake --build .
|
||||||
|
|||||||
@@ -31,4 +31,4 @@ jobs:
|
|||||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||||
mkdir testfindpackage &&
|
mkdir testfindpackage &&
|
||||||
cd testfindpackage &&
|
cd testfindpackage &&
|
||||||
echo -e 'cmake_minimum_required(VERSION 3.1)\nproject(simdjsontester)\nset(CMAKE_CXX_STANDARD 17)\nfind_package(simdjson REQUIRED)'> CMakeLists.txt && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../destination .. && cmake --build .
|
echo -e 'cmake_minimum_required(VERSION 3.14)\nproject(simdjsontester)\nset(CMAKE_CXX_STANDARD 17)\nfind_package(simdjson REQUIRED)'> CMakeLists.txt && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../destination .. && cmake --build .
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
|||||||
project(
|
project(
|
||||||
simdjson
|
simdjson
|
||||||
# The version number is modified by tools/release.py
|
# The version number is modified by tools/release.py
|
||||||
VERSION 4.0.2
|
VERSION 4.0.6
|
||||||
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
|
||||||
|
|||||||
@@ -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.0.2"
|
PROJECT_NUMBER = "4.0.6"
|
||||||
|
|
||||||
# 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
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ Real-world usage
|
|||||||
- [WasmEdge](https://wasmedge.org)
|
- [WasmEdge](https://wasmedge.org)
|
||||||
- [RonDB](https://github.com/logicalclocks/rondb)
|
- [RonDB](https://github.com/logicalclocks/rondb)
|
||||||
- [GreptimeDB](https://github.com/GreptimeTeam/greptimedb)
|
- [GreptimeDB](https://github.com/GreptimeTeam/greptimedb)
|
||||||
|
- [mamba](https://github.com/mamba-org/mamba)
|
||||||
|
|
||||||
|
|
||||||
If you are planning to use simdjson in a product, please work from one of our releases.
|
If you are planning to use simdjson in a product, please work from one of our releases.
|
||||||
@@ -117,9 +118,9 @@ Godbolt
|
|||||||
-------------
|
-------------
|
||||||
|
|
||||||
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
||||||
|
* [C++26 reflection example](https://godbolt.org/z/K3Px64TqK)
|
||||||
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/7G5qE4sr9)
|
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/7G5qE4sr9)
|
||||||
* [simdjson examples with errors without exceptions](https://godbolt.org/z/e9dWb9E4v)
|
* [simdjson examples with errors without exceptions](https://godbolt.org/z/e9dWb9E4v)
|
||||||
* [C++26 reflection example](https://godbolt.org/z/xK5TGKdPb)
|
|
||||||
|
|
||||||
Performance results
|
Performance results
|
||||||
-------------------
|
-------------------
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ CPMAddPackage(
|
|||||||
EXCLUDE_FROM_ALL YES
|
EXCLUDE_FROM_ALL YES
|
||||||
)
|
)
|
||||||
|
|
||||||
|
option(SIMDJSON_USE_RUST "Build the static_reflect benchmark" OFF)
|
||||||
|
|
||||||
|
if(SIMDJSON_USER_RUST)
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
# We want the check whether Rust is available before trying to build a crate.
|
# We want the check whether Rust is available before trying to build a crate.
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
@@ -38,6 +39,9 @@ else()
|
|||||||
message(STATUS "curl https://sh.rustup.rs -sSf | sh")
|
message(STATUS "curl https://sh.rustup.rs -sSf | sh")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
else(SIMDJSON_USER_RUST)
|
||||||
|
message(STATUS "We will not benchmark serde-benchmark." )
|
||||||
|
endif(SIMDJSON_USER_RUST)
|
||||||
|
|
||||||
# Add the benchmark executable targets
|
# Add the benchmark executable targets
|
||||||
add_subdirectory(twitter_benchmark)
|
add_subdirectory(twitter_benchmark)
|
||||||
|
|||||||
@@ -174,6 +174,10 @@ else()
|
|||||||
-Werror -Wall -Wextra -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings
|
-Werror -Wall -Wextra -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings
|
||||||
-Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion
|
-Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion
|
||||||
)
|
)
|
||||||
|
if(CMAKE_CXX_STANDARD VERSION_GREATER_EQUAL 20)
|
||||||
|
target_compile_options(simdjson-internal-flags INTERFACE -Wctad-maybe-unsupported)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(SIMDJSON_GLIBCXX_ASSERTIONS "Set _GLIBCXX_ASSERTIONS" OFF)
|
option(SIMDJSON_GLIBCXX_ASSERTIONS "Set _GLIBCXX_ASSERTIONS" OFF)
|
||||||
|
|||||||
+11
-2
@@ -1395,11 +1395,14 @@ Car c = doc.get<Car>();
|
|||||||
|
|
||||||
We try to automate the parsing of any given structure or class
|
We try to automate the parsing of any given structure or class
|
||||||
by looking at its non-static public members. At compile-time,
|
by looking at its non-static public members. At compile-time,
|
||||||
the library looks at a simple structre like `Car` and
|
the library looks at a simple structure like `Car` and
|
||||||
maps it to parsing code. We call the default constructor,
|
maps it to parsing code. We call the default constructor,
|
||||||
and then assign values to the public members.
|
and then assign values to the public members.
|
||||||
|
|
||||||
|
|
||||||
|
If a key is missing in the JSON document, an error is generated (`NO_SUCH_FIELD`),
|
||||||
|
except if the attribute is of a type like `std::optional` (`simdjson::concepts::optional_type`).
|
||||||
|
|
||||||
#### Special cases
|
#### Special cases
|
||||||
|
|
||||||
However, there are instances where the construction cannot
|
However, there are instances where the construction cannot
|
||||||
@@ -1450,7 +1453,7 @@ struct complicated_weather_data {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The code might as simple as the following.
|
The code might be as simple as the following.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto padded = R"({"time":["2023-03-15T12:00:00Z"],"temperature":[42]})"_padded;
|
auto padded = R"({"time":["2023-03-15T12:00:00Z"],"temperature":[42]})"_padded;
|
||||||
@@ -1477,6 +1480,12 @@ type without a document instance like so:
|
|||||||
Car car = simdjson::from(json);
|
Car car = simdjson::from(json);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also use the `simdjson::from` syntax without exceptions, like so:
|
||||||
|
```cpp
|
||||||
|
Car car;
|
||||||
|
simdjson::error_code err = simdjson::from(json_car).get(car);
|
||||||
|
```
|
||||||
|
|
||||||
You can also use the `simdjson::from` syntax to iterate over an array.
|
You can also use the `simdjson::from` syntax to iterate over an array.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|||||||
+100
-11
@@ -34,14 +34,15 @@ It has the following methods to add content to the string:
|
|||||||
- `append_null()`: Appends the string "null" to the JSON buffer.
|
- `append_null()`: Appends the string "null" to the JSON buffer.
|
||||||
- `clear()`: Clears the contents of the JSON buffer, resetting the position to 0 while retaining the allocated capacity.
|
- `clear()`: Clears the contents of the JSON buffer, resetting the position to 0 while retaining the allocated capacity.
|
||||||
- `escape_and_append(std::string_view input)`: Appends a string view to the JSON buffer after escaping special characters (e.g., quotes, backslashes) as required by JSON.
|
- `escape_and_append(std::string_view input)`: Appends a string view to the JSON buffer after escaping special characters (e.g., quotes, backslashes) as required by JSON.
|
||||||
- `escape_and_append_with_quotes(std::string_view input)` Appends a string view surrounded by double quotes (e.g., "input") to the JSON buffer after escaping special characters.
|
- `escape_and_append_with_quotes(std::string_view input)` Appends a string view surrounded by double quotes (e.g., "input") to the JSON buffer after escaping special characters. For constant strings, you may also do `escape_and_append_with_quotes<"mystring">()`.
|
||||||
Parameters:
|
|
||||||
- `escape_and_append_with_quotes(char input)`: Appends a single character surrounded by double quotes (e.g., "c") to the JSON buffer after escaping it if necessary.
|
- `escape_and_append_with_quotes(char input)`: Appends a single character surrounded by double quotes (e.g., "c") to the JSON buffer after escaping it if necessary.
|
||||||
- `append_raw(const char *c)`: Appends a null-terminated C string directly to the JSON buffer without escaping.
|
- `append_raw(const char *c)`: Appends a null-terminated C string directly to the JSON buffer without escaping.
|
||||||
- `append_raw(std::string_view input)`: Appends a string view directly to the JSON buffer without escaping.
|
- `append_raw(std::string_view input)`: Appends a string view directly to the JSON buffer without escaping.
|
||||||
- `append_raw(const char *str, size_t len)`: Appends a specified number of characters from a C string directly to the JSON
|
- `append_raw(const char *str, size_t len)`: Appends a specified number of characters from a C string directly to the JSON
|
||||||
|
- `append_key_value(key,value)`: Appends a key and a value (`"json":somevalue`)
|
||||||
|
- `append_key_value<"mykey">(value)`: Appends a key and a value (`"json":somevalue`), useful when the key is a compile-time constant (C++20).
|
||||||
|
|
||||||
After writting the content, if you have reasons to believe that the content might violate UTF-8 conventions, you can check it as follows:
|
After writing the content, if you have reasons to believe that the content might violate UTF-8 conventions, you can check it as follows:
|
||||||
|
|
||||||
- `validate_unicode()`: Checks if the content in the JSON buffer is valid UTF-8. Returns: true if the content is valid UTF-8, false otherwise.
|
- `validate_unicode()`: Checks if the content in the JSON buffer is valid UTF-8. Returns: true if the content is valid UTF-8, false otherwise.
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ Once you are satisfied, you can recover the string as follows:
|
|||||||
|
|
||||||
- `operator std::string()`: Converts the JSON buffer to an std::string. (Might throw if an error occurred.)
|
- `operator std::string()`: Converts the JSON buffer to an std::string. (Might throw if an error occurred.)
|
||||||
- `operator std::string_view()`: Converts the JSON buffer to an std::string_view. (Might throw if an error occurred.)
|
- `operator std::string_view()`: Converts the JSON buffer to an std::string_view. (Might throw if an error occurred.)
|
||||||
- `view()`: Returns a view of the written JSON buffer as a `simdjson_result<std::string_view>`.
|
- `view()`: Returns a view of the written JSON buffer as a `simdjson_result<std::string_view>` (C++20).
|
||||||
|
|
||||||
The later method (`view()`) is recommended. For performance reasons, we expect you to explicitly call `validate_unicode()` as needed (e.g., prior to calling `view()`).
|
The later method (`view()`) is recommended. For performance reasons, we expect you to explicitly call `validate_unicode()` as needed (e.g., prior to calling `view()`).
|
||||||
|
|
||||||
@@ -131,20 +132,20 @@ In all cases, the `std::string_view` instance depends the corresponding `string_
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
If you have C++20, you can simplify the code, as the `std::vector<double>` is automatically
|
If you have C++20, you can simplify the code, as the `std::vector<double>` is automatically supported. Further, we can pass the keys (which are compile-time
|
||||||
supported.
|
constant) as template parameter (for improved performance).
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
Car c = {"Toyota", "Corolla", 2017, {30.0,30.2,30.513,30.79}};
|
Car c = {"Toyota", "Corolla", 2017, {30.0,30.2,30.513,30.79}};
|
||||||
simdjson::builder::string_builder sb;
|
simdjson::builder::string_builder sb;
|
||||||
sb.start_object();
|
sb.start_object();
|
||||||
sb.append_key_value("make", c.make);
|
sb.append_key_value<"make">(c.make);
|
||||||
sb.append_comma();
|
sb.append_comma();
|
||||||
sb.append_key_value("model", c.model);
|
sb.append_key_value<"model">(c.model);
|
||||||
sb.append_comma();
|
sb.append_comma();
|
||||||
sb.append_key_value("year", c.year);
|
sb.append_key_value<"year">(c.year);
|
||||||
sb.append_comma();
|
sb.append_comma();
|
||||||
sb.append_key_value("tire_pressure", c.tire_pressure);
|
sb.append_key_value<"tire_pressure">(c.tire_pressure);
|
||||||
sb.end_object();
|
sb.end_object();
|
||||||
std::string_view p = sb.view();
|
std::string_view p = sb.view();
|
||||||
```
|
```
|
||||||
@@ -175,9 +176,52 @@ std::vector<std::vector<double>> c = {{1.0, 2.0}, {3.0, 4.0}};
|
|||||||
std::string json = simdjson::to_json(c);
|
std::string json = simdjson::to_json(c);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
We also have an overload for when you want to reuse the same `std::string` instance:
|
||||||
|
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::vector<std::vector<double>> c = {{1.0, 2.0}, {3.0, 4.0}};
|
||||||
|
std::string json;
|
||||||
|
auto error = simdjson::to_json(c, json);
|
||||||
|
if(error) { /* there was an error */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
We do recommend that you create and reuse the `string_builder` instance for performance
|
We do recommend that you create and reuse the `string_builder` instance for performance
|
||||||
reasons.
|
reasons.
|
||||||
|
|
||||||
|
You can also add custom serialization functions using a `tag_invoke` function.
|
||||||
|
For example, the following
|
||||||
|
function will allow you to serialize instances of the type `Car`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <simdjson>
|
||||||
|
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int64_t year;
|
||||||
|
std::vector<float> tire_pressure;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
|
||||||
|
template <typename builder_type>
|
||||||
|
void tag_invoke(serialize_tag, builder_type &builder, const Car& car) {
|
||||||
|
builder.start_object();
|
||||||
|
builder.append_key_value("make", car.make);
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("model", car.model);
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("year", car.year);
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("tire_pressure", car.tire_pressure);
|
||||||
|
builder.end_object();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace simdjson
|
||||||
|
```
|
||||||
|
|
||||||
C++26 static reflection
|
C++26 static reflection
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@@ -239,7 +283,17 @@ with the `simdjson::to_json` template function.
|
|||||||
If you know the output size, in bytes, of your JSON string, you may
|
If you know the output size, in bytes, of your JSON string, you may
|
||||||
pass it as a second parameter (e.g., `simdjson::to_json(c, 31123)`).
|
pass it as a second parameter (e.g., `simdjson::to_json(c, 31123)`).
|
||||||
|
|
||||||
|
Sometimes you may want to reuse the same `std::string` instance. We
|
||||||
|
have an overload for this purpose:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Car c = {"Toyota", "Corolla", 2017, {30.0,30.2,30.513,30.79}};
|
||||||
|
std::string s;
|
||||||
|
auto error = simdjson::to_json(c, s);
|
||||||
|
if(error) { /* there was an error */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then also add a third parameter for the expected output size in bytes.
|
||||||
|
|
||||||
### Without `string_buffer` instance but with explicit error handling
|
### Without `string_buffer` instance but with explicit error handling
|
||||||
|
|
||||||
@@ -248,9 +302,44 @@ pattern:
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::string json;
|
std::string json;
|
||||||
if(simdjson::to(c).get(json)) {
|
if(simdjson::to_json(c).get(json)) {
|
||||||
// there was an error
|
// there was an error
|
||||||
} else {
|
} else {
|
||||||
// json contain the serialized JSON
|
// json contain the serialized JSON
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Customization
|
||||||
|
|
||||||
|
If you want to serialize a value in a custome way, you can do it with a
|
||||||
|
`tag_invoke` specialization like the following example which will map
|
||||||
|
the year attribute to a string.
|
||||||
|
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <simdjson>
|
||||||
|
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int64_t year;
|
||||||
|
std::vector<float> tire_pressure;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
|
||||||
|
template <typename builder_type>
|
||||||
|
void tag_invoke(serialize_tag, builder_type &builder, const Car& car) {
|
||||||
|
builder.start_object();
|
||||||
|
builder.append_key_value("make", car.make);
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("model", car.model);
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("year", std::to_string(car.year));
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("tire_pressure", car.tire_pressure);
|
||||||
|
builder.end_object();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace simdjson
|
||||||
|
```
|
||||||
+1
-1
@@ -129,7 +129,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
|||||||
The strings contain unescaped valid UTF-8 strings: no unmatched surrogate is allowed.
|
The strings contain unescaped valid UTF-8 strings: no unmatched surrogate is allowed.
|
||||||
Internally, numbers are stored as either 64-bit integers or 64-bit floating-point numbers.
|
Internally, numbers are stored as either 64-bit integers or 64-bit floating-point numbers.
|
||||||
Thus it is possible to get the full 64-bit integer range (either signed or unsigned).
|
Thus it is possible to get the full 64-bit integer range (either signed or unsigned).
|
||||||
By default, the string `-0` is parsed as the integer 0 as in Pytho or C++. If you set the macro
|
By default, the string `-0` is parsed as the integer 0 as in Python or C++. If you set the macro
|
||||||
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to `1` when building simdjson, you can get that `-0` is mapped to `-0.0`
|
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to `1` when building simdjson, you can get that `-0` is mapped to `-0.0`
|
||||||
as in JavaScript. You can get the desired effect by building simdjson with cmake setting the
|
as in JavaScript. You can get the desired effect by building simdjson with cmake setting the
|
||||||
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to on: `cmake -B build -D SIMDJSON_MINUS_ZERO_AS_FLOAT=ON`.
|
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to on: `cmake -B build -D SIMDJSON_MINUS_ZERO_AS_FLOAT=ON`.
|
||||||
|
|||||||
@@ -122,11 +122,32 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
|||||||
} -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
|
} -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
|
||||||
};
|
};
|
||||||
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
||||||
|
{ obj.reset() } noexcept -> std::same_as<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace concepts
|
} // namespace concepts
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We use tag_invoke as our customization point mechanism.
|
||||||
|
*/
|
||||||
|
template <typename Tag, typename... Args>
|
||||||
|
concept tag_invocable = requires(Tag tag, Args... args) {
|
||||||
|
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Tag, typename... Args>
|
||||||
|
concept nothrow_tag_invocable =
|
||||||
|
tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
|
||||||
|
{
|
||||||
|
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
|
||||||
|
} noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
#endif // SIMDJSON_CONCEPTS_H
|
#endif // SIMDJSON_CONCEPTS_H
|
||||||
|
|||||||
@@ -58,6 +58,12 @@ inline simdjson_result<T> auto_parser<parser_type>::result() noexcept(is_nothrow
|
|||||||
return m_doc.get<T>();
|
return m_doc.get<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename parser_type>
|
||||||
|
template <typename T>
|
||||||
|
simdjson_warn_unused simdjson_inline error_code auto_parser<parser_type>::get(T &value) && noexcept(is_nothrow_gettable<T>) {
|
||||||
|
return result<T>().get(value);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename parser_type>
|
template <typename parser_type>
|
||||||
inline simdjson_result<ondemand::array> auto_parser<parser_type>::array() noexcept {
|
inline simdjson_result<ondemand::array> auto_parser<parser_type>::array() noexcept {
|
||||||
return result<ondemand::array>();
|
return result<ondemand::array>();
|
||||||
@@ -73,12 +79,7 @@ inline simdjson_result<ondemand::number> auto_parser<parser_type>::number() noex
|
|||||||
return result<ondemand::number>();
|
return result<ondemand::number>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename parser_type>
|
#if SIMDJSON_EXCEPTIONS
|
||||||
template <typename T>
|
|
||||||
inline auto_parser<parser_type>::operator simdjson_result<T>() noexcept(is_nothrow_gettable<T>) {
|
|
||||||
return result<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename parser_type>
|
template <typename parser_type>
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline auto_parser<parser_type>::operator T() noexcept(false) {
|
inline auto_parser<parser_type>::operator T() noexcept(false) {
|
||||||
@@ -87,6 +88,7 @@ inline auto_parser<parser_type>::operator T() noexcept(false) {
|
|||||||
}
|
}
|
||||||
return m_doc.get<T>();
|
return m_doc.get<T>();
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
template <typename parser_type>
|
template <typename parser_type>
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -109,13 +111,23 @@ inline T to_adaptor<T>::operator()(simdjson_result<ondemand::value> &val) const
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline auto to_adaptor<T>::operator()(padded_string_view const str) const noexcept {
|
inline auto to_adaptor<T>::operator()(padded_string_view const str) const noexcept {
|
||||||
return auto_parser{str};
|
return auto_parser<ondemand::parser *>{str};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline auto to_adaptor<T>::operator()(ondemand::parser &parser, padded_string_view const str) const noexcept {
|
inline auto to_adaptor<T>::operator()(ondemand::parser &parser, padded_string_view const str) const noexcept {
|
||||||
return auto_parser<ondemand::parser *>{parser, str};
|
return auto_parser<ondemand::parser *>{parser, str};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline auto to_adaptor<T>::operator()(std::string str) const noexcept {
|
||||||
|
return auto_parser<ondemand::parser *>{pad_with_reserve(str)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline auto to_adaptor<T>::operator()(ondemand::parser &parser, std::string str) const noexcept {
|
||||||
|
return auto_parser<ondemand::parser *>{parser, pad_with_reserve(str)};
|
||||||
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace convert
|
} // namespace convert
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -46,16 +46,19 @@ public:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<T> result() noexcept(is_nothrow_gettable<T>);
|
simdjson_warn_unused simdjson_inline simdjson_result<T> result() noexcept(is_nothrow_gettable<T>);
|
||||||
|
template <typename T>
|
||||||
|
simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept(is_nothrow_gettable<T>);
|
||||||
|
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::array> array() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::array> array() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::object> object() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::object> object() noexcept;
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::number> number() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<ondemand::number> number() noexcept;
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
simdjson_warn_unused simdjson_inline explicit(false) operator simdjson_result<T>() noexcept(is_nothrow_gettable<T>);
|
|
||||||
|
|
||||||
|
#if SIMDJSON_EXCEPTIONS
|
||||||
template <typename T>
|
template <typename T>
|
||||||
simdjson_warn_unused simdjson_inline explicit(false) operator T() noexcept(false);
|
simdjson_warn_unused simdjson_inline explicit(false) operator T() noexcept(false);
|
||||||
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
simdjson_warn_unused simdjson_inline std::optional<T> optional() noexcept(is_nothrow_gettable<T>);
|
simdjson_warn_unused simdjson_inline std::optional<T> optional() noexcept(is_nothrow_gettable<T>);
|
||||||
@@ -72,7 +75,14 @@ struct to_adaptor {
|
|||||||
T operator()(simdjson_result<ondemand::value> &val) const noexcept;
|
T operator()(simdjson_result<ondemand::value> &val) const noexcept;
|
||||||
auto operator()(padded_string_view const str) const noexcept;
|
auto operator()(padded_string_view const str) const noexcept;
|
||||||
auto operator()(ondemand::parser &parser, padded_string_view const str) const noexcept;
|
auto operator()(ondemand::parser &parser, padded_string_view const str) const noexcept;
|
||||||
|
// The std::string is padded with reserve to ensure there is enough space for padding.
|
||||||
|
// Some sanitizers may not like this, so you can use simdjson::pad instead.
|
||||||
|
// simdjson::from(simdjson::pad(str))
|
||||||
|
auto operator()(std::string str) const noexcept;
|
||||||
|
auto operator()(ondemand::parser &parser, std::string str) const noexcept;
|
||||||
};
|
};
|
||||||
|
// deduction guide
|
||||||
|
auto_parser(padded_string_view const str) -> auto_parser<ondemand::parser*>;
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace convert
|
} // namespace convert
|
||||||
|
|
||||||
|
|||||||
@@ -7,55 +7,8 @@
|
|||||||
#include "simdjson/generic/ondemand/array.h"
|
#include "simdjson/generic/ondemand/array.h"
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
#include <concepts>
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
|
|
||||||
namespace tag_invoke_fn_ns {
|
|
||||||
void tag_invoke();
|
|
||||||
|
|
||||||
struct tag_invoke_fn {
|
|
||||||
template <typename Tag, typename... Args>
|
|
||||||
requires requires(Tag tag, Args &&...args) {
|
|
||||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
constexpr auto operator()(Tag tag, Args &&...args) const
|
|
||||||
noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
|
|
||||||
std::forward<Args>(args)...)))
|
|
||||||
-> decltype(tag_invoke(std::forward<Tag>(tag),
|
|
||||||
std::forward<Args>(args)...)) {
|
|
||||||
return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace tag_invoke_fn_ns
|
|
||||||
|
|
||||||
inline namespace tag_invoke_ns {
|
|
||||||
inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
|
|
||||||
} // namespace tag_invoke_ns
|
|
||||||
|
|
||||||
template <typename Tag, typename... Args>
|
|
||||||
concept tag_invocable = requires(Tag tag, Args... args) {
|
|
||||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Tag, typename... Args>
|
|
||||||
concept nothrow_tag_invocable =
|
|
||||||
tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
|
|
||||||
{
|
|
||||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
|
|
||||||
} noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Tag, typename... Args>
|
|
||||||
using tag_invoke_result =
|
|
||||||
std::invoke_result<decltype(tag_invoke), Tag, Args...>;
|
|
||||||
|
|
||||||
template <typename Tag, typename... Args>
|
|
||||||
using tag_invoke_result_t =
|
|
||||||
std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
|
|
||||||
|
|
||||||
template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
|
|
||||||
|
|
||||||
|
|
||||||
struct deserialize_tag;
|
struct deserialize_tag;
|
||||||
|
|
||||||
/// These types are deserializable in a built-in way
|
/// These types are deserializable in a built-in way
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ concept container_but_not_string =
|
|||||||
!std::is_same_v<T, std::string_view> && !std::is_same_v<T, const char *>;
|
!std::is_same_v<T, std::string_view> && !std::is_same_v<T, const char *>;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
requires(container_but_not_string<T>)
|
requires(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) {
|
||||||
if (t.size() == 0) {
|
if (t.size() == 0) {
|
||||||
b.append_raw("[]");
|
b.append_raw("[]");
|
||||||
@@ -63,6 +63,7 @@ constexpr void atom(string_builder &b, const T &t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <concepts::string_view_keyed_map T>
|
template <concepts::string_view_keyed_map T>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
constexpr void atom(string_builder &b, const T &m) {
|
constexpr void atom(string_builder &b, const T &m) {
|
||||||
if (m.empty()) {
|
if (m.empty()) {
|
||||||
b.append_raw("{}");
|
b.append_raw("{}");
|
||||||
@@ -99,7 +100,7 @@ template <class T>
|
|||||||
!std::is_same_v<T, std::string> &&
|
!std::is_same_v<T, std::string> &&
|
||||||
!std::is_same_v<T, std::string_view> &&
|
!std::is_same_v<T, std::string_view> &&
|
||||||
!std::is_same_v<T, const char*> &&
|
!std::is_same_v<T, const char*> &&
|
||||||
!std::is_same_v<T, char>)
|
!std::is_same_v<T, char> && !require_custom_serialization<T>)
|
||||||
constexpr void atom(string_builder &b, const T &t) {
|
constexpr void atom(string_builder &b, const T &t) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
b.append('{');
|
b.append('{');
|
||||||
@@ -117,6 +118,7 @@ constexpr void atom(string_builder &b, const T &t) {
|
|||||||
|
|
||||||
// Support for optional types (std::optional, etc.)
|
// Support for optional types (std::optional, etc.)
|
||||||
template <concepts::optional_type T>
|
template <concepts::optional_type T>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
constexpr void atom(string_builder &b, const T &opt) {
|
constexpr void atom(string_builder &b, const T &opt) {
|
||||||
if (opt) {
|
if (opt) {
|
||||||
atom(b, opt.value());
|
atom(b, opt.value());
|
||||||
@@ -127,6 +129,7 @@ constexpr void atom(string_builder &b, const T &opt) {
|
|||||||
|
|
||||||
// Support for smart pointers (std::unique_ptr, std::shared_ptr, etc.)
|
// Support for smart pointers (std::unique_ptr, std::shared_ptr, etc.)
|
||||||
template <concepts::smart_pointer T>
|
template <concepts::smart_pointer T>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
constexpr void atom(string_builder &b, const T &ptr) {
|
constexpr void atom(string_builder &b, const T &ptr) {
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
atom(b, *ptr);
|
atom(b, *ptr);
|
||||||
@@ -137,7 +140,7 @@ constexpr void atom(string_builder &b, const T &ptr) {
|
|||||||
|
|
||||||
// Support for enums - serialize as string representation using expand approach from P2996R12
|
// Support for enums - serialize as string representation using expand approach from P2996R12
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires(std::is_enum_v<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
|
||||||
constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
|
constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
|
||||||
@@ -161,7 +164,7 @@ template <concepts::appendable_containers T>
|
|||||||
requires(!container_but_not_string<T> && !concepts::string_view_keyed_map<T> &&
|
requires(!container_but_not_string<T> && !concepts::string_view_keyed_map<T> &&
|
||||||
!concepts::optional_type<T> && !concepts::smart_pointer<T> &&
|
!concepts::optional_type<T> && !concepts::smart_pointer<T> &&
|
||||||
!std::is_same_v<T, std::string> &&
|
!std::is_same_v<T, std::string> &&
|
||||||
!std::is_same_v<T, std::string_view> && !std::is_same_v<T, const char*>)
|
!std::is_same_v<T, std::string_view> && !std::is_same_v<T, const char*> && !require_custom_serialization<T>)
|
||||||
constexpr void atom(string_builder &b, const T &container) {
|
constexpr void atom(string_builder &b, const T &container) {
|
||||||
if (container.empty()) {
|
if (container.empty()) {
|
||||||
b.append_raw("[]");
|
b.append_raw("[]");
|
||||||
@@ -196,11 +199,13 @@ void append(string_builder &b, const T &t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <concepts::optional_type T>
|
template <concepts::optional_type T>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
void append(string_builder &b, const T &t) {
|
void append(string_builder &b, const T &t) {
|
||||||
atom(b, t);
|
atom(b, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <concepts::smart_pointer T>
|
template <concepts::smart_pointer T>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
void append(string_builder &b, const T &t) {
|
void append(string_builder &b, const T &t) {
|
||||||
atom(b, t);
|
atom(b, t);
|
||||||
}
|
}
|
||||||
@@ -209,12 +214,13 @@ template <concepts::appendable_containers T>
|
|||||||
requires(!container_but_not_string<T> && !concepts::string_view_keyed_map<T> &&
|
requires(!container_but_not_string<T> && !concepts::string_view_keyed_map<T> &&
|
||||||
!concepts::optional_type<T> && !concepts::smart_pointer<T> &&
|
!concepts::optional_type<T> && !concepts::smart_pointer<T> &&
|
||||||
!std::is_same_v<T, std::string> &&
|
!std::is_same_v<T, std::string> &&
|
||||||
!std::is_same_v<T, std::string_view> && !std::is_same_v<T, const char*>)
|
!std::is_same_v<T, std::string_view> && !std::is_same_v<T, const char*> && !require_custom_serialization<T>)
|
||||||
void append(string_builder &b, const T &t) {
|
void append(string_builder &b, const T &t) {
|
||||||
atom(b, t);
|
atom(b, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <concepts::string_view_keyed_map T>
|
template <concepts::string_view_keyed_map T>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
void append(string_builder &b, const T &t) {
|
void append(string_builder &b, const T &t) {
|
||||||
atom(b, t);
|
atom(b, t);
|
||||||
}
|
}
|
||||||
@@ -229,7 +235,7 @@ template <class Z>
|
|||||||
!std::is_same_v<Z, std::string> &&
|
!std::is_same_v<Z, std::string> &&
|
||||||
!std::is_same_v<Z, std::string_view> &&
|
!std::is_same_v<Z, std::string_view> &&
|
||||||
!std::is_same_v<Z, const char*> &&
|
!std::is_same_v<Z, const char*> &&
|
||||||
!std::is_same_v<Z, char>)
|
!std::is_same_v<Z, char> && !require_custom_serialization<Z>)
|
||||||
void append(string_builder &b, const Z &z) {
|
void append(string_builder &b, const Z &z) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
b.append('{');
|
b.append('{');
|
||||||
@@ -247,7 +253,7 @@ void append(string_builder &b, const Z &z) {
|
|||||||
|
|
||||||
// works for container
|
// works for container
|
||||||
template <class Z>
|
template <class Z>
|
||||||
requires(container_but_not_string<Z>)
|
requires(container_but_not_string<Z> && !require_custom_serialization<Z>)
|
||||||
void append(string_builder &b, const Z &z) {
|
void append(string_builder &b, const Z &z) {
|
||||||
if (z.size() == 0) {
|
if (z.size() == 0) {
|
||||||
b.append_raw("[]");
|
b.append_raw("[]");
|
||||||
@@ -263,7 +269,14 @@ void append(string_builder &b, const Z &z) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Z>
|
template <class Z>
|
||||||
simdjson_result<std::string> to_json_string(const Z &z, size_t initial_capacity = 1024) {
|
requires (require_custom_serialization<Z>)
|
||||||
|
void append(string_builder &b, const Z &z) {
|
||||||
|
b.append(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class Z>
|
||||||
|
simdjson_warn_unused simdjson_result<std::string> to_json_string(const Z &z, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) {
|
||||||
string_builder b(initial_capacity);
|
string_builder b(initial_capacity);
|
||||||
append(b, z);
|
append(b, z);
|
||||||
std::string_view s;
|
std::string_view s;
|
||||||
@@ -272,8 +285,8 @@ simdjson_result<std::string> to_json_string(const Z &z, size_t initial_capacity
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Z>
|
template <class Z>
|
||||||
simdjson_error to_json(const Z &z, std::string &s) {
|
simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = string_builder::DEFAULT_INITIAL_CAPACITY) {
|
||||||
string_builder b;
|
string_builder b(initial_capacity);
|
||||||
append(b, z);
|
append(b, z);
|
||||||
std::string_view view;
|
std::string_view view;
|
||||||
if(auto e = b.view().get(view); e) { return e; }
|
if(auto e = b.view().get(view); e) { return e; }
|
||||||
@@ -290,9 +303,13 @@ string_builder& operator<<(string_builder& b, const Z& z) {
|
|||||||
} // namespace SIMDJSON_IMPLEMENTATION
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
// Alias the function template to 'to' in the global namespace
|
// Alias the function template to 'to' in the global namespace
|
||||||
template <class Z>
|
template <class Z>
|
||||||
simdjson_result<std::string> to_json(const Z &z, size_t initial_capacity = 1024) {
|
simdjson_warn_unused simdjson_result<std::string> to_json(const Z &z, size_t initial_capacity = SIMDJSON_IMPLEMENTATION::builder::string_builder::DEFAULT_INITIAL_CAPACITY) {
|
||||||
return SIMDJSON_IMPLEMENTATION::builder::to_json_string(z, initial_capacity);
|
return SIMDJSON_IMPLEMENTATION::builder::to_json_string(z, initial_capacity);
|
||||||
}
|
}
|
||||||
|
template <class Z>
|
||||||
|
simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = SIMDJSON_IMPLEMENTATION::builder::string_builder::DEFAULT_INITIAL_CAPACITY) {
|
||||||
|
return SIMDJSON_IMPLEMENTATION::builder::to_json(z, s, initial_capacity);
|
||||||
|
}
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_STATIC_REFLECTION
|
#endif // SIMDJSON_STATIC_REFLECTION
|
||||||
|
|||||||
@@ -284,10 +284,12 @@ simdjson_inline void string_builder::clear() noexcept {
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// We could specialize further for 32-bit integers.
|
|
||||||
simdjson_really_inline int int_log2(uint32_t x) { return (63 - leading_zeroes(x | 1)); }
|
|
||||||
|
|
||||||
simdjson_really_inline int fast_digit_count(uint32_t x) {
|
template <typename number_type, typename = typename std::enable_if<
|
||||||
|
std::is_unsigned<number_type>::value>::type>
|
||||||
|
simdjson_really_inline int int_log2(number_type x) { return 63 - leading_zeroes(uint64_t(x) | 1); }
|
||||||
|
|
||||||
|
simdjson_really_inline int fast_digit_count_32(uint32_t x) {
|
||||||
static uint64_t table[] = {
|
static uint64_t table[] = {
|
||||||
4294967296, 8589934582, 8589934582, 8589934582, 12884901788,
|
4294967296, 8589934582, 8589934582, 8589934582, 12884901788,
|
||||||
12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
|
12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
|
||||||
@@ -299,9 +301,8 @@ simdjson_really_inline int fast_digit_count(uint32_t x) {
|
|||||||
return uint32_t((x + table[int_log2(x)]) >> 32);
|
return uint32_t((x + table[int_log2(x)]) >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_really_inline int int_log2(uint64_t x) { return 63 - leading_zeroes(x | 1); }
|
|
||||||
|
|
||||||
simdjson_really_inline int fast_digit_count(uint64_t x) {
|
simdjson_really_inline int fast_digit_count_64(uint64_t x) {
|
||||||
static uint64_t table[] = {9,
|
static uint64_t table[] = {9,
|
||||||
99,
|
99,
|
||||||
999,
|
999,
|
||||||
@@ -332,7 +333,11 @@ simdjson_really_inline size_t digit_count(number_type v) noexcept {
|
|||||||
static_assert(sizeof(number_type) == 8 || sizeof(number_type) == 4 ||
|
static_assert(sizeof(number_type) == 8 || sizeof(number_type) == 4 ||
|
||||||
sizeof(number_type) == 2 || sizeof(number_type) == 1,
|
sizeof(number_type) == 2 || sizeof(number_type) == 1,
|
||||||
"We only support 8-bit, 16-bit, 32-bit and 64-bit numbers");
|
"We only support 8-bit, 16-bit, 32-bit and 64-bit numbers");
|
||||||
return fast_digit_count(v);
|
SIMDJSON_IF_CONSTEXPR(sizeof(number_type) <= 4) {
|
||||||
|
return fast_digit_count_32(static_cast<uint32_t>(v));
|
||||||
|
} else {
|
||||||
|
return fast_digit_count_64(static_cast<uint64_t>(v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static const char decimal_table[200] = {
|
static const char decimal_table[200] = {
|
||||||
0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35,
|
0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35,
|
||||||
@@ -355,6 +360,7 @@ static const char decimal_table[200] = {
|
|||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
|
||||||
template <typename number_type, typename>
|
template <typename number_type, typename>
|
||||||
simdjson_inline void string_builder::append(number_type v) noexcept {
|
simdjson_inline void string_builder::append(number_type v) noexcept {
|
||||||
static_assert(std::is_same<number_type, bool>::value ||
|
static_assert(std::is_same<number_type, bool>::value ||
|
||||||
@@ -470,6 +476,12 @@ simdjson_inline void string_builder::escape_and_append_with_quotes(const char* i
|
|||||||
std::string_view cinput(input);
|
std::string_view cinput(input);
|
||||||
escape_and_append_with_quotes(cinput);
|
escape_and_append_with_quotes(cinput);
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
template<internal::fixed_string key>
|
||||||
|
simdjson_inline void string_builder::escape_and_append_with_quotes() noexcept {
|
||||||
|
escape_and_append_with_quotes(internal::string_constant<key>::value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
simdjson_inline void string_builder::append_raw(const char *c) noexcept {
|
simdjson_inline void string_builder::append_raw(const char *c) noexcept {
|
||||||
size_t len = std::strlen(c);
|
size_t len = std::strlen(c);
|
||||||
@@ -494,6 +506,7 @@ simdjson_inline void string_builder::append_raw(const char *str,
|
|||||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
// Support for optional types (std::optional, etc.)
|
// Support for optional types (std::optional, etc.)
|
||||||
template <concepts::optional_type T>
|
template <concepts::optional_type T>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
simdjson_inline void string_builder::append(const T &opt) {
|
simdjson_inline void string_builder::append(const T &opt) {
|
||||||
if (opt) {
|
if (opt) {
|
||||||
append(*opt);
|
append(*opt);
|
||||||
@@ -501,6 +514,14 @@ simdjson_inline void string_builder::append(const T &opt) {
|
|||||||
append_null();
|
append_null();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(require_custom_serialization<T>)
|
||||||
|
simdjson_inline void string_builder::append(const T &val) {
|
||||||
|
serialize(*this, val);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires(std::is_convertible<T, std::string_view>::value ||
|
requires(std::is_convertible<T, std::string_view>::value ||
|
||||||
std::is_same<T, const char*>::value)
|
std::is_same<T, const char*>::value)
|
||||||
@@ -649,6 +670,25 @@ simdjson_inline void string_builder::append_key_value(key_type key, value_type v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
template<internal::fixed_string key, typename value_type>
|
||||||
|
simdjson_inline void string_builder::append_key_value(value_type value) noexcept {
|
||||||
|
escape_and_append_with_quotes<key>();
|
||||||
|
append_colon();
|
||||||
|
SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, std::nullptr_t>::value) {
|
||||||
|
append_null();
|
||||||
|
} else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, char>::value) {
|
||||||
|
escape_and_append_with_quotes(value);
|
||||||
|
} else SIMDJSON_IF_CONSTEXPR(std::is_convertible<value_type, std::string_view>::value) {
|
||||||
|
escape_and_append_with_quotes(value);
|
||||||
|
} else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, const char*>::value) {
|
||||||
|
escape_and_append_with_quotes(value);
|
||||||
|
} else {
|
||||||
|
append(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace builder
|
} // namespace builder
|
||||||
} // namespace SIMDJSON_IMPLEMENTATION
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -10,9 +10,62 @@
|
|||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
|
|
||||||
|
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|
||||||
namespace SIMDJSON_IMPLEMENTATION {
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
namespace builder {
|
namespace builder {
|
||||||
|
class string_builder;
|
||||||
|
}}
|
||||||
|
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct has_custom_serialization : std::false_type {};
|
||||||
|
|
||||||
|
inline constexpr struct serialize_tag {
|
||||||
|
template <typename T>
|
||||||
|
requires custom_deserializable<T>
|
||||||
|
constexpr void operator()(SIMDJSON_IMPLEMENTATION::builder::string_builder& b, T& obj) const{
|
||||||
|
return tag_invoke(*this, b, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} serialize{};
|
||||||
|
template <typename T>
|
||||||
|
struct has_custom_serialization<T, std::void_t<
|
||||||
|
decltype(tag_invoke(serialize, std::declval<SIMDJSON_IMPLEMENTATION::builder::string_builder&>(), std::declval<T&>()))
|
||||||
|
>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool require_custom_serialization = has_custom_serialization<T>::value;
|
||||||
|
#else
|
||||||
|
struct has_custom_serialization : std::false_type {};
|
||||||
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace builder {
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
// Helper to create string constants
|
||||||
|
namespace internal {
|
||||||
|
template <std::size_t N>
|
||||||
|
struct fixed_string {
|
||||||
|
constexpr fixed_string(const char (&str)[N]) {
|
||||||
|
for (std::size_t i = 0; i < N; ++i) {
|
||||||
|
data[i] = str[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char data[N];
|
||||||
|
constexpr std::string_view view() const { return {data, N - 1}; }
|
||||||
|
};
|
||||||
|
template <std::size_t N>
|
||||||
|
fixed_string(const char (&)[N]) -> fixed_string<N>;
|
||||||
|
|
||||||
|
template <fixed_string str>
|
||||||
|
struct string_constant {
|
||||||
|
static constexpr std::string_view value = str.view();
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
/**
|
/**
|
||||||
* A builder for JSON strings representing documents. This is a low-level
|
* A builder for JSON strings representing documents. This is a low-level
|
||||||
* builder that is not meant to be used directly by end-users. Though it
|
* builder that is not meant to be used directly by end-users. Though it
|
||||||
@@ -24,7 +77,9 @@ namespace builder {
|
|||||||
*/
|
*/
|
||||||
class string_builder {
|
class string_builder {
|
||||||
public:
|
public:
|
||||||
simdjson_inline string_builder(size_t initial_capacity = 1024);
|
simdjson_inline string_builder(size_t initial_capacity = DEFAULT_INITIAL_CAPACITY);
|
||||||
|
|
||||||
|
static constexpr size_t DEFAULT_INITIAL_CAPACITY = 1024;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append number (includes Booleans). Booleans are mapped to the strings
|
* Append number (includes Booleans). Booleans are mapped to the strings
|
||||||
@@ -62,7 +117,10 @@ public:
|
|||||||
* There is no UTF-8 validation.
|
* There is no UTF-8 validation.
|
||||||
*/
|
*/
|
||||||
simdjson_inline void escape_and_append_with_quotes(std::string_view input) noexcept;
|
simdjson_inline void escape_and_append_with_quotes(std::string_view input) noexcept;
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
template<internal::fixed_string key>
|
||||||
|
simdjson_inline void escape_and_append_with_quotes() noexcept;
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* Append the character surrounded by double quotes, after escaping it.
|
* Append the character surrounded by double quotes, after escaping it.
|
||||||
* There is no UTF-8 validation.
|
* There is no UTF-8 validation.
|
||||||
@@ -119,10 +177,18 @@ public:
|
|||||||
template<typename key_type, typename value_type>
|
template<typename key_type, typename value_type>
|
||||||
simdjson_inline void append_key_value(key_type key, value_type value) noexcept;
|
simdjson_inline void append_key_value(key_type key, value_type value) noexcept;
|
||||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
template<internal::fixed_string key, typename value_type>
|
||||||
|
simdjson_inline void append_key_value(value_type value) noexcept;
|
||||||
|
|
||||||
// Support for optional types (std::optional, etc.)
|
// Support for optional types (std::optional, etc.)
|
||||||
template <concepts::optional_type T>
|
template <concepts::optional_type T>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
simdjson_inline void append(const T &opt);
|
simdjson_inline void append(const T &opt);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(require_custom_serialization<T>)
|
||||||
|
simdjson_inline void append(const T &val);
|
||||||
|
|
||||||
// Support for string-like types
|
// Support for string-like types
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires(std::is_convertible<T, std::string_view>::value ||
|
requires(std::is_convertible<T, std::string_view>::value ||
|
||||||
@@ -232,7 +298,7 @@ private:
|
|||||||
#if !SIMDJSON_STATIC_REFLECTION
|
#if !SIMDJSON_STATIC_REFLECTION
|
||||||
// fallback implementation until we have static reflection
|
// fallback implementation until we have static reflection
|
||||||
template <class Z>
|
template <class Z>
|
||||||
simdjson_result<std::string> to_json(const Z &z, size_t initial_capacity = 1024) {
|
simdjson_warn_unused simdjson_result<std::string> to_json(const Z &z, size_t initial_capacity = simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder::DEFAULT_INITIAL_CAPACITY) {
|
||||||
simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder b(initial_capacity);
|
simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder b(initial_capacity);
|
||||||
b.append(z);
|
b.append(z);
|
||||||
std::string_view s;
|
std::string_view s;
|
||||||
@@ -240,8 +306,20 @@ simdjson_result<std::string> to_json(const Z &z, size_t initial_capacity = 1024)
|
|||||||
if(e) { return e; }
|
if(e) { return e; }
|
||||||
return std::string(s);
|
return std::string(s);
|
||||||
}
|
}
|
||||||
|
template <class Z>
|
||||||
|
simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t initial_capacity = simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder::DEFAULT_INITIAL_CAPACITY) {
|
||||||
|
simdjson::SIMDJSON_IMPLEMENTATION::builder::string_builder b(initial_capacity);
|
||||||
|
b.append(z);
|
||||||
|
std::string_view sv;
|
||||||
|
auto e = b.view().get(sv);
|
||||||
|
if(e) { return e; }
|
||||||
|
s.assign(sv.data(), sv.size());
|
||||||
|
return simdjson::SUCCESS;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -16,15 +16,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
template <typename T>
|
|
||||||
constexpr bool require_custom_serialization = false;
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
// Number deserialization
|
// Number deserialization
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
template <std::unsigned_integral T>
|
template <std::unsigned_integral T>
|
||||||
requires(!require_custom_serialization<T>)
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||||
using limits = std::numeric_limits<T>;
|
using limits = std::numeric_limits<T>;
|
||||||
|
|
||||||
@@ -38,7 +35,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <std::floating_point T>
|
template <std::floating_point T>
|
||||||
requires(!require_custom_serialization<T>)
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||||
double x;
|
double x;
|
||||||
SIMDJSON_TRY(val.get_double().get(x));
|
SIMDJSON_TRY(val.get_double().get(x));
|
||||||
@@ -47,7 +43,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <std::signed_integral T>
|
template <std::signed_integral T>
|
||||||
requires(!require_custom_serialization<T>)
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||||
using limits = std::numeric_limits<T>;
|
using limits = std::numeric_limits<T>;
|
||||||
|
|
||||||
@@ -77,7 +72,6 @@ error_code tag_invoke(deserialize_tag, auto &val, char &out) noexcept {
|
|||||||
|
|
||||||
// any string-like type (can be constructed from std::string_view)
|
// any string-like type (can be constructed from std::string_view)
|
||||||
template <concepts::constructible_from_string_view T, typename ValT>
|
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>) {
|
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v<T, std::string_view>) {
|
||||||
std::string_view str;
|
std::string_view str;
|
||||||
SIMDJSON_TRY(val.get_string().get(str));
|
SIMDJSON_TRY(val.get_string().get(str));
|
||||||
@@ -94,7 +88,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr
|
|||||||
* doc.get<std::vector<int>>().
|
* doc.get<std::vector<int>>().
|
||||||
*/
|
*/
|
||||||
template <concepts::appendable_containers T, typename ValT>
|
template <concepts::appendable_containers T, typename ValT>
|
||||||
requires(!require_custom_serialization<T>)
|
|
||||||
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
||||||
using value_type = typename std::remove_cvref_t<T>::value_type;
|
using value_type = typename std::remove_cvref_t<T>::value_type;
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -140,7 +133,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
|||||||
* string-keyed types.
|
* string-keyed types.
|
||||||
*/
|
*/
|
||||||
template <concepts::string_view_keyed_map T, typename ValT>
|
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) {
|
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
||||||
using value_type = typename std::remove_cvref_t<T>::mapped_type;
|
using value_type = typename std::remove_cvref_t<T>::mapped_type;
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -222,7 +214,6 @@ error_code tag_invoke(deserialize_tag, SIMDJSON_IMPLEMENTATION::ondemand::docume
|
|||||||
* @return status of the conversion
|
* @return status of the conversion
|
||||||
*/
|
*/
|
||||||
template <concepts::smart_pointer T, typename ValT>
|
template <concepts::smart_pointer T, typename ValT>
|
||||||
requires(!require_custom_serialization<T>)
|
|
||||||
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
|
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
|
||||||
using element_type = typename std::remove_cvref_t<T>::element_type;
|
using element_type = typename std::remove_cvref_t<T>::element_type;
|
||||||
|
|
||||||
@@ -248,7 +239,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser
|
|||||||
* This CPO (Customization Point Object) will help deserialize into optional types.
|
* This CPO (Customization Point Object) will help deserialize into optional types.
|
||||||
*/
|
*/
|
||||||
template <concepts::optional_type T>
|
template <concepts::optional_type T>
|
||||||
requires(!require_custom_serialization<T>)
|
|
||||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, decltype(val)>) {
|
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, decltype(val)>) {
|
||||||
using value_type = typename std::remove_cvref_t<T>::value_type;
|
using value_type = typename std::remove_cvref_t<T>::value_type;
|
||||||
|
|
||||||
@@ -274,7 +264,7 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept(nothrow_deser
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr bool user_defined_type = (std::is_class_v<T>
|
constexpr bool user_defined_type = (std::is_class_v<T>
|
||||||
&& !std::is_same_v<T, std::string> && !std::is_same_v<T, std::string_view> && !concepts::optional_type<T> &&
|
&& !std::is_same_v<T, std::string> && !std::is_same_v<T, std::string_view> && !concepts::optional_type<T> &&
|
||||||
!concepts::appendable_containers<T> && !require_custom_serialization<T>);
|
!concepts::appendable_containers<T>);
|
||||||
|
|
||||||
|
|
||||||
template <typename T, typename ValT>
|
template <typename T, typename ValT>
|
||||||
@@ -286,18 +276,26 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
|
|||||||
} else {
|
} else {
|
||||||
SIMDJSON_TRY(val.get_object().get(obj));
|
SIMDJSON_TRY(val.get_object().get(obj));
|
||||||
}
|
}
|
||||||
error_code e = simdjson::SUCCESS;
|
|
||||||
template for (constexpr auto mem : 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(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
|
||||||
if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
|
if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
|
||||||
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));
|
||||||
// Note: removed static assert as optional types are now handled generically
|
if constexpr (concepts::optional_type<decltype(out.[:mem:])>) {
|
||||||
// as long we are succesful or the field is not found, we continue
|
// for optional members, it's ok if the key is missing
|
||||||
if(e == simdjson::SUCCESS || e == simdjson::NO_SUCH_FIELD) {
|
auto error = obj[key].get(out.[:mem:]);
|
||||||
e = obj[key].get(out.[:mem:]);
|
if (error && error != NO_SUCH_FIELD) {
|
||||||
|
if(error == NO_SUCH_FIELD) {
|
||||||
|
out.[:mem:].reset();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// for non-optional members, the key must be present
|
||||||
|
SIMDJSON_TRY(obj[key].get(out.[:mem:]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return e;
|
return simdjson::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support for enum deserialization - deserialize from string representation using expand approach from P2996R12
|
// Support for enum deserialization - deserialize from string representation using expand approach from P2996R12
|
||||||
|
|||||||
@@ -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.0.2"
|
#define SIMDJSON_VERSION "4.0.6"
|
||||||
|
|
||||||
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 = 2
|
SIMDJSON_VERSION_REVISION = 6
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* auto-generated on 2025-09-14 09:01:41 -0600. version 4.0.2 Do not edit! */
|
/* auto-generated on 2025-09-20 22:23:09 -0600. version 4.0.6 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
|
||||||
@@ -3009,11 +3009,32 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
|||||||
} -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
|
} -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
|
||||||
};
|
};
|
||||||
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
||||||
|
{ obj.reset() } noexcept -> std::same_as<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace concepts
|
} // namespace concepts
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We use tag_invoke as our customization point mechanism.
|
||||||
|
*/
|
||||||
|
template <typename Tag, typename... Args>
|
||||||
|
concept tag_invocable = requires(Tag tag, Args... args) {
|
||||||
|
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Tag, typename... Args>
|
||||||
|
concept nothrow_tag_invocable =
|
||||||
|
tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
|
||||||
|
{
|
||||||
|
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
|
||||||
|
} noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
#endif // SIMDJSON_CONCEPTS_H
|
#endif // SIMDJSON_CONCEPTS_H
|
||||||
|
|||||||
+1415
-684
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -2,6 +2,7 @@
|
|||||||
include_directories(..)
|
include_directories(..)
|
||||||
add_cpp_test(builder_string_builder_tests LABELS ondemand acceptance per_implementation)
|
add_cpp_test(builder_string_builder_tests LABELS ondemand acceptance per_implementation)
|
||||||
if(SIMDJSON_STATIC_REFLECTION)
|
if(SIMDJSON_STATIC_REFLECTION)
|
||||||
|
add_cpp_test(static_reflection_custom_tests LABELS ondemand acceptance per_implementation)
|
||||||
add_cpp_test(static_reflection_builder_tests LABELS ondemand acceptance per_implementation)
|
add_cpp_test(static_reflection_builder_tests LABELS ondemand acceptance per_implementation)
|
||||||
add_cpp_test(static_reflection_comprehensive_tests LABELS ondemand acceptance per_implementation)
|
add_cpp_test(static_reflection_comprehensive_tests LABELS ondemand acceptance per_implementation)
|
||||||
add_cpp_test(static_reflection_edge_cases_tests LABELS ondemand acceptance per_implementation)
|
add_cpp_test(static_reflection_edge_cases_tests LABELS ondemand acceptance per_implementation)
|
||||||
|
|||||||
@@ -331,8 +331,6 @@ namespace builder_tests {
|
|||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void serialize_car(const Car& car, simdjson::builder::string_builder& builder) {
|
void serialize_car(const Car& car, simdjson::builder::string_builder& builder) {
|
||||||
// start of JSON
|
// start of JSON
|
||||||
builder.start_object();
|
builder.start_object();
|
||||||
@@ -369,7 +367,43 @@ namespace builder_tests {
|
|||||||
builder.end_object();
|
builder.end_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
void serialize_car_template(const Car& car, simdjson::builder::string_builder& builder) {
|
||||||
|
// start of JSON
|
||||||
|
builder.start_object();
|
||||||
|
|
||||||
|
// "make"
|
||||||
|
builder.append_key_value<"make">(car.make);
|
||||||
|
builder.append_comma();
|
||||||
|
|
||||||
|
// "model"
|
||||||
|
builder.append_key_value<"model">(car.model);
|
||||||
|
|
||||||
|
builder.append_comma();
|
||||||
|
|
||||||
|
// "year"
|
||||||
|
builder.append_key_value<"year">(car.year);
|
||||||
|
|
||||||
|
builder.append_comma();
|
||||||
|
|
||||||
|
// "tire_pressure"
|
||||||
|
builder.escape_and_append_with_quotes<"tire_pressure">();
|
||||||
|
builder.append_colon();
|
||||||
|
builder.start_array();
|
||||||
|
// vector tire_pressure
|
||||||
|
for (size_t i = 0; i < car.tire_pressure.size(); ++i) {
|
||||||
|
builder.append(car.tire_pressure[i]);
|
||||||
|
if (i < car.tire_pressure.size() - 1) {
|
||||||
|
builder.append_comma();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end of array
|
||||||
|
builder.end_array();
|
||||||
|
|
||||||
|
// end of object
|
||||||
|
builder.end_object();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
bool car_test() {
|
bool car_test() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
simdjson::builder::string_builder sb;
|
simdjson::builder::string_builder sb;
|
||||||
@@ -382,6 +416,17 @@ namespace builder_tests {
|
|||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
bool car_test_template() {
|
||||||
|
TEST_START();
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
Car c = {"Toyota", "Corolla", 2017, {30.0,30.2,30.513,30.79}};
|
||||||
|
serialize_car_template(c, sb);
|
||||||
|
std::string_view p;
|
||||||
|
auto result = sb.view().get(p);
|
||||||
|
ASSERT_SUCCESS(result);
|
||||||
|
ASSERT_EQUAL(p, "{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,\"tire_pressure\":[30.0,30.2,30.513,30.79]}");
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
bool serialize_optional() {
|
bool serialize_optional() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
simdjson::builder::string_builder sb;
|
simdjson::builder::string_builder sb;
|
||||||
@@ -474,6 +519,20 @@ namespace builder_tests {
|
|||||||
ASSERT_EQUAL(s, "[[1.0,2.0],[3.0,4.0]]");
|
ASSERT_EQUAL(s, "[[1.0,2.0],[3.0,4.0]]");
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
bool double_double_test_to_string() {
|
||||||
|
TEST_START();
|
||||||
|
std::vector<std::vector<double>> c = {{1.0, 2.0}, {3.0, 4.0}};
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
sb.append(c);
|
||||||
|
std::string_view p;
|
||||||
|
auto result = sb.view().get(p);
|
||||||
|
ASSERT_SUCCESS(result);
|
||||||
|
ASSERT_EQUAL(p, "[[1.0,2.0],[3.0,4.0]]");
|
||||||
|
std::string s;
|
||||||
|
simdjson::simdjson_error ec = simdjson::to_json(c,s);
|
||||||
|
ASSERT_EQUAL(s, "[[1.0,2.0],[3.0,4.0]]");
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
bool car_test_simple_complete_exceptions() {
|
bool car_test_simple_complete_exceptions() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
@@ -522,6 +581,7 @@ namespace builder_tests {
|
|||||||
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
map_test() &&
|
map_test() &&
|
||||||
double_double_test() &&
|
double_double_test() &&
|
||||||
|
double_double_test_to_string() &&
|
||||||
car_test_simple() &&
|
car_test_simple() &&
|
||||||
car_test_simple_complete() &&
|
car_test_simple_complete() &&
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
@@ -529,6 +589,7 @@ namespace builder_tests {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
car_test_template() &&
|
||||||
serialize_optional() &&
|
serialize_optional() &&
|
||||||
#endif
|
#endif
|
||||||
append_char() &&
|
append_char() &&
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include "test_builder.h"
|
||||||
|
#include <charconv>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace simdjson;
|
||||||
|
|
||||||
|
// Suppose that we want to serialize/deserialize Car using
|
||||||
|
// strings for the year
|
||||||
|
struct Car {
|
||||||
|
std::string make;
|
||||||
|
std::string model;
|
||||||
|
int64_t year;
|
||||||
|
std::vector<float> tire_pressure;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
// This tag_invoke MUST be inside simdjson namespace
|
||||||
|
template <typename simdjson_value>
|
||||||
|
auto tag_invoke(deserialize_tag, simdjson_value &val, Car& car) {
|
||||||
|
ondemand::object obj;
|
||||||
|
auto error = val.get_object().get(obj);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["make"].get_string(car.make))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if ((error = obj["model"].get_string(car.model))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
std::string_view year_str;
|
||||||
|
if ((error = obj["year"].get(year_str))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
int64_t year_value;
|
||||||
|
auto [ptr, ec] = std::from_chars(year_str.data(), year_str.data() + year_str.size(), year_value);
|
||||||
|
if (ec != std::errc{}) {
|
||||||
|
return INCORRECT_TYPE;
|
||||||
|
}
|
||||||
|
car.year = year_value;
|
||||||
|
if ((error = obj["tire_pressure"].get<std::vector<float>>().get(
|
||||||
|
car.tire_pressure))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return simdjson::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename builder_type>
|
||||||
|
void tag_invoke(serialize_tag, builder_type &builder, const Car& car) {
|
||||||
|
builder.start_object();
|
||||||
|
builder.append_key_value("make", car.make);
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("model", car.model);
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("year", std::to_string(car.year));
|
||||||
|
builder.append_comma();
|
||||||
|
builder.append_key_value("tire_pressure", car.tire_pressure);
|
||||||
|
builder.end_object();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace simdjson
|
||||||
|
namespace custom_tests {
|
||||||
|
|
||||||
|
bool test_car_deserialization() {
|
||||||
|
TEST_START();
|
||||||
|
auto json = R"({"make":"Toyota","model":"Camry","year":"2018","tire_pressure":[30.5,30.6,30.7,30.8]})"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
auto doc_result = parser.iterate(json);
|
||||||
|
ASSERT_SUCCESS(doc_result);
|
||||||
|
Car car;
|
||||||
|
ASSERT_SUCCESS(doc_result.get(car));
|
||||||
|
if (car.make != "Toyota" || car.model != "Camry" || std::to_string(car.year) != "2018" || car.tire_pressure.size() != 4 || car.tire_pressure[0] != 30.5f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
bool test_car_serialization() {
|
||||||
|
TEST_START();
|
||||||
|
Car car{"Toyota", "Camry", 2018, {30.5f,30.6f,30.7f,30.8f}};
|
||||||
|
simdjson::builder::string_builder builder;
|
||||||
|
builder.append(car);
|
||||||
|
std::string_view json;
|
||||||
|
ASSERT_SUCCESS(builder.view().get(json));
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
bool test_car_roundtrip() {
|
||||||
|
TEST_START();
|
||||||
|
Car car{"Toyota", "Camry", 2018, {30.5f,30.6f,30.7f,30.8f}};
|
||||||
|
simdjson::builder::string_builder builder;
|
||||||
|
builder.append(car);
|
||||||
|
std::string json;
|
||||||
|
ASSERT_SUCCESS(builder.view().get(json));
|
||||||
|
ondemand::parser parser;
|
||||||
|
auto doc_result = parser.iterate(json);
|
||||||
|
ASSERT_SUCCESS(doc_result);
|
||||||
|
Car carback;
|
||||||
|
ASSERT_SUCCESS(doc_result.get(carback));
|
||||||
|
|
||||||
|
if (carback.make != car.make || carback.model != car.model || carback.year != car.year || carback.tire_pressure != car.tire_pressure) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test_car_roundtrip_to_json() {
|
||||||
|
TEST_START();
|
||||||
|
Car car{"Toyota", "Camry", 2018, {30.5f,30.6f,30.7f,30.8f}};
|
||||||
|
std::string json;
|
||||||
|
ASSERT_SUCCESS(simdjson::to_json(car).get(json));
|
||||||
|
simdjson::builder::string_builder builder;
|
||||||
|
ondemand::parser parser;
|
||||||
|
auto doc_result = parser.iterate(json);
|
||||||
|
ASSERT_SUCCESS(doc_result);
|
||||||
|
Car carback;
|
||||||
|
ASSERT_SUCCESS(doc_result.get(carback));
|
||||||
|
|
||||||
|
if (carback.make != car.make || carback.model != car.model || carback.year != car.year || carback.tire_pressure != car.tire_pressure) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
bool run() {
|
||||||
|
return test_car_deserialization() && test_car_serialization() && test_car_roundtrip() && test_car_roundtrip_to_json();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace builder_tests
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
return test_main(argc, argv, custom_tests::run);
|
||||||
|
}
|
||||||
@@ -123,7 +123,7 @@ endif()
|
|||||||
|
|
||||||
# Add the tests if we're on:
|
# Add the tests if we're on:
|
||||||
# 1. Visual Studio 2022 v17.6 or later
|
# 1. Visual Studio 2022 v17.6 or later
|
||||||
# 2. GCC v14.0.0 or later (GCC v13.0.0 cannot handle pipe oprator of lambda)
|
# 2. GCC v14.0.0 or later (GCC v13.0.0 cannot handle pipe operator of lambda)
|
||||||
# 3. Clang v15.0.0 or later (certain version C++ headers occur error when compiling)
|
# 3. Clang v15.0.0 or later (certain version C++ headers occur error when compiling)
|
||||||
if(
|
if(
|
||||||
(MSVC AND MSVC_VERSION LESS 1930) OR
|
(MSVC AND MSVC_VERSION LESS 1930) OR
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "simdjson/convert.h"
|
#include "simdjson/convert.h"
|
||||||
#include "test_ondemand.h"
|
#include "test_ondemand.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -21,6 +22,24 @@ private:
|
|||||||
std::string date_str;
|
std::string date_str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Meeting {
|
||||||
|
std::string title;
|
||||||
|
std::vector<std::string> attendees;
|
||||||
|
std::optional<std::string> location;
|
||||||
|
bool is_recurring;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct MeetingTime {
|
||||||
|
std::string title;
|
||||||
|
std::chrono::system_clock::time_point start_time;
|
||||||
|
std::vector<std::string> attendees;
|
||||||
|
std::optional<std::string> location;
|
||||||
|
bool is_recurring;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
template <typename simdjson_value>
|
template <typename simdjson_value>
|
||||||
auto tag_invoke(deserialize_tag, simdjson_value &val, MyDate& date) {
|
auto tag_invoke(deserialize_tag, simdjson_value &val, MyDate& date) {
|
||||||
@@ -43,7 +62,24 @@ struct complicated_weather_data {
|
|||||||
#ifdef __cpp_lib_ranges
|
#ifdef __cpp_lib_ranges
|
||||||
|
|
||||||
namespace convert_tests {
|
namespace convert_tests {
|
||||||
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_CONCEPTS
|
|
||||||
|
simdjson::padded_string json_car =
|
||||||
|
R"( {
|
||||||
|
"make": "Toyota",
|
||||||
|
"model": "Camry",
|
||||||
|
"year": 2018,
|
||||||
|
"tire_pressure": [ 40.1, 39.9 ]
|
||||||
|
} )"_padded;
|
||||||
|
simdjson::padded_string json_cars =
|
||||||
|
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||||
|
"tire_pressure": [ 40.1, 39.9 ] },
|
||||||
|
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||||
|
"tire_pressure": [ 30.1, 31.0 ] },
|
||||||
|
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||||
|
"tire_pressure": [ 29.8, 30.0 ] }
|
||||||
|
])"_padded;
|
||||||
|
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
struct Car {
|
struct Car {
|
||||||
std::string make{};
|
std::string make{};
|
||||||
std::string model{};
|
std::string model{};
|
||||||
@@ -95,21 +131,17 @@ static_assert(simdjson::custom_deserializable<std::unique_ptr<Car>>,
|
|||||||
"It should be deserializable");
|
"It should be deserializable");
|
||||||
|
|
||||||
|
|
||||||
simdjson::padded_string json_car =
|
bool simple_no_except() {
|
||||||
R"( {
|
TEST_START();
|
||||||
"make": "Toyota",
|
Car car;
|
||||||
"model": "Camry",
|
ASSERT_SUCCESS(simdjson::from(json_car).get(car));
|
||||||
"year": 2018,
|
if (car.make != "Toyota" || car.model != "Camry" || car.year != 2018) {
|
||||||
"tire_pressure": [ 40.1, 39.9 ]
|
return false;
|
||||||
} )"_padded;
|
}
|
||||||
simdjson::padded_string json_cars =
|
TEST_SUCCEED();
|
||||||
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
}
|
||||||
"tire_pressure": [ 40.1, 39.9 ] },
|
#endif // SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
"tire_pressure": [ 30.1, 31.0 ] },
|
|
||||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
|
||||||
"tire_pressure": [ 29.8, 30.0 ] }
|
|
||||||
])"_padded;
|
|
||||||
|
|
||||||
bool simple() {
|
bool simple() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
@@ -119,14 +151,42 @@ bool simple() {
|
|||||||
}
|
}
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
struct Player {
|
||||||
|
std::string username;
|
||||||
|
int level;
|
||||||
|
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 {
|
||||||
|
std::string username;
|
||||||
|
std::optional<int> level;
|
||||||
|
double health;
|
||||||
|
};
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
|
bool missing_key_player() {
|
||||||
|
TEST_START();
|
||||||
|
std::string json = R"({"username":"Alice","health":100.0})";
|
||||||
|
simdjson::padded_string padded(json);
|
||||||
|
Player p;
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
auto doc = parser.iterate(padded);
|
||||||
|
ASSERT_ERROR(doc.get(p), simdjson::NO_SUCH_FIELD);
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
bool missing_key_optional_player() {
|
||||||
|
TEST_START();
|
||||||
|
std::string json = R"({"username":"Alice","health":100.0})";
|
||||||
|
simdjson::padded_string padded(json);
|
||||||
|
OptionalPlayer p;
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
auto doc = parser.iterate(padded);
|
||||||
|
ASSERT_SUCCESS(doc.get(p));
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
bool bad_player() {
|
bool bad_player() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
// username is a string but we declared it as an int
|
// username is a string but we declared it as an int
|
||||||
@@ -160,6 +220,38 @@ bool simple() {
|
|||||||
ASSERT_SUCCESS(doc.get(p));
|
ASSERT_SUCCESS(doc.get(p));
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool meeting_test() {
|
||||||
|
TEST_START();
|
||||||
|
std::string json = simdjson::to_json(Meeting{
|
||||||
|
.title = "CppCon Planning",
|
||||||
|
.attendees = {"Alice", "Bob", "Charlie"},
|
||||||
|
.location = "Denver",
|
||||||
|
.is_recurring = true
|
||||||
|
});
|
||||||
|
Meeting m2 = simdjson::from(json);
|
||||||
|
std::cout << m2.title << std::endl;
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
bool meeting_time_test() {
|
||||||
|
TEST_START();
|
||||||
|
auto start_time = std::chrono::system_clock::now();
|
||||||
|
std::string json = simdjson::to_json(MeetingTime{
|
||||||
|
.title = "CppCon Planning",
|
||||||
|
.start_time = start_time,
|
||||||
|
.attendees = {"Alice", "Bob", "Charlie"},
|
||||||
|
.location = "Denver",
|
||||||
|
.is_recurring = true
|
||||||
|
});
|
||||||
|
std::cout << json << std::endl;
|
||||||
|
MeetingTime m2 = simdjson::from(json);
|
||||||
|
//ASSERT_EQUAL(m2.start_time, start_time);
|
||||||
|
std::cout << m2.title << std::endl;
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
bool broken() {
|
bool broken() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
@@ -415,7 +507,10 @@ bool test_to_vs_from_equivalence() {
|
|||||||
bool run() {
|
bool run() {
|
||||||
return
|
return
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION
|
||||||
bad_player() && good_player() && complicated_weather_test() &&
|
missing_key_optional_player() && missing_key_player() && meeting_time_test() && meeting_test() && bad_player() && good_player() && complicated_weather_test() &&
|
||||||
|
#endif
|
||||||
|
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
|
simple_no_except() &&
|
||||||
#endif
|
#endif
|
||||||
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_CONCEPTS
|
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_CONCEPTS
|
||||||
broken() && simple() && simple_optional() && with_parser() && to_array() &&
|
broken() && simple() && simple_optional() && with_parser() && to_array() &&
|
||||||
|
|||||||
Reference in New Issue
Block a user