Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 980f2ad3af | |||
| 7ad9fe63a6 | |||
| 7987418b1f | |||
| 5e871f6724 | |||
| 5d16fd5f31 | |||
| 4e9ff03af5 | |||
| aa7489060a | |||
| ae32422891 | |||
| 667d0ed3c7 | |||
| b1c31b428d | |||
| 56ac56ba32 | |||
| 19549c60ec | |||
| 16e99f229b | |||
| 21342a4142 | |||
| d0e841d3e9 | |||
| a962652ec3 | |||
| 77d73b068a | |||
| 19ff7a572d |
@@ -38,7 +38,7 @@ If we cannot reproduce the issue, then we cannot address it. Note that a stack t
|
||||
|
||||
It should be possible to trigger the bug by using solely simdjson with our default build setup. If you can only observe the bug within some specific context, with some other software, please reduce the issue first.
|
||||
|
||||
**simjson release**
|
||||
**simdjson release**
|
||||
|
||||
Unless you plan to contribute to simdjson, you should only work from releases. Please be mindful that our main branch may have additional features, bugs and documentation items.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 4.2.1
|
||||
VERSION 4.2.4
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "4.2.1"
|
||||
PROJECT_NUMBER = "4.2.4"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -183,6 +183,9 @@ auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json
|
||||
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
|
||||
```
|
||||
|
||||
(Windows users compiling with C++17 or better may use `wchar_t` strings to support non-ASCII
|
||||
filenames: `padded_string::load(L"twitter.json")`.)
|
||||
|
||||
If you prefer not to create your own `ondemand::parser` instance, you can access
|
||||
a thread-local version by calling `ondemand::parser.get_parser()`.
|
||||
|
||||
@@ -449,7 +452,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
When you are iterating through an object, you are advancing through its keys and values. You should not also access the object or other objects. E.g. within a loop over `myobject`, you should not be accessing `myobject`. The following is an anti-pattern: `for(auto value: myobject) {myobject["mykey"]}`.
|
||||
|
||||
You should never reset an object as you are iterating through it. The following is an anti-pattern: `for(auto value: myobject) {myobject.reset()}`.
|
||||
* **Array Index:** Because it is forward-only, you cannot look up an array element by index by index. Instead,
|
||||
* **Array Index:** Because it is forward-only, you cannot look up an array element by index. Instead,
|
||||
you should iterate through the array and keep an index yourself. Exceptionally, if need a single value
|
||||
out of the array, you may use an array access (e.g., `array[1]`). You should never reset an array as you are iterating through it. The following is an anti-pattern: `for(auto value: myarray) {myarray.reset()}`.
|
||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
||||
@@ -524,13 +527,13 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> auto silly_json = R"( { "test": "result" } )"_padded;
|
||||
> ondemand::document doc = parser.iterate(silly_json);
|
||||
> std::cout << simdjson::to_json_string(doc["test"]) << std::endl; // Requires simdjson 1.0 or better
|
||||
>````
|
||||
> ```
|
||||
> ```cpp
|
||||
> // retrieves an unescaped string value as a string_view instance
|
||||
> auto silly_json = R"( { "test": "result" } )"_padded;
|
||||
> ondemand::document doc = parser.iterate(silly_json);
|
||||
> std::cout << std::string_view(doc["test"]) << std::endl;
|
||||
>````
|
||||
> ```
|
||||
You can use `to_json_string` to efficiently extract components of a JSON document to reconstruct a new JSON document, as in the following example:
|
||||
> ```cpp
|
||||
> auto cars_json = R"( [
|
||||
@@ -559,7 +562,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> oss << "]";
|
||||
> auto json_string = oss.str();
|
||||
> // json_string == "[[ 40.1, 39.9, 37.7, 40.4 ],[ 30.1, 31.0, 28.6, 28.7 ]]"
|
||||
>````
|
||||
> ```
|
||||
* **Extracting Values (without exceptions):** You can use a variant usage of `get()` with error
|
||||
codes to avoid exceptions. You first declare the variable of the appropriate type (`double`,
|
||||
`uint64_t`, `int64_t`, `bool`, `ondemand::object` and `ondemand::array`) and pass it by reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Parse json at compile time
|
||||
* [Introduction](#introduction)
|
||||
* [Example](#example)
|
||||
* [Concepts](#concepts)
|
||||
* [Loading from disk](#loading-from-disk)
|
||||
* [Limitations (compile-time errors)](#limitations-compile-time-errors)
|
||||
|
||||
@@ -106,6 +107,68 @@ static_assert(arr.size() == 3);
|
||||
static_assert(arr[1] == 2);
|
||||
```
|
||||
|
||||
|
||||
## Concepts
|
||||
|
||||
Given that the parsed data is made of structures that depend on the JSON input, you might
|
||||
want to check that it conforms to your expectation. You can do so with concepts.
|
||||
|
||||
Let us consider this example:
|
||||
|
||||
```cpp
|
||||
constexpr auto config = R"(
|
||||
|
||||
[
|
||||
{ "name": "Alice", "age": 30 },
|
||||
{ "name": "Bob", "age": 25 },
|
||||
{ "name": "Charlie", "age": 35 }
|
||||
]
|
||||
|
||||
)"_json;
|
||||
```
|
||||
|
||||
You might want to ensure that the result is an array of persons. You can define your
|
||||
expection with concepts like so:
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
concept person = requires(T p) {
|
||||
std::string_view(p.name); // has name field convertible to string_view
|
||||
p.age; // has age field
|
||||
requires std::is_integral_v<decltype(p.age)>; // age is integral
|
||||
};
|
||||
|
||||
/**
|
||||
* Concept to validate that a type is an array of person objects
|
||||
*/
|
||||
template <typename T>
|
||||
concept array_of_person = requires(T arr) {
|
||||
arr.size(); // has size method
|
||||
arr[0]; // can access elements with []
|
||||
requires person<decltype(arr[0])>; // elements satisfy person concept
|
||||
};
|
||||
```
|
||||
|
||||
And then a simple static assert with `decltype` is sufficient to check that the expectation is met:
|
||||
|
||||
```cpp
|
||||
constexpr auto config = R"(
|
||||
|
||||
[
|
||||
{ "name": "Alice", "age": 30 },
|
||||
{ "name": "Bob", "age": 25 },
|
||||
{ "name": "Charlie", "age": 35 }
|
||||
]
|
||||
|
||||
)"_json;
|
||||
|
||||
|
||||
// Validate that the array satisfies the array_of_person concept
|
||||
static_assert(array_of_person<decltype(config)>);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Loading from disk
|
||||
|
||||
In practice, you may have a JSON file, say `json_data` that you want to parse
|
||||
|
||||
@@ -54,6 +54,22 @@ dom::parser parser;
|
||||
dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padded suffix creates a simdjson::padded_string instance
|
||||
```
|
||||
|
||||
You can also load a `padded_string` from a file.
|
||||
|
||||
|
||||
```cpp
|
||||
auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json'.
|
||||
dom::element doc = parser.parse(json);
|
||||
```
|
||||
|
||||
(Windows users compiling with C++17 or better may use `wchar_t` strings to support non-ASCII
|
||||
filenames: `padded_string::load(L"twitter.json")`.)
|
||||
|
||||
|
||||
(Windows users compiling with C++17 or better may use `wchar_t` strings to support non-ASCII
|
||||
filenames: `padded_string::load(L"twitter.json")`.)
|
||||
|
||||
|
||||
You can copy your data directly on a `simdjson::padded_string` as follows:
|
||||
|
||||
```cpp
|
||||
@@ -827,7 +843,7 @@ memcpy(padded_json_copy.get(), json, json_len);
|
||||
memset(padded_json_copy.get() + json_len, 0, SIMDJSON_PADDING);
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false);
|
||||
````
|
||||
```
|
||||
|
||||
Setting the `realloc_if_needed` parameter `false` in this manner may lead to better performance since copies are avoided, but it requires that the user takes more responsibilities: the simdjson library cannot verify that the input buffer was padded with SIMDJSON_PADDING extra bytes.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ library provides high-speed access to files or streams containing multiple small
|
||||
{"text":"a"}
|
||||
{"text":"b"}
|
||||
{"text":"c"}
|
||||
...
|
||||
"..."
|
||||
```
|
||||
... you want to read the entries (individual JSON documents) as quickly and as conveniently as possible. Importantly, the input might span several gigabytes, but you want to use a small (fixed) amount of memory. Ideally, you'd also like the parallelize the processing (using more than one core) to speed up the process.
|
||||
|
||||
@@ -403,4 +403,4 @@ Otherwise you may use this longer version for explicit handling of errors:
|
||||
}
|
||||
cars.push_back(c);
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -545,7 +545,7 @@ To help visualize the algorithm, we'll walk through the example C++ given at the
|
||||
"statuses": [
|
||||
{ "id": 1, "text": "first!", "user": { "screen_name": "lemire", "name": "Daniel" }, "retweet_count": 40 },
|
||||
{ "id": 2, "text": "second!", "user": { "screen_name": "jkeiser2", "name": "John" }, "retweet_count": 3 }
|
||||
^ (depth 3 - root > statuses > tweet)
|
||||
^ (depth 4 - root > statuses > tweet > field)
|
||||
],
|
||||
"search_metadata": { "count": 2 }
|
||||
}
|
||||
|
||||
@@ -8,16 +8,11 @@
|
||||
* Minifies by first parsing, then minifying.
|
||||
*/
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
|
||||
auto begin = as_chars(Data);
|
||||
auto end = begin + Size;
|
||||
|
||||
std::string str(begin, end);
|
||||
simdjson::padded_string str(reinterpret_cast<const char *>(Data), Size);
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element elem;
|
||||
auto error = parser.parse(str).get(elem);
|
||||
if (error) { return 0; }
|
||||
|
||||
std::string minified = simdjson::minify(elem);
|
||||
(void)minified;
|
||||
return 0;
|
||||
|
||||
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 226 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 256 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 258 KiB |
|
After Width: | Height: | Size: 136 KiB |
@@ -204,10 +204,7 @@ public:
|
||||
*
|
||||
* ### std::string references
|
||||
*
|
||||
* If you pass a mutable std::string reference (std::string&), the parser will seek to extend
|
||||
* its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
|
||||
*
|
||||
* Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
|
||||
* Whenever you pass an std::string reference, the parser may access the bytes beyond the end of
|
||||
* the string but before the end of the allocated memory (std::string::capacity()).
|
||||
* If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
|
||||
* container-overflow checks, you may encounter sanitizer warnings.
|
||||
@@ -239,7 +236,7 @@ public:
|
||||
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
|
||||
simdjson_inline simdjson_result<element> parse(const char *buf, size_t len, bool realloc_if_needed = true) & noexcept;
|
||||
simdjson_inline simdjson_result<element> parse(const char *buf, size_t len, bool realloc_if_needed = true) && =delete;
|
||||
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
|
||||
/** @overload parse(const std::string &) */
|
||||
simdjson_inline simdjson_result<element> parse(const std::string &s) & noexcept;
|
||||
simdjson_inline simdjson_result<element> parse(const std::string &s) && =delete;
|
||||
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
|
||||
|
||||
@@ -265,6 +265,8 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
}; // struct simdjson_result_base
|
||||
|
||||
} // namespace internal
|
||||
@@ -376,6 +378,8 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
}; // struct simdjson_result
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
@@ -138,6 +138,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
|
||||
@@ -403,7 +403,9 @@ public:
|
||||
simdjson_inline simdjson_result<array_iterator> end() & noexcept;
|
||||
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
* Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that
|
||||
* fields must be accessed in the order they appear in the JSON text (although you can
|
||||
* skip fields). See find_field_unordered() and operator[] for an order-insensitive version.
|
||||
*
|
||||
* The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
|
||||
* JSON `{ "x": 1, "y": 2, "z": 3 }`:
|
||||
@@ -447,7 +449,8 @@ public:
|
||||
* missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
|
||||
* in question is large. The fact that the extra code is there also bumps the executable size.
|
||||
*
|
||||
* It is the default, however, because it would be highly surprising (and hard to debug) if the
|
||||
* We default operator[] on find_field_unordered() for convenience.
|
||||
* It is the default because it would be highly surprising (and hard to debug) if the
|
||||
* default behavior failed to look up a field just because it was in the wrong order--and many
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
|
||||
@@ -519,8 +519,8 @@ simdjson_inline void string_builder::append(const T &opt) {
|
||||
|
||||
template <typename T>
|
||||
requires(require_custom_serialization<T>)
|
||||
simdjson_inline void string_builder::append(const T &val) {
|
||||
serialize(*this, val);
|
||||
simdjson_inline void string_builder::append(T &&val) {
|
||||
serialize(*this, std::forward<T>(val));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -534,11 +534,11 @@ simdjson_inline void string_builder::append(const T &value) {
|
||||
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
||||
// Support for range-based appending (std::ranges::view, etc.)
|
||||
template <std::ranges::range R>
|
||||
requires(!std::is_convertible<R, std::string_view>::value)
|
||||
requires(!std::is_convertible<R, std::string_view>::value && !require_custom_serialization<R>)
|
||||
simdjson_inline void string_builder::append(const R &range) noexcept {
|
||||
auto it = std::ranges::begin(range);
|
||||
auto end = std::ranges::end(range);
|
||||
if constexpr (concepts::is_pair<typename R::value_type>) {
|
||||
if constexpr (concepts::is_pair<std::ranges::range_value_t<R>>) {
|
||||
start_object();
|
||||
|
||||
if (it == end) {
|
||||
|
||||
@@ -24,9 +24,8 @@ 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);
|
||||
constexpr void operator()(SIMDJSON_IMPLEMENTATION::builder::string_builder& b, T&& obj) const{
|
||||
return tag_invoke(*this, b, std::forward<T>(obj));
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +164,7 @@ public:
|
||||
|
||||
template <typename T>
|
||||
requires(require_custom_serialization<T>)
|
||||
simdjson_inline void append(const T &val);
|
||||
simdjson_inline void append(T &&val);
|
||||
|
||||
// Support for string-like types
|
||||
template <typename T>
|
||||
@@ -176,7 +175,7 @@ public:
|
||||
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
||||
// Support for range-based appending (std::ranges::view, etc.)
|
||||
template <std::ranges::range R>
|
||||
requires (!std::is_convertible<R, std::string_view>::value)
|
||||
requires (!std::is_convertible<R, std::string_view>::value && !require_custom_serialization<R>)
|
||||
simdjson_inline void append(const R &range) noexcept;
|
||||
#endif
|
||||
/**
|
||||
@@ -301,4 +300,4 @@ simdjson_warn_unused simdjson_error to_json(const Z &z, std::string &s, size_t i
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_STRING_BUILDER_H
|
||||
#endif // SIMDJSON_GENERIC_STRING_BUILDER_H
|
||||
|
||||
@@ -30,7 +30,9 @@ public:
|
||||
simdjson_inline simdjson_result<object_iterator> begin() noexcept;
|
||||
simdjson_inline simdjson_result<object_iterator> end() noexcept;
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
* Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that
|
||||
* fields must be accessed in the order they appear in the JSON text (although you can
|
||||
* skip fields). See find_field_unordered() and operator[] for an order-insensitive version.
|
||||
*
|
||||
* The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
|
||||
* JSON `{ "x": 1, "y": 2, "z": 3 }`:
|
||||
@@ -78,7 +80,8 @@ public:
|
||||
* missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
|
||||
* in question is large. The fact that the extra code is there also bumps the executable size.
|
||||
*
|
||||
* It is the default, however, because it would be highly surprising (and hard to debug) if the
|
||||
* We default operator[] on find_field_unordered() for convenience.
|
||||
* It is the default because it would be highly surprising (and hard to debug) if the
|
||||
* default behavior failed to look up a field just because it was in the wrong order--and many
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
|
||||
@@ -395,7 +395,9 @@ public:
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> at(size_t index) noexcept;
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
* Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that
|
||||
* fields must be accessed in the order they appear in the JSON text (although you can
|
||||
* skip fields). See find_field_unordered() and operator[] for an order-insensitive version.
|
||||
*
|
||||
* The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
|
||||
* JSON `{ "x": 1, "y": 2, "z": 3 }`:
|
||||
@@ -429,7 +431,8 @@ public:
|
||||
* missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
|
||||
* in question is large. The fact that the extra code is there also bumps the executable size.
|
||||
*
|
||||
* It is the default, however, because it would be highly surprising (and hard to debug) if the
|
||||
* We default operator[] on find_field_unordered() for convenience.
|
||||
* It is the default because it would be highly surprising (and hard to debug) if the
|
||||
* default behavior failed to look up a field just because it was in the wrong order--and many
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
@@ -776,7 +779,9 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
|
||||
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
* Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that
|
||||
* fields must be accessed in the order they appear in the JSON text (although you can
|
||||
* skip fields). See find_field_unordered() and operator[] for an order-insensitive version.
|
||||
*
|
||||
* The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
|
||||
* JSON `{ "x": 1, "y": 2, "z": 3 }`:
|
||||
@@ -808,7 +813,8 @@ public:
|
||||
* missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
|
||||
* in question is large. The fact that the extra code is there also bumps the executable size.
|
||||
*
|
||||
* It is the default, however, because it would be highly surprising (and hard to debug) if the
|
||||
* We default operator[] on find_field_unordered() for convenience.
|
||||
* It is the defaul because it would be highly surprising (and hard to debug) if the
|
||||
* default behavior failed to look up a field just because it was in the wrong order--and many
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "simdjson/padded_string_view-inl.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cwchar>
|
||||
|
||||
namespace simdjson {
|
||||
namespace internal {
|
||||
@@ -185,6 +186,62 @@ inline simdjson_result<padded_string> padded_string::load(std::string_view filen
|
||||
return s;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && SIMDJSON_CPLUSPLUS17
|
||||
inline simdjson_result<padded_string> padded_string::load(std::wstring_view filename) noexcept {
|
||||
// Open the file using the wide characters
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
||||
std::FILE *fp = _wfopen(filename.data(), L"rb");
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
if (fp == nullptr) {
|
||||
return IO_ERROR;
|
||||
}
|
||||
|
||||
// Get the file size
|
||||
int ret;
|
||||
#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
|
||||
ret = _fseeki64(fp, 0, SEEK_END);
|
||||
#else
|
||||
ret = std::fseek(fp, 0, SEEK_END);
|
||||
#endif // _WIN64
|
||||
if(ret < 0) {
|
||||
std::fclose(fp);
|
||||
return IO_ERROR;
|
||||
}
|
||||
#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
|
||||
__int64 llen = _ftelli64(fp);
|
||||
if(llen == -1L) {
|
||||
std::fclose(fp);
|
||||
return IO_ERROR;
|
||||
}
|
||||
#else
|
||||
long llen = std::ftell(fp);
|
||||
if((llen < 0) || (llen == LONG_MAX)) {
|
||||
std::fclose(fp);
|
||||
return IO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Allocate the padded_string
|
||||
size_t len = static_cast<size_t>(llen);
|
||||
padded_string s(len);
|
||||
if (s.data() == nullptr) {
|
||||
std::fclose(fp);
|
||||
return MEMALLOC;
|
||||
}
|
||||
|
||||
// Read the padded_string
|
||||
std::rewind(fp);
|
||||
size_t bytes_read = std::fread(s.data(), 1, len, fp);
|
||||
if (std::fclose(fp) != 0 || bytes_read != len) {
|
||||
return IO_ERROR;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
inline simdjson::padded_string operator ""_padded(const char *str, size_t len) {
|
||||
|
||||
@@ -127,6 +127,19 @@ struct padded_string final {
|
||||
**/
|
||||
inline static simdjson_result<padded_string> load(std::string_view path) noexcept;
|
||||
|
||||
#if defined(_WIN32) && SIMDJSON_CPLUSPLUS17
|
||||
/**
|
||||
* This function accepts a wide string path (UTF-16) and converts it to
|
||||
* UTF-8 before loading the file. This allows windows users to work
|
||||
* with unicode file paths without manually converting the paths everytime.
|
||||
*
|
||||
* @return IO_ERROR on error, including conversion failures.
|
||||
*
|
||||
* @param path the path to the file as a wide string.
|
||||
**/
|
||||
inline static simdjson_result<padded_string> load(std::wstring_view path) noexcept;
|
||||
#endif
|
||||
|
||||
private:
|
||||
padded_string &operator=(const padded_string &o) = delete;
|
||||
padded_string(const padded_string &o) = delete;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION "4.2.1"
|
||||
#define SIMDJSON_VERSION "4.2.4"
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
@@ -19,7 +19,7 @@ enum {
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 1
|
||||
SIMDJSON_VERSION_REVISION = 4
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2025-11-03 11:03:21 -0500. version 4.2.1 Do not edit! */
|
||||
/* auto-generated on 2025-12-17 20:32:36 -0500. version 4.2.4 Do not edit! */
|
||||
/* including simdjson.cpp: */
|
||||
/* begin file simdjson.cpp */
|
||||
#define SIMDJSON_SRC_SIMDJSON_CPP
|
||||
@@ -2752,6 +2752,8 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
}; // struct simdjson_result_base
|
||||
|
||||
} // namespace internal
|
||||
@@ -2863,6 +2865,8 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
}; // struct simdjson_result
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
@@ -4043,20 +4047,14 @@ void grisu2(char *buf, int &len, int &decimal_exponent, FloatType value) {
|
||||
*/
|
||||
inline char *append_exponent(char *buf, int e) {
|
||||
|
||||
if (e < 0) {
|
||||
e = -e;
|
||||
*buf++ = '-';
|
||||
} else {
|
||||
*buf++ = '+';
|
||||
}
|
||||
bool isNegative = e < 0;
|
||||
e = isNegative ? -e : e;
|
||||
*buf++ = isNegative ? '-' : '+';
|
||||
|
||||
auto k = static_cast<std::uint32_t>(e);
|
||||
if (k < 10) {
|
||||
if (k < 100) {
|
||||
// Always print at least two digits in the exponent.
|
||||
// This is for compatibility with printf("%g").
|
||||
*buf++ = '0';
|
||||
*buf++ = static_cast<char>('0' + k);
|
||||
} else if (k < 100) {
|
||||
*buf++ = static_cast<char>('0' + k / 10);
|
||||
k %= 10;
|
||||
*buf++ = static_cast<char>('0' + k);
|
||||
@@ -10105,6 +10103,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
@@ -16600,6 +16601,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
@@ -22950,6 +22954,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
@@ -29457,6 +29464,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
@@ -36323,6 +36333,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
@@ -43011,6 +43024,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
@@ -49145,6 +49161,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
@@ -54871,6 +54890,9 @@ struct implementation_simdjson_result_base {
|
||||
*/
|
||||
simdjson_inline T&& value_unsafe() && noexcept;
|
||||
|
||||
using value_type = T;
|
||||
using error_type = error_code;
|
||||
|
||||
protected:
|
||||
/** users should never directly access first and second. **/
|
||||
T first{}; /** Users should never directly access 'first'. **/
|
||||
|
||||
@@ -814,20 +814,14 @@ void grisu2(char *buf, int &len, int &decimal_exponent, FloatType value) {
|
||||
*/
|
||||
inline char *append_exponent(char *buf, int e) {
|
||||
|
||||
if (e < 0) {
|
||||
e = -e;
|
||||
*buf++ = '-';
|
||||
} else {
|
||||
*buf++ = '+';
|
||||
}
|
||||
bool isNegative = e < 0;
|
||||
e = isNegative ? -e : e;
|
||||
*buf++ = isNegative ? '-' : '+';
|
||||
|
||||
auto k = static_cast<std::uint32_t>(e);
|
||||
if (k < 10) {
|
||||
if (k < 100) {
|
||||
// Always print at least two digits in the exponent.
|
||||
// This is for compatibility with printf("%g").
|
||||
*buf++ = '0';
|
||||
*buf++ = static_cast<char>('0' + k);
|
||||
} else if (k < 100) {
|
||||
*buf++ = static_cast<char>('0' + k / 10);
|
||||
k %= 10;
|
||||
*buf++ = static_cast<char>('0' + k);
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#if SIMDJSON_SUPPORTS_RANGES
|
||||
#include <ranges>
|
||||
#endif
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct Car {
|
||||
@@ -13,6 +17,33 @@ struct Car {
|
||||
std::vector<double> tire_pressure;
|
||||
}; // Car
|
||||
|
||||
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
struct Car2549 {
|
||||
std::string make;
|
||||
std::string model;
|
||||
int64_t year;
|
||||
std::vector<float> tire_pressure;
|
||||
};
|
||||
namespace simdjson {
|
||||
// we intentionally pass by non-const reference to car.
|
||||
template <typename builder_type>
|
||||
void tag_invoke(serialize_tag, builder_type& builder, Car2549& 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
|
||||
|
||||
static_assert(simdjson::require_custom_serialization<Car2549>);
|
||||
#endif
|
||||
|
||||
namespace builder_tests {
|
||||
using namespace std;
|
||||
|
||||
@@ -424,6 +455,21 @@ bool car_test() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
|
||||
bool issue2549() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
Car2549 c = { "Toyota", "Corolla", 2017, {1.0f,2.0f,3.0f} };
|
||||
sb.start_object();
|
||||
sb.append_key_value("car", c);
|
||||
sb.end_object();
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_SUCCESS(result);
|
||||
ASSERT_EQUAL(p, "{\"car\":{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,\"tire_pressure\":[1.0,2.0,3.0]}}");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool car_test_template() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
@@ -517,6 +563,24 @@ bool map_test() {
|
||||
ASSERT_EQUAL(s, "{\"key1\":1.0,\"key2\":1.0}");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool ranges_test() {
|
||||
TEST_START();
|
||||
struct Foo {
|
||||
int a;
|
||||
float b;
|
||||
};
|
||||
std::vector<Foo> c = {{1, 2.0f}, {3, 4.0f}, {5, 6.0f}, {7, 8.0f}};
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append(c | std::views::transform(&Foo::b));
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_SUCCESS(result);
|
||||
ASSERT_EQUAL(p, "[2.0,4.0,6.0,8.0]");
|
||||
std::string s;
|
||||
ASSERT_SUCCESS(simdjson::to_json(c | std::views::transform(&Foo::b)).get(s));
|
||||
ASSERT_EQUAL(s, "[2.0,4.0,6.0,8.0]");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool double_double_test() {
|
||||
TEST_START();
|
||||
std::vector<std::vector<double>> c = {{1.0, 2.0}, {3.0, 4.0}};
|
||||
@@ -586,14 +650,15 @@ bool run() {
|
||||
car_test_exception() && string_convertion_except() &&
|
||||
#endif
|
||||
#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
|
||||
map_test() && double_double_test() && double_double_test_to_string() &&
|
||||
car_test_simple() && car_test_simple_complete() &&
|
||||
map_test() && ranges_test() && double_double_test() &&
|
||||
double_double_test_to_string() && car_test_simple() &&
|
||||
car_test_simple_complete() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
car_test_simple_complete_exceptions() &&
|
||||
#endif
|
||||
#endif
|
||||
#if SIMDJSON_SUPPORTS_CONCEPTS
|
||||
car_test_template() && serialize_optional() &&
|
||||
issue2549() && car_test_template() && serialize_optional() &&
|
||||
#endif
|
||||
append_char() && append_integer() && append_float() && append_null() &&
|
||||
clear() && escape_and_append() && escape_and_append_with_quotes() &&
|
||||
|
||||
@@ -87,16 +87,16 @@ bool cast_tester<T>::test_get_error(simdjson_result<element> element, error_code
|
||||
|
||||
template<typename T>
|
||||
bool cast_tester<T>::test_get_t(element element, T expected) {
|
||||
auto actual = element.get<T>();
|
||||
ASSERT_SUCCESS(actual.error());
|
||||
return assert_equal(actual.value_unsafe(), expected);
|
||||
T value;
|
||||
ASSERT_SUCCESS(element.get<T>().get(value));
|
||||
return assert_equal(value, expected);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool cast_tester<T>::test_get_t(simdjson_result<element> element, T expected) {
|
||||
auto actual = element.get<T>();
|
||||
ASSERT_SUCCESS(actual.error());
|
||||
return assert_equal(actual.value_unsafe(), expected);
|
||||
T value;
|
||||
ASSERT_SUCCESS(element.get<T>().get(value));
|
||||
return assert_equal(value, expected);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -597,6 +597,101 @@ bool test_top_level_array_example() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
/**
|
||||
* Concept to validate that a type represents a person with name and age
|
||||
*/
|
||||
template <typename T>
|
||||
concept person = requires(T p) {
|
||||
std::string_view(p.name); // has name field convertible to string_view
|
||||
p.age; // has age field
|
||||
requires std::is_integral_v<decltype(p.age)>; // age is integral
|
||||
};
|
||||
|
||||
/**
|
||||
* Concept to validate that a type is an array of person objects
|
||||
*/
|
||||
template <typename T>
|
||||
concept array_of_person = requires(T arr) {
|
||||
arr.size(); // has size method
|
||||
arr[0]; // can access elements with []
|
||||
requires person<decltype(arr[0])>; // elements satisfy person concept
|
||||
};
|
||||
|
||||
/**
|
||||
* Test: Array of objects with concept validation
|
||||
*/
|
||||
bool test_array_of_objects_with_concept() {
|
||||
TEST_START();
|
||||
|
||||
constexpr auto config = R"(
|
||||
|
||||
[
|
||||
{ "name": "Alice", "age": 30 },
|
||||
{ "name": "Bob", "age": 25 },
|
||||
{ "name": "Charlie", "age": 35 }
|
||||
]
|
||||
|
||||
)"_json;
|
||||
|
||||
std::print("Array size: {}\n", config.size());
|
||||
|
||||
static_assert(config.size() == 3);
|
||||
|
||||
// Validate that the array satisfies the array_of_person concept
|
||||
static_assert(array_of_person<decltype(config)>);
|
||||
|
||||
|
||||
// Test the actual values
|
||||
static_assert(std::string_view(config[0].name) == "Alice");
|
||||
static_assert(config[0].age == 30);
|
||||
static_assert(std::string_view(config[1].name) == "Bob");
|
||||
static_assert(config[1].age == 25);
|
||||
static_assert(std::string_view(config[2].name) == "Charlie");
|
||||
static_assert(config[2].age == 35);
|
||||
|
||||
// Runtime assertions
|
||||
ASSERT_EQUAL(config.size(), 3);
|
||||
ASSERT_EQUAL(std::string_view(config[0].name), "Alice"sv);
|
||||
ASSERT_EQUAL(config[0].age, 30);
|
||||
ASSERT_EQUAL(std::string_view(config[1].name), "Bob"sv);
|
||||
ASSERT_EQUAL(config[1].age, 25);
|
||||
ASSERT_EQUAL(std::string_view(config[2].name), "Charlie"sv);
|
||||
ASSERT_EQUAL(config[2].age, 35);
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#if defined(__cpp_pp_embed) && __cpp_pp_embed >= 202502L
|
||||
#define TEST_EMBED_SUPPORTED
|
||||
/**
|
||||
* Test: #embed support for external JSON files (C++26)
|
||||
*/
|
||||
bool test_embed_twitter_json() {
|
||||
TEST_START();
|
||||
|
||||
// C++26 #embed allows embedding files directly into the binary at compile time
|
||||
// This creates a const char array with the file contents plus null terminator
|
||||
constexpr const char twitter_json[] = {
|
||||
#embed TWITTER_JSON
|
||||
, 0
|
||||
};
|
||||
|
||||
// Parse the embedded JSON at compile time
|
||||
constexpr auto parsed_twitter = simdjson::compile_time::parse_json<twitter_json>();
|
||||
|
||||
// Verify the structure - twitter.json should have a "statuses" array
|
||||
static_assert(parsed_twitter.statuses.size() > 0);
|
||||
|
||||
// Runtime verification
|
||||
ASSERT_TRUE(parsed_twitter.statuses.size() > 0);
|
||||
|
||||
std::cout << "Successfully parsed embedded twitter.json with "
|
||||
<< parsed_twitter.statuses.size() << " statuses" << std::endl;
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif // defined(__cpp_pp_embed) && __cpp_pp_embed >= 202502L
|
||||
|
||||
bool run() {
|
||||
return test_basic_object() &&
|
||||
test_nested_objects() &&
|
||||
@@ -620,7 +715,12 @@ bool run() {
|
||||
array_of_objects() &&
|
||||
test_user_config_example() &&
|
||||
test_nested_servers_example() &&
|
||||
test_top_level_array_example();
|
||||
test_top_level_array_example() &&
|
||||
test_array_of_objects_with_concept()
|
||||
#ifdef TEST_EMBED_SUPPORTED
|
||||
&& test_embed_twitter_json()
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
} // namespace compile_time_json_tests
|
||||
|
||||
@@ -1951,18 +1951,39 @@ namespace minify_tests {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool test_empty() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
const std::string_view test = "";
|
||||
const std::string_view minified = "";
|
||||
return check_minification(test.data(), test.size(), minified.data(), minified.size());
|
||||
}
|
||||
|
||||
bool test_two_quotes() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
const std::string_view test = R"("")";
|
||||
const std::string_view minified = R"("")";
|
||||
return check_minification(test.data(), test.size(), minified.data(), minified.size());
|
||||
}
|
||||
|
||||
bool test_number() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
const std::string_view test = R"(3.41)";
|
||||
const std::string_view minified = R"(3.41)";
|
||||
return check_minification(test.data(), test.size(), minified.data(), minified.size());
|
||||
}
|
||||
|
||||
bool test_minify() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
const std::string test = R"({ "foo" : 1, "bar" : [ 1, 2, 0.11111111111111113 ], "baz": { "a": 3.1415926535897936, "b": 2, "c": 3.141592653589794 } })";
|
||||
const std::string minified(R"({"foo":1,"bar":[1,2,0.11111111111111113],"baz":{"a":3.1415926535897936,"b":2,"c":3.141592653589794}})");
|
||||
return check_minification(test.c_str(), test.size(), minified.c_str(), minified.size());
|
||||
const std::string_view test = R"({ "foo" : 1, "bar" : [ 1, 2, 0.11111111111111113 ], "baz": { "a": 3.1415926535897936, "b": 2, "c": 3.141592653589794 } })";
|
||||
const std::string_view minified = R"({"foo":1,"bar":[1,2,0.11111111111111113],"baz":{"a":3.1415926535897936,"b":2,"c":3.141592653589794}})";
|
||||
return check_minification(test.data(), test.size(), minified.data(), minified.size());
|
||||
}
|
||||
|
||||
bool test_minify_array() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
std::string test("[ 1, 2, 3]");
|
||||
std::string minified("[1,2,3]");
|
||||
return check_minification(test.c_str(), test.size(), minified.c_str(), minified.size());
|
||||
std::string_view test("[ 1, 2, 3]");
|
||||
std::string_view minified("[1,2,3]");
|
||||
return check_minification(test.data(), test.size(), minified.data(), minified.size());
|
||||
}
|
||||
|
||||
bool test_minify_object() {
|
||||
@@ -1972,7 +1993,10 @@ namespace minify_tests {
|
||||
return check_minification(test.c_str(), test.size(), minified.c_str(), minified.size());
|
||||
}
|
||||
bool run() {
|
||||
return test_various_lengths2() &&
|
||||
return test_two_quotes() &&
|
||||
test_empty() &&
|
||||
test_number() &&
|
||||
test_various_lengths2() &&
|
||||
test_various_lengths() &&
|
||||
test_single_quote() &&
|
||||
test_minify() &&
|
||||
@@ -2194,6 +2218,22 @@ namespace format_tests {
|
||||
s << minify(object);
|
||||
return assert_minified(s, R"({"a":3.1415926535897936,"b":2,"c":3.141592653589794})");
|
||||
}
|
||||
bool print_minify_empty_string() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
dom::parser parser;
|
||||
dom::element e = parser.parse(R"("")"_padded);
|
||||
ostringstream s;
|
||||
s << minify(e);
|
||||
return assert_minified(s, R"("")");
|
||||
}
|
||||
bool print_minify_number_string() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
dom::parser parser;
|
||||
dom::element e = parser.parse("3.41"_padded);
|
||||
ostringstream s;
|
||||
s << minify(e);
|
||||
return assert_minified(s, "3.41");
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool run() {
|
||||
@@ -2209,6 +2249,7 @@ namespace format_tests {
|
||||
print_element_exception() && print_minify_element_exception() &&
|
||||
print_array_exception() && print_minify_array_exception() &&
|
||||
print_object_exception() && print_minify_object_exception() &&
|
||||
print_minify_empty_string() && print_minify_number_string() &&
|
||||
#endif
|
||||
true;
|
||||
}
|
||||
|
||||