mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b71acf803 | |||
| 325db34d41 | |||
| 85cadf4074 | |||
| bc48e72070 |
@@ -52,6 +52,20 @@ if(SIMDJSON_DISABLE_DEPRECATED_API)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(SIMDJSON_FEATURE_ONDEMAND_API "Enable ondemand API" ON)
|
||||||
|
option(SIMDJSON_FEATURE_DOM_API "Enable DOM API" ON)
|
||||||
|
option(SIMDJSON_FEATURE_BUILDER_API "Enable builder API" ON)
|
||||||
|
|
||||||
|
if(NOT SIMDJSON_FEATURE_ONDEMAND_API)
|
||||||
|
add_compile_definitions(SIMDJSON_FEATURE_ONDEMAND_API=0)
|
||||||
|
endif()
|
||||||
|
if(NOT SIMDJSON_FEATURE_DOM_API)
|
||||||
|
add_compile_definitions(SIMDJSON_FEATURE_DOM_API=0)
|
||||||
|
endif()
|
||||||
|
if(NOT SIMDJSON_FEATURE_BUILDER_API)
|
||||||
|
add_compile_definitions(SIMDJSON_FEATURE_BUILDER_API=0)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25.0")
|
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25.0")
|
||||||
option(SIMDJSON_STATIC_REFLECTION "Enables static reflection (experimental), requires C++26" OFF)
|
option(SIMDJSON_STATIC_REFLECTION "Enables static reflection (experimental), requires C++26" OFF)
|
||||||
else()
|
else()
|
||||||
|
|||||||
+18
@@ -32,6 +32,24 @@ It is similar for Visual Studio users, please see the CMake or Visual Studio doc
|
|||||||
|
|
||||||
By default the library is built in Release mode.
|
By default the library is built in Release mode.
|
||||||
|
|
||||||
|
## Optional APIs (Feature Flags)
|
||||||
|
|
||||||
|
simdjson provides three APIs:
|
||||||
|
- DOM (`simdjson::dom`)
|
||||||
|
- OnDemand (`simdjson::ondemand`)
|
||||||
|
- Builder (`simdjson::builder`) — requires DOM
|
||||||
|
|
||||||
|
You can enable or disable these APIs at compile time to reduce binary size and compile time.
|
||||||
|
At least one of DOM or OnDemand must be enabled.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Using CMake:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -DSIMDJSON_FEATURE_DOM_API=OFF \
|
||||||
|
-DSIMDJSON_FEATURE_ONDEMAND_API=ON \
|
||||||
|
-DSIMDJSON_FEATURE_BUILDER_API=OFF ..
|
||||||
|
|
||||||
Assertions and development checks
|
Assertions and development checks
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|||||||
+90
-70
@@ -161,54 +161,77 @@ The basics: loading and parsing JSON documents
|
|||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
The simdjson library allows you to navigate and validate JSON documents ([RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html)).
|
The simdjson library allows you to navigate and validate JSON documents ([RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html)).
|
||||||
As required by the standard, your JSON document should be in a Unicode (UTF-8) string. The whole
|
Your JSON document should be a valid Unicode (UTF-8) string.
|
||||||
string, from the beginning to the end, needs to be valid: we do not attempt to tolerate bad
|
|
||||||
inputs before or after a document.
|
|
||||||
|
|
||||||
For efficiency reasons, simdjson requires a string with a few bytes (`simdjson::SIMDJSON_PADDING`)
|
To parse JSON, create a `ondemand::parser` and call its `iterate()` method on a padded input.
|
||||||
at the end, these bytes may be read but their content does not affect the parsing. In practice,
|
The simplest way to load a JSON file is with `padded_string::load`:
|
||||||
it means that the JSON inputs should be stored in a memory region with `simdjson::SIMDJSON_PADDING`
|
|
||||||
extra bytes at the end. You do not have to set these bytes to specific values though you may
|
|
||||||
want to if you want to avoid runtime warnings with some sanitizers. We expect the user
|
|
||||||
of the library to load the data (from disk or from the network) into a padded buffer. To make
|
|
||||||
this easy, we provide the `padded_string::load` function which loads files from disk in a padded buffer.
|
|
||||||
[You can similarly fetch a file from a URL to a padded string](https://github.com/simdjson/curltostring) using our `simdjson::padded_string_builder`. Advanced users may want to read the section Free Padding in [our performance notes](performance.md).
|
|
||||||
|
|
||||||
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can
|
|
||||||
access by creating a `ondemand::parser` and calling the `iterate()` method. The iterate method
|
|
||||||
quickly indexes the input string and may detect some errors. The following example illustrates
|
|
||||||
how to get started with an input JSON file (`"twitter.json"`):
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json'.
|
auto json = padded_string::load("twitter.json");
|
||||||
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
|
ondemand::document doc = parser.iterate(json);
|
||||||
```
|
```
|
||||||
|
|
||||||
(Windows users compiling with C++17 or better may use `wchar_t` strings to support non-ASCII
|
For inline JSON strings, use the `_padded` suffix:
|
||||||
filenames: `padded_string::load(L"twitter.json")`.)
|
|
||||||
|
|
||||||
If you prefer not to create your own `ondemand::parser` instance, you can access
|
```cpp
|
||||||
a thread-local version by calling `ondemand::parser.get_parser()`.
|
ondemand::parser parser;
|
||||||
|
auto json = "[1,2,3]"_padded;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are compiling with C++17 or better, you can use `simdjson::padded_input`
|
||||||
|
which accepts any string-like input and handles padding automatically:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
ondemand::parser parser;
|
||||||
|
std::string_view json = "[1,2,3]";
|
||||||
|
simdjson::padded_input input(json);
|
||||||
|
ondemand::document doc = parser.iterate(input);
|
||||||
|
|
||||||
|
// Also works with std::string, considering reserved capacity
|
||||||
|
std::string json_str = "[1,2,3]";
|
||||||
|
json_str.reserve(100); // Reserve extra space
|
||||||
|
simdjson::padded_input input2(json_str); // May avoid copying
|
||||||
|
ondemand::document doc2 = parser.iterate(input2);
|
||||||
|
```
|
||||||
|
|
||||||
|
The simdjson library also accepts `std::string` instances directly---if the provided
|
||||||
|
reference is non-const, it will allocate padding as needed:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
ondemand::parser parser;
|
||||||
|
std::string json = "[1,2,3]";
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error handling](#error-handling) for details.
|
||||||
|
|
||||||
|
|
||||||
|
### Advanced input options
|
||||||
|
|
||||||
|
This section covers additional ways to provide JSON input to simdjson, including
|
||||||
|
options for fine-grained control over padding and memory.
|
||||||
|
|
||||||
|
**Thread-local parser.** If you prefer not to create your own `ondemand::parser` instance, you can access
|
||||||
|
a thread-local version by calling `ondemand::parser.get_parser()`:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
ondemand::document doc = ondemand::parser.get_parser().iterate(json);
|
ondemand::document doc = ondemand::parser.get_parser().iterate(json);
|
||||||
```
|
```
|
||||||
|
|
||||||
However, you should be careful because a parser instance can only be used for one
|
A parser instance can only be used for one document at a time, so
|
||||||
document at a time, thus it is only applicable when you are only parsing one
|
the thread-local parser is only applicable when you parse one
|
||||||
document per thread at any one time.
|
document per thread at any one time.
|
||||||
|
|
||||||
You can also create a padded string---and call `iterate()`:
|
**`padded_input` details (C++17+).** The actual padding only occurs when the JSON string ends near the boundary of a memory page, which is
|
||||||
|
uncommon. Using a `simdjson::padded_input` is safe although sanitizers and tools like valgrind
|
||||||
|
might report illegal reads (which are safe in our case because they remain in the mapped page). You should avoid `simdjson::padded_input`
|
||||||
|
on systems without a page size of at least 4096: virtually all systems qualify except for
|
||||||
|
some niche embedded systems running custom operating systems. Standard Linux, Windows, macOS, Android, iOS, etc., are all fine. Note that, most times, a `simdjson::padded_input` instance will not copy the data and will only act
|
||||||
|
as a view (it does not own the memory).
|
||||||
|
|
||||||
```cpp
|
**User-managed buffers.** If you have a buffer of your own with enough padding already (`SIMDJSON_PADDING` extra bytes allocated), you can use `padded_string_view` to pass it in:
|
||||||
ondemand::parser parser;
|
|
||||||
auto json = "[1,2,3]"_padded; // The _padded suffix creates a simdjson::padded_string instance
|
|
||||||
ondemand::document doc = parser.iterate(json); // parse a string
|
|
||||||
```
|
|
||||||
|
|
||||||
If you have a buffer of your own with enough padding already (SIMDJSON_PADDING extra bytes allocated), you can use `padded_string_view` to pass it in:
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
@@ -217,73 +240,72 @@ strcpy(json, "[1]");
|
|||||||
ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
|
ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
|
||||||
```
|
```
|
||||||
|
|
||||||
The simdjson library will also accept `std::string` instances. If the provided
|
**Copying into a `padded_string`.** You can copy your data directly into a `simdjson::padded_string`:
|
||||||
reference is non-const, it will allocate padding as needed.
|
|
||||||
|
|
||||||
You can copy your data directly on a `simdjson::padded_string` as follows:
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const char * data = "my data"; // 7 bytes
|
const char * data = "my data"; // 7 bytes
|
||||||
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
||||||
```
|
```
|
||||||
|
|
||||||
Or as follows...
|
Or from a `std::string`:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::string data = "my data";
|
std::string data = "my data";
|
||||||
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then parse the JSON data from the `simdjson::padded_string` instance:
|
**`std::string` and sanitizer warnings.** Whenever you pass an `std::string` reference to `parser::iterate`,
|
||||||
|
the parser may access bytes beyond the end of
|
||||||
|
|
||||||
```cpp
|
|
||||||
ondemand::document doc = parser.iterate(my_padded_data);
|
|
||||||
```
|
|
||||||
|
|
||||||
Whenever you pass an `std::string` reference to `parser::iterate`,
|
|
||||||
the parser will access the bytes beyond the end of
|
|
||||||
the string but before the end of the allocated memory (`std::string::capacity()`).
|
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
|
Sanitizers that check for reading uninitialized bytes may produce warnings.
|
||||||
container-overflow checks, you may encounter sanitizer warnings.
|
You can safely ignore these warnings, or call `simdjson::pad(std::string&)` to pad the
|
||||||
You can safely ignore these warnings. Or you can call `simdjson::pad(std::string&)` to pad the
|
string explicitly:
|
||||||
string with `SIMDJSON_PADDING` spaces: this function returns a `simdjson::padding_string_view` which can be be passed to the parser's iterator function:
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::string json = "[1]";
|
std::string json = "[1]";
|
||||||
ondemand::document doc = parser.iterate(simdjson::pad(json));
|
ondemand::document doc = parser.iterate(simdjson::pad(json));
|
||||||
```
|
```
|
||||||
|
|
||||||
We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data.
|
We recommend against creating many `std::string` or many `std::padded_string` instances in your application to store your JSON data.
|
||||||
Consider reusing the same buffers and limiting memory allocations.
|
Consider reusing the same buffers and limiting memory allocations.
|
||||||
|
|
||||||
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error handling](#error-handling) for details.
|
**Memory-file mapping (non-Windows).** You can use memory-file mapping to create a `simdjson::padded_string_view`
|
||||||
|
from a file on disk:
|
||||||
|
|
||||||
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
```cpp
|
||||||
|
simdjson::padded_memory_map map(myfilename);
|
||||||
|
if (!map.is_valid()) { /* handle error */ }
|
||||||
|
simdjson::padded_string_view view = map.view();
|
||||||
|
ondemand::document doc = parser.iterate(view);
|
||||||
|
```
|
||||||
|
|
||||||
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn)
|
**Windows-specific notes.** Windows users compiling with C++17 or better may use `wchar_t` strings to support non-ASCII
|
||||||
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
|
filenames: `padded_string::load(L"twitter.json")`. Windows users who need to read files with
|
||||||
|
|
||||||
*Windows-specific*: Windows users who need to read files with
|
|
||||||
non-ANSI characters in the name should set their code page to
|
non-ANSI characters in the name should set their code page to
|
||||||
UTF-8 (65001). This should be the default with Windows 11 and better.
|
UTF-8 (65001). This should be the default with Windows 11 and better.
|
||||||
Further, they may use the AreFileApisANSI function to determine whether
|
Further, they may use the AreFileApisANSI function to determine whether
|
||||||
the filename is interpreted using the ANSI or the system default OEM
|
the filename is interpreted using the ANSI or the system default OEM
|
||||||
codepage, and they may call SetFileApisToOEM accordingly.
|
codepage, and they may call SetFileApisToOEM accordingly.
|
||||||
|
|
||||||
|
Some users may want to browse code along with the compiled assembly:
|
||||||
|
|
||||||
**Advanced feature:**
|
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn)
|
||||||
On non-Windows systems, you can use memory-file mapping to create a `simdjson::padded_string_view`
|
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
|
||||||
from a file on disk.
|
|
||||||
|
|
||||||
```cpp
|
**Summary of input types:**
|
||||||
// If the macro _WIN32 is defined, this will not work since we do not support memory-file mapping
|
|
||||||
// under Windows at this time.
|
|
||||||
simdjson::padded_memory_map map(myfilename);
|
| Input Type / Method | Padding Requirement | How Padding is Handled | Ownership / Copying | Notes / Warnings |
|
||||||
if (!map.is_valid()) { /* handle error */ }
|
|----------------------------------------------|-------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|----------------------------------------------|----------------------------------------------------------------------------------|
|
||||||
simdjson::padded_string_view view = map.view(); // view is usable while padded_memory_map is in scope
|
| `padded_string::load("file.json")` | Automatic (SIMDJSON_PADDING extra bytes) | Library allocates padded buffer and loads file into it | Owned by `padded_string` | Recommended for files; safest and simplest. |
|
||||||
ondemand::document doc = parser.iterate(view); // parse the JSON
|
| `"...json..."_padded` literal | Automatic (built-in padding) | Creates `padded_string` with padding | Owned by `padded_string` | Convenient for small hardcoded JSON. |
|
||||||
```
|
| `simdjson::padded_input` (C++17+) | Automatic when needed | Adds padding **only** if the string ends near a memory page boundary. For `std::string`, considers `capacity()` | Usually a non-owning view (no copy most times) | Safe on standard OS (page size ≥ 4096). May trigger sanitizer/valgrind warnings (harmless). Avoid on niche embedded systems. |
|
||||||
|
| User buffer with explicit padding | Must have at least `SIMDJSON_PADDING` extra allocated bytes after JSON content | Pass via `iterate(ptr, json_length, total_allocated_size)` or `padded_string_view` | User-owned (no copy) | Use `char buf[len + SIMDJSON_PADDING]`. Library reads (but never writes) into padding. |
|
||||||
|
| `std::string` (non-const) | Library checks `capacity()` | If insufficient, library may allocate a padded copy | May copy (depends on capacity) | Can trigger sanitizer warnings on uninitialized bytes. Use `simdjson::pad(json)` to avoid. |
|
||||||
|
| `simdjson::pad(std::string&)` | Adds padding if needed | Returns `padded_string_view` pointing to the (possibly resized) string | References original string | Recommended to silence sanitizers when using `std::string`. |
|
||||||
|
| `padded_string(data, length)` or `padded_string(std::string)` | Automatic (copies into padded buffer) | Explicit copy into owned padded buffer | Owned by `padded_string` | Safe when you want full ownership and padding guaranteed. |
|
||||||
|
| `padded_string_view` (manual) | User guarantees `SIMDJSON_PADDING` extra bytes after the viewed length | User provides pointer + length + capacity | Non-owning view | Low-level; requires careful buffer management. |
|
||||||
|
| Memory-mapped file (`padded_memory_map`) | Automatic via mapping (non-Windows only) | Creates view with sufficient padding | Non-owning (tied to map lifetime) | Advanced; efficient for large files on Linux/macOS/etc. |
|
||||||
|
|
||||||
|
|
||||||
Documents are iterators
|
Documents are iterators
|
||||||
@@ -379,8 +401,6 @@ tracking explicitly potential programming mistakes. Thus you should not relying
|
|||||||
size (`sizeof`) of our data structures to be constant: they may change depending on the
|
size (`sizeof`) of our data structures to be constant: they may change depending on the
|
||||||
compiler settings.
|
compiler settings.
|
||||||
|
|
||||||
When `SIMDJSON_DEVELOPMENT_CHECKS` is set at compile time, the global variable `simdjson_development_checks_enabled` is defined as true. It is false otherwise.
|
|
||||||
|
|
||||||
Once your code has been tested, you can then run it in
|
Once your code has been tested, you can then run it in
|
||||||
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
|
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
|
||||||
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
|
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
|
||||||
|
|||||||
@@ -32,6 +32,21 @@ your code with the `SIMDJSON_STATIC_REFLECTION` macro set:
|
|||||||
The `simdjson::compile_time::parse_json` function parses a JSON document at **compile time** and returns a `constexpr` structure reflecting its content. We support the full range of JSON values, which are mapped to C++ types as in
|
The `simdjson::compile_time::parse_json` function parses a JSON document at **compile time** and returns a `constexpr` structure reflecting its content. We support the full range of JSON values, which are mapped to C++ types as in
|
||||||
the following table.
|
the following table.
|
||||||
|
|
||||||
|
For convenience, you can also use the `""_json` user-defined literal operator, which is available in the `simdjson::literals` namespace:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace simdjson::literals;
|
||||||
|
|
||||||
|
constexpr auto cfg = R"(
|
||||||
|
{
|
||||||
|
"port": 8080,
|
||||||
|
"host": "localhost"
|
||||||
|
}
|
||||||
|
)"_json;
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can use the qualified name `simdjson::literals::operator""_json`.
|
||||||
|
|
||||||
|
|
||||||
| JSON type | C++ type |
|
| JSON type | C++ type |
|
||||||
|----------------|----------------------------------|
|
|----------------|----------------------------------|
|
||||||
@@ -61,6 +76,8 @@ You can do so, at compile-time, as follows:
|
|||||||
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
using namespace simdjson::literals;
|
||||||
|
|
||||||
constexpr auto cfg = R"(
|
constexpr auto cfg = R"(
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -79,6 +96,8 @@ constexpr auto cfg = R"(
|
|||||||
You can nest objects and arrays:
|
You can nest objects and arrays:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
using namespace simdjson::literals;
|
||||||
|
|
||||||
constexpr auto data = R"(
|
constexpr auto data = R"(
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -98,6 +117,8 @@ constexpr auto data = R"(
|
|||||||
Top-level arrays are allowed:
|
Top-level arrays are allowed:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
using namespace simdjson::literals;
|
||||||
|
|
||||||
constexpr auto arr = R"(
|
constexpr auto arr = R"(
|
||||||
|
|
||||||
[1, 2, 3]
|
[1, 2, 3]
|
||||||
@@ -116,6 +137,8 @@ want to check that it conforms to your expectation. You can do so with concepts.
|
|||||||
Let us consider this example:
|
Let us consider this example:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
using namespace simdjson::literals;
|
||||||
|
|
||||||
constexpr auto config = R"(
|
constexpr auto config = R"(
|
||||||
|
|
||||||
[
|
[
|
||||||
|
|||||||
+13
@@ -882,6 +882,19 @@ simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len,
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
If you are compiling your project with C++17 or better, you can use a `simdjson::padded_input`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
simdjson::dom::parser parser;
|
||||||
|
std::string_view json = "[1,2,3]";
|
||||||
|
simdjson::padded_input input(json); // Automatically pads if needed
|
||||||
|
simdjson::dom::element element = parser.parse(input);
|
||||||
|
```
|
||||||
|
|
||||||
|
The actual padding only occurs if the JSON string ends near the boundary of a memory page, which is uncommon. Using a `simdjson::padded_input` is safe although sanitizers and tools like valgrind might report illegal reads (which are safe in our case because they remain in the mapped page). You should avoid `simdjson::padded_input` on systems without a page size of at least 4096: virtually all systems qualify except for some niche embedded systems running custom operating systems. Standard Linux, Windows, macOS, Android, iOS, etc., are all fine. Note that, most times, an `simdjson::padded_input` instance will not copy the data and will only act
|
||||||
|
as a view (it does not own the memory).
|
||||||
|
|
||||||
|
|
||||||
Performance Tips
|
Performance Tips
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|||||||
+20
-4
@@ -204,9 +204,25 @@ but can be significantly larger. E.g., Apple systems favour pages spanning 16 ki
|
|||||||
|
|
||||||
In effect, it means that you can almost always read a few bytes beyond your current buffer---without
|
In effect, it means that you can almost always read a few bytes beyond your current buffer---without
|
||||||
allocating extra memory. However, tools such as valgrind or memory sanitizers will flag such behavior as unsafe.
|
allocating extra memory. However, tools such as valgrind or memory sanitizers will flag such behavior as unsafe.
|
||||||
Nevertheless, you can still make sure of this capability in your code if you are an expert
|
You can still make sure of this capability in your code if you are an expert
|
||||||
programmer and you are willing to silence sanitizer warnings. The following code provides
|
programmer and you are willing to silence sanitizer warnings.
|
||||||
a portable example.
|
|
||||||
|
If you are building simdjson with C++17 or better, you can use `simdjson::padded_input`.
|
||||||
|
The `padded_input` struct automatically manages padding for you. It can be constructed from a `std::string_view` or a C-style string with length. If the input already has sufficient padding (up to the end of the memory page), it creates a view without copying. Otherwise, it copies the data into a `padded_string` with proper padding.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::string_view json = get_json_data();
|
||||||
|
simdjson::padded_input input(json); // Automatically pads if needed
|
||||||
|
auto result = parser.parse(input);
|
||||||
|
```
|
||||||
|
|
||||||
|
This simplifies padding management compared to manually checking and allocating.
|
||||||
|
|
||||||
|
|
||||||
|
More generally, the following code provides a portable example.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The conditional compilation checks for the `_MSC_VER` macro (indicating Microsoft Visual Studio)
|
The conditional compilation checks for the `_MSC_VER` macro (indicating Microsoft Visual Studio)
|
||||||
@@ -250,7 +266,7 @@ long page_size() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
|
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
|
||||||
// page boundary.
|
// page boundary. Assumes len != 0.
|
||||||
bool need_allocation(const char *buf, size_t len) {
|
bool need_allocation(const char *buf, size_t len) {
|
||||||
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
|
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
|
||||||
+ simdjson::SIMDJSON_PADDING >= static_cast<uintptr_t>(page_size()));
|
+ simdjson::SIMDJSON_PADDING >= static_cast<uintptr_t>(page_size()));
|
||||||
|
|||||||
+12
-1
@@ -35,6 +35,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "simdjson/common_defs.h"
|
#include "simdjson/common_defs.h"
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
|
|
||||||
// This provides the public API for simdjson.
|
// This provides the public API for simdjson.
|
||||||
// DOM and ondemand are amalgamated separately, in simdjson.h
|
// DOM and ondemand are amalgamated separately, in simdjson.h
|
||||||
@@ -45,19 +46,29 @@
|
|||||||
#include "simdjson/error.h"
|
#include "simdjson/error.h"
|
||||||
#include "simdjson/error-inl.h"
|
#include "simdjson/error-inl.h"
|
||||||
#include "simdjson/implementation.h"
|
#include "simdjson/implementation.h"
|
||||||
|
#include "simdjson/builtin.h"
|
||||||
#include "simdjson/minify.h"
|
#include "simdjson/minify.h"
|
||||||
#include "simdjson/padded_string.h"
|
#include "simdjson/padded_string.h"
|
||||||
#include "simdjson/padded_string-inl.h"
|
#include "simdjson/padded_string-inl.h"
|
||||||
#include "simdjson/padded_string_view.h"
|
#include "simdjson/padded_string_view.h"
|
||||||
#include "simdjson/padded_string_view-inl.h"
|
#include "simdjson/padded_string_view-inl.h"
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
#include "simdjson/dom.h"
|
#include "simdjson/dom.h"
|
||||||
|
#if SIMDJSON_FEATURE_BUILDER_API
|
||||||
#include "simdjson/builder.h"
|
#include "simdjson/builder.h"
|
||||||
|
#endif // SIMDJSON_FEATURE_BUILDER_API
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_ONDEMAND_API
|
||||||
#include "simdjson/ondemand.h"
|
#include "simdjson/ondemand.h"
|
||||||
|
#endif // SIMDJSON_FEATURE_ONDEMAND_API
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API && SIMDJSON_FEATURE_ONDEMAND_API
|
||||||
#include "simdjson/convert.h"
|
#include "simdjson/convert.h"
|
||||||
#include "simdjson/convert-inl.h"
|
#include "simdjson/convert-inl.h"
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API && SIMDJSON_FEATURE_ONDEMAND_API
|
||||||
|
|
||||||
// Compile-time JSON parsing (C++26 P2996 reflection)
|
|
||||||
#include "simdjson/compile_time_json.h"
|
#include "simdjson/compile_time_json.h"
|
||||||
#include "simdjson/compile_time_json-inl.h"
|
#include "simdjson/compile_time_json-inl.h"
|
||||||
|
|
||||||
|
|||||||
@@ -297,15 +297,6 @@ namespace std {
|
|||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
#endif // SIMDJSON_DEVELOPMENT_CHECKS
|
#endif // SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
|
|
||||||
|
|
||||||
// Prevent ODR violations for the simdjson_development_checks_enabled variable.
|
|
||||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
|
||||||
extern const bool simdjson_development_checks_enabled = true;
|
|
||||||
#else
|
|
||||||
extern const bool simdjson_development_checks_enabled = false;
|
|
||||||
#endif // SIMDJSON_DEVELOPMENT_CHECKS
|
|
||||||
|
|
||||||
|
|
||||||
// The SIMDJSON_CHECK_EOF macro is a feature flag for the "don't require padding"
|
// The SIMDJSON_CHECK_EOF macro is a feature flag for the "don't require padding"
|
||||||
// feature.
|
// feature.
|
||||||
|
|
||||||
|
|||||||
@@ -63,13 +63,16 @@ namespace compile_time {
|
|||||||
template <constevalutil::fixed_string json_str> consteval auto parse_json();
|
template <constevalutil::fixed_string json_str> consteval auto parse_json();
|
||||||
|
|
||||||
} // namespace compile_time
|
} // namespace compile_time
|
||||||
} // namespace simdjson
|
|
||||||
|
|
||||||
|
inline namespace literals {
|
||||||
|
|
||||||
template <simdjson::constevalutil::fixed_string str>
|
template <simdjson::constevalutil::fixed_string str>
|
||||||
consteval auto operator ""_json() {
|
consteval auto operator ""_json() {
|
||||||
return simdjson::compile_time::parse_json<str>();
|
return simdjson::compile_time::parse_json<str>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace literals
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_STATIC_REFLECTION
|
#endif // SIMDJSON_STATIC_REFLECTION
|
||||||
#endif // SIMDJSON_GENERIC_COMPILE_TIME_JSON_H
|
#endif // SIMDJSON_GENERIC_COMPILE_TIME_JSON_H
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(SIMDJSON_FEATURE_DOM_API)
|
||||||
|
#define SIMDJSON_FEATURE_DOM_API 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SIMDJSON_FEATURE_ONDEMAND_API)
|
||||||
|
#define SIMDJSON_FEATURE_ONDEMAND_API 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SIMDJSON_FEATURE_BUILDER_API)
|
||||||
|
#define SIMDJSON_FEATURE_BUILDER_API 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !SIMDJSON_FEATURE_DOM_API && !SIMDJSON_FEATURE_ONDEMAND_API
|
||||||
|
#error "simdjson: at least one of SIMDJSON_FEATURE_DOM_API or SIMDJSON_FEATURE_ONDEMAND_API must be enabled."
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_BUILDER_DEPENDENCIES_H)
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_ONDEMAND_API
|
||||||
|
|
||||||
|
#if defined(SIMDJSON_CONDITIONAL_INCLUDE) && !defined(SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H)
|
||||||
#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
|
#error simdjson/generic/ondemand/dependencies.h must be included before simdjson/generic/ondemand/amalgamated.h!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -48,3 +54,5 @@
|
|||||||
// JSON path accessor (compile-time) - must be after inline definitions
|
// JSON path accessor (compile-time) - must be after inline definitions
|
||||||
#include "simdjson/generic/ondemand/compile_time_accessors.h"
|
#include "simdjson/generic/ondemand/compile_time_accessors.h"
|
||||||
|
|
||||||
|
#endif // SIMDJSON_FEATURE_ONDEMAND_API
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
// Internal headers needed for ondemand generics.
|
// Internal headers needed for ondemand generics.
|
||||||
// All includes not under simdjson/generic/ondemand must be here!
|
// All includes not under simdjson/generic/ondemand must be here!
|
||||||
// Otherwise, amalgamation will fail.
|
// Otherwise, amalgamation will fail.
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY
|
#include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY
|
||||||
#include "simdjson/implementation.h"
|
#include "simdjson/implementation.h"
|
||||||
#include "simdjson/padded_string.h"
|
#include "simdjson/padded_string.h"
|
||||||
|
|||||||
@@ -8,12 +8,14 @@ namespace simdjson {
|
|||||||
* @copydoc simdjson::builtin::ondemand
|
* @copydoc simdjson::builtin::ondemand
|
||||||
*/
|
*/
|
||||||
namespace ondemand = builtin::ondemand;
|
namespace ondemand = builtin::ondemand;
|
||||||
|
#if SIMDJSON_FEATURE_BUILDER_API
|
||||||
/**
|
/**
|
||||||
* @copydoc simdjson::builtin::builder
|
* @copydoc simdjson::builtin::builder
|
||||||
*/
|
*/
|
||||||
namespace builder = builtin::builder;
|
namespace builder = builtin::builder;
|
||||||
|
#endif // SIMDJSON_FEATURE_BUILDER_API
|
||||||
|
|
||||||
#if SIMDJSON_STATIC_REFLECTION
|
#if SIMDJSON_STATIC_REFLECTION && SIMDJSON_FEATURE_BUILDER_API
|
||||||
/**
|
/**
|
||||||
* Create a JSON string from any user-defined type using static reflection.
|
* Create a JSON string from any user-defined type using static reflection.
|
||||||
* Only available when SIMDJSON_STATIC_REFLECTION is enabled.
|
* Only available when SIMDJSON_STATIC_REFLECTION is enabled.
|
||||||
|
|||||||
@@ -6,6 +6,15 @@
|
|||||||
|
|
||||||
#include <cstring> /* memcmp */
|
#include <cstring> /* memcmp */
|
||||||
|
|
||||||
|
// for page size computation.
|
||||||
|
#if defined(__unix__) || defined(__APPLE__) || defined(__linux__)
|
||||||
|
#include <unistd.h>
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
|
|
||||||
inline padded_string_view::padded_string_view(const char* s, size_t len, size_t capacity) noexcept
|
inline padded_string_view::padded_string_view(const char* s, size_t len, size_t capacity) noexcept
|
||||||
@@ -95,7 +104,83 @@ inline padded_string_view pad_with_reserve(std::string& s) noexcept {
|
|||||||
return padded_string_view(s.data(), s.size(), s.capacity());
|
return padded_string_view(s.data(), s.size(), s.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint32_t get_page_size() noexcept {
|
||||||
|
#if defined(_WINDOWS_) // if and only if someone loaded Windows.h, we can get the page size from there.
|
||||||
|
// Otherwise, we assume 4096.
|
||||||
|
static const uint32_t cached = []() -> uint32_t {
|
||||||
|
SYSTEM_INFO si;
|
||||||
|
GetSystemInfo(&si);
|
||||||
|
return static_cast<std::uint32_t>(si.dwPageSize);
|
||||||
|
}();
|
||||||
|
return cached;
|
||||||
|
#elif defined(__unix__) || defined(__APPLE__) || defined(__linux__)
|
||||||
|
static const uint32_t cached = []() -> uint32_t {
|
||||||
|
long page_size = sysconf(_SC_PAGESIZE);
|
||||||
|
if (page_size > 0) {
|
||||||
|
return static_cast<uint32_t>(page_size);
|
||||||
|
}
|
||||||
|
return 4096; // fallback
|
||||||
|
}();
|
||||||
|
return cached;
|
||||||
|
#else
|
||||||
|
return 4096; // fallback
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
|
|
||||||
|
inline padded_input::padded_input(std::string_view sv)
|
||||||
|
: storage(simdjson::padded_string_view{}) {
|
||||||
|
if (needs_allocation(sv.data(), sv.size())) {
|
||||||
|
storage = simdjson::padded_string(sv);
|
||||||
|
} else {
|
||||||
|
storage = simdjson::padded_string_view(
|
||||||
|
sv.data(), sv.size(), sv.size() + simdjson::SIMDJSON_PADDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline padded_input::padded_input(const char *data, size_t length)
|
||||||
|
: storage(simdjson::padded_string_view{}) {
|
||||||
|
if (needs_allocation(data, length)) {
|
||||||
|
storage = simdjson::padded_string(data, length);
|
||||||
|
} else {
|
||||||
|
storage = simdjson::padded_string_view(
|
||||||
|
data, length, length + simdjson::SIMDJSON_PADDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline padded_input::padded_input(const std::string &s)
|
||||||
|
: storage(simdjson::padded_string_view{}) {
|
||||||
|
const size_t len = s.size();
|
||||||
|
const size_t cap = s.capacity();
|
||||||
|
// Here we have the string content from data() to data() + size(),
|
||||||
|
// but the memory is accessible from data() to data() + capacity().
|
||||||
|
const size_t needed_padding = (cap - len) < simdjson::SIMDJSON_PADDING
|
||||||
|
? simdjson::SIMDJSON_PADDING - (cap - len) : 0;
|
||||||
|
if (needed_padding > 0 && needs_allocation(s.data(), cap, needed_padding)) {
|
||||||
|
storage = simdjson::padded_string(s);
|
||||||
|
} else {
|
||||||
|
storage = simdjson::padded_string_view(
|
||||||
|
s.data(), len, len + simdjson::SIMDJSON_PADDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool padded_input::is_view() const noexcept {
|
||||||
|
return std::holds_alternative<simdjson::padded_string_view>(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline padded_input::operator simdjson::padded_string_view() const noexcept {
|
||||||
|
return std::visit([](const auto& p) -> simdjson::padded_string_view {
|
||||||
|
return p;
|
||||||
|
}, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool padded_input::needs_allocation(const char* buf, size_t len, size_t padding) noexcept {
|
||||||
|
if(len == 0) { return false; }
|
||||||
|
const auto page_size = get_page_size();
|
||||||
|
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size)
|
||||||
|
+ padding >= static_cast<uintptr_t>(page_size));
|
||||||
|
}
|
||||||
|
#endif // SIMDJSON_CPLUSPLUS17
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
|
#include <variant>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
|
|
||||||
@@ -73,6 +76,68 @@ public:
|
|||||||
|
|
||||||
}; // padded_string_view
|
}; // padded_string_view
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the system's memory page size. By default, we return
|
||||||
|
* 4096 bytes, which is the most common page size. On systems
|
||||||
|
* where the page size is not a multiple of 4096 bytes, and not
|
||||||
|
* a unix-like system, nor Windows, this function may return an
|
||||||
|
* incorrect value.
|
||||||
|
*
|
||||||
|
* @return The page size in bytes.
|
||||||
|
*/
|
||||||
|
inline uint32_t get_page_size() noexcept;
|
||||||
|
|
||||||
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
|
/**
|
||||||
|
* A padded_input is a wrapper around either a padded_string_view or a padded_string.
|
||||||
|
* It will automatically pad a string_view if it does not have sufficient padding
|
||||||
|
* up to the end of the memory page. Note that a requirement for this method to
|
||||||
|
* make sense is to be on a system with a page size of at least 4096 (which is
|
||||||
|
* universal except on some embedded systems).
|
||||||
|
*/
|
||||||
|
struct padded_input {
|
||||||
|
/**
|
||||||
|
* Construct a padded_input from a string_view. If the string_view does not have sufficient padding,
|
||||||
|
* the data will be copied into a padded_string and the padded_string_view will point to the
|
||||||
|
* padded_string's data. Otherwise, the padded_string_view will point to the original string_view's data.
|
||||||
|
*/
|
||||||
|
inline explicit padded_input(std::string_view sv);
|
||||||
|
/**
|
||||||
|
* Construct a padded_input from a C-style string (length specified). If the string does not have sufficient padding,
|
||||||
|
* the data will be copied into a padded_string and the padded_string_view will point to the
|
||||||
|
* padded_string's data. Otherwise, the padded_string_view will point to the original string's data.
|
||||||
|
*/
|
||||||
|
inline explicit padded_input(const char *data, size_t length);
|
||||||
|
/**
|
||||||
|
* Construct a padded_input from a std::string. If the string does not have sufficient padding
|
||||||
|
* (considering its capacity), the data will be copied into a padded_string and the padded_string_view
|
||||||
|
* will point to the padded_string's data. Otherwise, the padded_string_view will point to the
|
||||||
|
* original string's data.
|
||||||
|
*/
|
||||||
|
inline explicit padded_input(const std::string &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the padded_input is a view.
|
||||||
|
*
|
||||||
|
* @return true if the padded_input is a view, false otherwise.
|
||||||
|
*/
|
||||||
|
inline bool is_view() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the padded_input to a padded_string_view.
|
||||||
|
*
|
||||||
|
* @return The padded_string_view.
|
||||||
|
*/
|
||||||
|
inline operator simdjson::padded_string_view() const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<simdjson::padded_string_view, simdjson::padded_string> storage;
|
||||||
|
// whether we cross a page boundary and need to allocate a new padded string.
|
||||||
|
static inline bool needs_allocation(const char* buf, size_t len, size_t padding = SIMDJSON_PADDING) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SIMDJSON_CPLUSPLUS17
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
/**
|
/**
|
||||||
* Send padded_string instance to an output stream.
|
* Send padded_string instance to an output stream.
|
||||||
@@ -105,6 +170,7 @@ inline padded_string_view pad(std::string& s) noexcept;
|
|||||||
* @return The padded string.
|
* @return The padded string.
|
||||||
*/
|
*/
|
||||||
inline padded_string_view pad_with_reserve(std::string& s) noexcept;
|
inline padded_string_view pad_with_reserve(std::string& s) noexcept;
|
||||||
|
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_PADDED_STRING_VIEW_H
|
#endif // SIMDJSON_PADDED_STRING_VIEW_H
|
||||||
|
|||||||
Executable
+226
@@ -0,0 +1,226 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Amalgamates simdjson into temporary files, then builds and runs 7 feature-flag
|
||||||
|
test programs. Reports compile time and binary size for each configuration.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
SCRIPTPATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
PROJECTPATH = os.path.dirname(SCRIPTPATH)
|
||||||
|
TESTSRC = os.path.join(PROJECTPATH, "tests", "feature_flag_tests")
|
||||||
|
|
||||||
|
# ── feature-flag configurations ──────────────────────────────────────────────
|
||||||
|
CONFIGS = [
|
||||||
|
{
|
||||||
|
"name": "dom_only",
|
||||||
|
"flags": {"SIMDJSON_FEATURE_DOM_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_ONDEMAND_API": 0,
|
||||||
|
"SIMDJSON_FEATURE_BUILDER_API": 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ondemand_only",
|
||||||
|
"flags": {"SIMDJSON_FEATURE_DOM_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_ONDEMAND_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_BUILDER_API": 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dom_and_ondemand",
|
||||||
|
"flags": {"SIMDJSON_FEATURE_DOM_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_ONDEMAND_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_BUILDER_API": 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "builder_and_dom",
|
||||||
|
"flags": {"SIMDJSON_FEATURE_DOM_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_ONDEMAND_API": 0,
|
||||||
|
"SIMDJSON_FEATURE_BUILDER_API": 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "builder_and_ondemand",
|
||||||
|
"flags": {"SIMDJSON_FEATURE_DOM_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_ONDEMAND_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_BUILDER_API": 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "builder_dom_and_ondemand",
|
||||||
|
"flags": {"SIMDJSON_FEATURE_DOM_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_ONDEMAND_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_BUILDER_API": 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "builder_only",
|
||||||
|
"flags": {"SIMDJSON_FEATURE_DOM_API": 1,
|
||||||
|
"SIMDJSON_FEATURE_ONDEMAND_API": 0,
|
||||||
|
"SIMDJSON_FEATURE_BUILDER_API": 1},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
CXX = os.environ.get("CXX", "c++")
|
||||||
|
CXXSTD = os.environ.get("CXXSTD", "-std=c++17")
|
||||||
|
OPT = os.environ.get("OPT", "-O2")
|
||||||
|
|
||||||
|
|
||||||
|
def amalgamate(output_dir):
|
||||||
|
"""Run amalgamate.py, writing simdjson.h / simdjson.cpp into *output_dir*."""
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["AMALGAMATE_OUTPUT_PATH"] = output_dir
|
||||||
|
cmd = [sys.executable, os.path.join(SCRIPTPATH, "amalgamate.py")]
|
||||||
|
result = subprocess.run(cmd, env=env, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print("amalgamate.py failed:")
|
||||||
|
print(result.stdout)
|
||||||
|
print(result.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
header = os.path.join(output_dir, "simdjson.h")
|
||||||
|
source = os.path.join(output_dir, "simdjson.cpp")
|
||||||
|
assert os.path.isfile(header), f"missing {header}"
|
||||||
|
assert os.path.isfile(source), f"missing {source}"
|
||||||
|
return header, source
|
||||||
|
|
||||||
|
|
||||||
|
def compile_and_run(name, flags, amal_dir, build_dir):
|
||||||
|
"""
|
||||||
|
1. Compile simdjson.cpp -> simdjson.o (timed, size reported)
|
||||||
|
2. Compile test .cpp -> test.o (timed, size reported)
|
||||||
|
3. Link and run the test program
|
||||||
|
|
||||||
|
Returns (lib_time, lib_size, test_time, test_size) or Nones on failure.
|
||||||
|
"""
|
||||||
|
src = os.path.join(TESTSRC, f"{name}.cpp")
|
||||||
|
simdjson_cpp = os.path.join(amal_dir, "simdjson.cpp")
|
||||||
|
simdjson_o = os.path.join(build_dir, f"{name}_simdjson.o")
|
||||||
|
test_o = os.path.join(build_dir, f"{name}.o")
|
||||||
|
binary = os.path.join(build_dir, name)
|
||||||
|
|
||||||
|
defs = [f"-D{k}={v}" for k, v in flags.items()]
|
||||||
|
|
||||||
|
# ── compile simdjson.o (timed) ────────────────────────────────────────
|
||||||
|
cmd_lib = [CXX, CXXSTD, OPT, "-c"] + defs + [
|
||||||
|
f"-I{amal_dir}", "-o", simdjson_o, simdjson_cpp,
|
||||||
|
]
|
||||||
|
t0 = time.monotonic()
|
||||||
|
result = subprocess.run(cmd_lib, capture_output=True, text=True)
|
||||||
|
lib_time = time.monotonic() - t0
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f" COMPILE FAILED (simdjson.o): {name}")
|
||||||
|
print(f" command: {' '.join(cmd_lib)}")
|
||||||
|
print(result.stderr)
|
||||||
|
return None, None, None, None
|
||||||
|
|
||||||
|
lib_size = os.path.getsize(simdjson_o)
|
||||||
|
|
||||||
|
# ── compile test source (timed) ───────────────────────────────────────
|
||||||
|
cmd_test = [CXX, CXXSTD, OPT, "-c"] + defs + [
|
||||||
|
f"-I{amal_dir}", "-o", test_o, src,
|
||||||
|
]
|
||||||
|
t0 = time.monotonic()
|
||||||
|
result = subprocess.run(cmd_test, capture_output=True, text=True)
|
||||||
|
test_time = time.monotonic() - t0
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f" COMPILE FAILED (test): {name}")
|
||||||
|
print(f" command: {' '.join(cmd_test)}")
|
||||||
|
print(result.stderr)
|
||||||
|
return None, None, None, None
|
||||||
|
|
||||||
|
test_size = os.path.getsize(test_o)
|
||||||
|
|
||||||
|
# ── link ──────────────────────────────────────────────────────────────
|
||||||
|
cmd_link = [CXX, "-o", binary, test_o, simdjson_o]
|
||||||
|
result = subprocess.run(cmd_link, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f" LINK FAILED: {name}")
|
||||||
|
print(f" command: {' '.join(cmd_link)}")
|
||||||
|
print(result.stderr)
|
||||||
|
return None, None, None, None
|
||||||
|
|
||||||
|
# ── run ───────────────────────────────────────────────────────────────
|
||||||
|
result = subprocess.run([binary], capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f" RUN FAILED: {name}")
|
||||||
|
print(result.stdout)
|
||||||
|
print(result.stderr)
|
||||||
|
return lib_time, lib_size, test_time, test_size
|
||||||
|
|
||||||
|
print(f" {result.stdout.strip()}")
|
||||||
|
return lib_time, lib_size, test_time, test_size
|
||||||
|
|
||||||
|
|
||||||
|
def human_size(n):
|
||||||
|
"""Return e.g. '1.23 MB' or '456 KB'."""
|
||||||
|
if n is None:
|
||||||
|
return "N/A"
|
||||||
|
if n >= 1_000_000:
|
||||||
|
return f"{n / 1_000_000:.2f} MB"
|
||||||
|
if n >= 1_000:
|
||||||
|
return f"{n / 1_000:.1f} KB"
|
||||||
|
return f"{n} B"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
tmpdir = tempfile.mkdtemp(prefix="simdjson_features_")
|
||||||
|
amal_dir = os.path.join(tmpdir, "amalgamated")
|
||||||
|
build_dir = os.path.join(tmpdir, "build")
|
||||||
|
os.makedirs(amal_dir, exist_ok=True)
|
||||||
|
os.makedirs(build_dir, exist_ok=True)
|
||||||
|
|
||||||
|
print(f"Working directory: {tmpdir}")
|
||||||
|
print(f"Compiler: {CXX} flags: {CXXSTD} {OPT}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# ── amalgamate ────────────────────────────────────────────────────────
|
||||||
|
print("Amalgamating...")
|
||||||
|
amalgamate(amal_dir)
|
||||||
|
print("Amalgamation done.\n")
|
||||||
|
|
||||||
|
# ── build & run each configuration ────────────────────────────────────
|
||||||
|
results = []
|
||||||
|
for cfg in CONFIGS:
|
||||||
|
name = cfg["name"]
|
||||||
|
flags = cfg["flags"]
|
||||||
|
enabled = [k.replace("SIMDJSON_FEATURE_", "").replace("_API", "")
|
||||||
|
for k, v in flags.items() if v]
|
||||||
|
label = " + ".join(enabled) if enabled else "none"
|
||||||
|
print(f"[{name}] ({label})")
|
||||||
|
lib_time, lib_size, test_time, test_size = \
|
||||||
|
compile_and_run(name, flags, amal_dir, build_dir)
|
||||||
|
results.append((name, label, lib_time, lib_size, test_time, test_size))
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
# ── summary table ─────────────────────────────────────────────────────
|
||||||
|
name_w = max(len(r[0]) for r in results)
|
||||||
|
label_w = max(len(r[1]) for r in results)
|
||||||
|
hdr = (f"{'Test':<{name_w}} {'APIs':<{label_w}}"
|
||||||
|
f" {'lib time':>9} {'simdjson.o':>11}"
|
||||||
|
f" {'test time':>10} {'test .o':>11}")
|
||||||
|
print(hdr)
|
||||||
|
print("-" * len(hdr))
|
||||||
|
for name, label, lt, ls, tt, ts in results:
|
||||||
|
lt_s = f"{lt:.2f} s" if lt is not None else "FAIL"
|
||||||
|
ls_s = human_size(ls)
|
||||||
|
tt_s = f"{tt:.2f} s" if tt is not None else "FAIL"
|
||||||
|
ts_s = human_size(ts)
|
||||||
|
print(f"{name:<{name_w}} {label:<{label_w}}"
|
||||||
|
f" {lt_s:>9} {ls_s:>11}"
|
||||||
|
f" {tt_s:>10} {ts_s:>11}")
|
||||||
|
|
||||||
|
# ── cleanup ───────────────────────────────────────────────────────────
|
||||||
|
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||||
|
|
||||||
|
# exit non-zero if anything failed
|
||||||
|
if any(lt is None for _, _, lt, _, _, _ in results):
|
||||||
|
print("\nSome tests FAILED.")
|
||||||
|
sys.exit(1)
|
||||||
|
print("\nAll tests passed.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -268,7 +268,21 @@ class SimdjsonFile:
|
|||||||
print(f" Adding include: {self} includes {include}")
|
print(f" Adding include: {self} includes {include}")
|
||||||
if self.is_conditional_include:
|
if self.is_conditional_include:
|
||||||
# If I have a dependency file, I can only include something that has a dependency file.
|
# If I have a dependency file, I can only include something that has a dependency file.
|
||||||
assert include.is_conditional_include, f"Error: Amalgamated file '{self}' is trying to include '{include}', but '{include}' is not an amalgamated file. Amalgamated files can only include other amalgamated files to maintain conditional inclusion structure. Check the inclusion rules in the script's 'rules' variable. {rules}"
|
if not include.is_conditional_include:
|
||||||
|
dep = self.dependency_file
|
||||||
|
dep_hint = f" and add it to the dependency file '{dep}'" if dep else ""
|
||||||
|
raise AssertionError(
|
||||||
|
f"Error: Amalgamated file '{self}' is trying to include '{include}', "
|
||||||
|
f"but '{include}' is not an amalgamated file.\n\n"
|
||||||
|
f"FIX: Wrap the #include \"{include}\" in a conditional block:\n\n"
|
||||||
|
f" #ifndef SIMDJSON_CONDITIONAL_INCLUDE\n"
|
||||||
|
f" #include \"{include}\"\n"
|
||||||
|
f" #endif // SIMDJSON_CONDITIONAL_INCLUDE\n\n"
|
||||||
|
f"This makes the include editor-only (skipped during amalgamation){dep_hint}.\n\n"
|
||||||
|
f"During amalgamation, '{include}' is already included earlier in the "
|
||||||
|
f"amalgamated output, so it does not need to be included again.\n\n"
|
||||||
|
f"{rules}"
|
||||||
|
)
|
||||||
# TODO make sure we only include amalgamated files that are guaranteed to be included with us (or before us)
|
# TODO make sure we only include amalgamated files that are guaranteed to be included with us (or before us)
|
||||||
# if include.amalgamator_file:
|
# if include.amalgamator_file:
|
||||||
# assert include.amalgamator_file == self, f"{self} cannot include {include}: it should be included from {include.amalgamator_file} instead."
|
# assert include.amalgamator_file == self, f"{self} cannot include {include}: it should be included from {include.amalgamator_file} instead."
|
||||||
@@ -425,8 +439,10 @@ class Amalgamator:
|
|||||||
self.implementation = "SIMDJSON_BUILTIN_IMPLEMENTATION"
|
self.implementation = "SIMDJSON_BUILTIN_IMPLEMENTATION"
|
||||||
|
|
||||||
assert not self.editor_only_region, f"Error: Already in an editor-only region when starting to write '{file}'. Ensure proper nesting of conditional blocks."
|
assert not self.editor_only_region, f"Error: Already in an editor-only region when starting to write '{file}'. Ensure proper nesting of conditional blocks."
|
||||||
|
editor_only_start_line = None
|
||||||
|
bare_endif_lines = []
|
||||||
with open(file.absolute_path, 'r') as fid2:
|
with open(file.absolute_path, 'r') as fid2:
|
||||||
for line in fid2:
|
for line_number, line in enumerate(fid2, 1):
|
||||||
line = line.rstrip('\n')
|
line = line.rstrip('\n')
|
||||||
|
|
||||||
# Ignore #pragma once, it causes warnings if it ends up in a .cpp file
|
# Ignore #pragma once, it causes warnings if it ends up in a .cpp file
|
||||||
@@ -439,6 +455,7 @@ class Amalgamator:
|
|||||||
assert self.in_conditional_include_block, f"Error: File '{file}' uses '#ifndef SIMDJSON_CONDITIONAL_INCLUDE' without a prior '#define SIMDJSON_CONDITIONAL_INCLUDE'. Ensure the define comes first. Stack: {self.include_stack}. {rules}"
|
assert self.in_conditional_include_block, f"Error: File '{file}' uses '#ifndef SIMDJSON_CONDITIONAL_INCLUDE' without a prior '#define SIMDJSON_CONDITIONAL_INCLUDE'. Ensure the define comes first. Stack: {self.include_stack}. {rules}"
|
||||||
assert not self.editor_only_region, f"Error: File '{file}' uses '#ifndef SIMDJSON_CONDITIONAL_INCLUDE' twice in a row. Ensure conditional blocks are properly nested and closed. {rules}"
|
assert not self.editor_only_region, f"Error: File '{file}' uses '#ifndef SIMDJSON_CONDITIONAL_INCLUDE' twice in a row. Ensure conditional blocks are properly nested and closed. {rules}"
|
||||||
self.editor_only_region = True
|
self.editor_only_region = True
|
||||||
|
editor_only_start_line = line_number
|
||||||
|
|
||||||
# Handle ignored lines (and ending ignore blocks)
|
# Handle ignored lines (and ending ignore blocks)
|
||||||
end_ignore = endif_conditional_re.search(line)
|
end_ignore = endif_conditional_re.search(line)
|
||||||
@@ -453,6 +470,12 @@ class Amalgamator:
|
|||||||
file.add_editor_only_include(included_file)
|
file.add_editor_only_include(included_file)
|
||||||
if end_ignore:
|
if end_ignore:
|
||||||
self.editor_only_region = False
|
self.editor_only_region = False
|
||||||
|
editor_only_start_line = None
|
||||||
|
else:
|
||||||
|
# Track bare #endif lines that might be the intended closer
|
||||||
|
stripped = line.strip()
|
||||||
|
if stripped == '#endif' or (stripped.startswith('#endif') and 'SIMDJSON_CONDITIONAL_INCLUDE' not in stripped):
|
||||||
|
bare_endif_lines.append((line_number, line.strip()))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert not end_ignore, f"Error: File '{file}' has '#endif // SIMDJSON_CONDITIONAL_INCLUDE' without a matching '#ifndef'. Ensure proper conditional block structure. {rules}"
|
assert not end_ignore, f"Error: File '{file}' has '#endif // SIMDJSON_CONDITIONAL_INCLUDE' without a matching '#ifndef'. Ensure proper conditional block structure. {rules}"
|
||||||
@@ -501,7 +524,35 @@ class Amalgamator:
|
|||||||
|
|
||||||
self.write(line)
|
self.write(line)
|
||||||
|
|
||||||
assert not self.editor_only_region, f"Error: File '{file}' ended without closing the '#endif // SIMDJSON_CONDITIONAL_INCLUDE'. Ensure all conditional blocks are properly closed. {rules}"
|
if self.editor_only_region:
|
||||||
|
msg = (
|
||||||
|
f"Error: File '{file}' ended without closing the "
|
||||||
|
f"'#endif // SIMDJSON_CONDITIONAL_INCLUDE' block "
|
||||||
|
f"(opened at line {editor_only_start_line}).\n\n"
|
||||||
|
)
|
||||||
|
if bare_endif_lines:
|
||||||
|
msg += (
|
||||||
|
f"HINT: Found #endif line(s) inside the block that are missing "
|
||||||
|
f"the required comment. The amalgamation script looks for exactly:\n\n"
|
||||||
|
f" #endif // SIMDJSON_CONDITIONAL_INCLUDE\n\n"
|
||||||
|
f"but found:\n"
|
||||||
|
)
|
||||||
|
for ln, text in bare_endif_lines:
|
||||||
|
msg += f" line {ln}: {text}\n"
|
||||||
|
msg += (
|
||||||
|
f"\nFIX: Change the #endif to:\n\n"
|
||||||
|
f" #endif // SIMDJSON_CONDITIONAL_INCLUDE\n\n"
|
||||||
|
f"The '// SIMDJSON_CONDITIONAL_INCLUDE' comment is required "
|
||||||
|
f"for the amalgamation script to recognize it as the closing "
|
||||||
|
f"of the conditional block.\n"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
msg += (
|
||||||
|
f"FIX: Add '#endif // SIMDJSON_CONDITIONAL_INCLUDE' to close "
|
||||||
|
f"the '#ifndef SIMDJSON_CONDITIONAL_INCLUDE' block.\n"
|
||||||
|
)
|
||||||
|
msg += f"\n{rules}"
|
||||||
|
raise AssertionError(msg)
|
||||||
|
|
||||||
self.write(f"/* end file {self.file_to_str(file)} */")
|
self.write(f"/* end file {self.file_to_str(file)} */")
|
||||||
|
|
||||||
|
|||||||
+2121
-2010
File diff suppressed because it is too large
Load Diff
+8515
-8257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_ARM64_CPP
|
#define SIMDJSON_SRC_ARM64_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -142,6 +143,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
return arm64::stage1::generic_validate_utf8(buf,len);
|
return arm64::stage1::generic_validate_utf8(buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -149,6 +151,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||||
@@ -159,11 +162,13 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return arm64::stringparsing::parse_wobbly_string(src, dst);
|
return arm64::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
} // namespace arm64
|
} // namespace arm64
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_FALLBACK_CPP
|
#define SIMDJSON_SRC_FALLBACK_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -11,10 +12,13 @@
|
|||||||
#include <simdjson/fallback/begin.h>
|
#include <simdjson/fallback/begin.h>
|
||||||
#include <generic/stage1/find_next_document_index.h>
|
#include <generic/stage1/find_next_document_index.h>
|
||||||
#include <generic/stage2/stringparsing.h>
|
#include <generic/stage2/stringparsing.h>
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
#include <generic/stage2/logger.h>
|
#include <generic/stage2/logger.h>
|
||||||
#include <generic/stage2/json_iterator.h>
|
#include <generic/stage2/json_iterator.h>
|
||||||
#include <generic/stage2/tape_writer.h>
|
#include <generic/stage2/tape_writer.h>
|
||||||
#include <generic/stage2/tape_builder.h>
|
#include <generic/stage2/tape_builder.h>
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
//
|
//
|
||||||
// Stage 1
|
// Stage 1
|
||||||
@@ -436,6 +440,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
namespace fallback {
|
namespace fallback {
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -443,6 +448,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||||
@@ -453,11 +459,13 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return fallback::stringparsing::parse_wobbly_string(src, dst);
|
return fallback::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
} // namespace fallback
|
} // namespace fallback
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#ifndef SIMDJSON_SRC_GENERIC_DEPENDENCIES_H
|
#ifndef SIMDJSON_SRC_GENERIC_DEPENDENCIES_H
|
||||||
#define SIMDJSON_SRC_GENERIC_DEPENDENCIES_H
|
#define SIMDJSON_SRC_GENERIC_DEPENDENCIES_H
|
||||||
|
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
|
|
||||||
#endif // SIMDJSON_SRC_GENERIC_DEPENDENCIES_H
|
#endif // SIMDJSON_SRC_GENERIC_DEPENDENCIES_H
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
#include <generic/stage2/stringparsing.h>
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
// Stuff other things depend on
|
// Stuff other things depend on
|
||||||
#include <generic/stage2/base.h>
|
#include <generic/stage2/base.h>
|
||||||
#include <generic/stage2/tape_writer.h>
|
#include <generic/stage2/tape_writer.h>
|
||||||
@@ -5,6 +9,7 @@
|
|||||||
|
|
||||||
// All other declarations
|
// All other declarations
|
||||||
#include <generic/stage2/json_iterator.h>
|
#include <generic/stage2/json_iterator.h>
|
||||||
#include <generic/stage2/stringparsing.h>
|
|
||||||
#include <generic/stage2/structural_iterator.h>
|
#include <generic/stage2/structural_iterator.h>
|
||||||
#include <generic/stage2/tape_builder.h>
|
#include <generic/stage2/tape_builder.h>
|
||||||
|
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|||||||
+6
-1
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_HASWELL_CPP
|
#define SIMDJSON_SRC_HASWELL_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -139,6 +140,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
return haswell::stage1::generic_validate_utf8(buf,len);
|
return haswell::stage1::generic_validate_utf8(buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -146,6 +148,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||||
@@ -156,15 +159,17 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return haswell::stringparsing::parse_wobbly_string(src, dst);
|
return haswell::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
} // namespace SIMDJSON_IMPLEMENTATION
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#include <simdjson/haswell/end.h>
|
#include <simdjson/haswell/end.h>
|
||||||
|
|
||||||
#endif // SIMDJSON_SRC_HASWELL_CPP
|
#endif // SIMDJSON_SRC_HASWELL_CPP
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_ICELAKE_CPP
|
#define SIMDJSON_SRC_ICELAKE_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -185,6 +186,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
return icelake::stage1::generic_validate_utf8(buf,len);
|
return icelake::stage1::generic_validate_utf8(buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -192,6 +194,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||||
@@ -202,11 +205,13 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return icelake::stringparsing::parse_wobbly_string(src, dst);
|
return icelake::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
} // namespace icelake
|
} // namespace icelake
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_LASX_CPP
|
#define SIMDJSON_SRC_LASX_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -102,6 +103,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
return lasx::stage1::generic_validate_utf8(buf,len);
|
return lasx::stage1::generic_validate_utf8(buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -109,6 +111,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||||
@@ -119,11 +122,13 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return lasx::stringparsing::parse_wobbly_string(src, dst);
|
return lasx::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
} // namespace lasx
|
} // namespace lasx
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_LSX_CPP
|
#define SIMDJSON_SRC_LSX_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -106,6 +107,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
return lsx::stage1::generic_validate_utf8(buf,len);
|
return lsx::stage1::generic_validate_utf8(buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -113,6 +115,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||||
@@ -123,11 +126,13 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return lsx::stringparsing::parse_wobbly_string(src, dst);
|
return lsx::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
} // namespace lsx
|
} // namespace lsx
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_PPC64_CPP
|
#define SIMDJSON_SRC_PPC64_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -112,6 +113,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
return ppc64::stage1::generic_validate_utf8(buf,len);
|
return ppc64::stage1::generic_validate_utf8(buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -119,6 +121,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||||
@@ -129,11 +132,13 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return ppc64::stringparsing::parse_wobbly_string(src, dst);
|
return ppc64::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
} // namespace ppc64
|
} // namespace ppc64
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_RVV_VLS_CPP
|
#define SIMDJSON_SRC_RVV_VLS_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -101,6 +102,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
return rvv_vls::stage1::generic_validate_utf8(buf,len);
|
return rvv_vls::stage1::generic_validate_utf8(buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -108,6 +110,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||||
@@ -118,11 +121,13 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return rvv_vls::stringparsing::parse_wobbly_string(src, dst);
|
return rvv_vls::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
} // namespace rvv_vls
|
} // namespace rvv_vls
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|||||||
+5
-1
@@ -1,5 +1,7 @@
|
|||||||
#define SIMDJSON_SRC_SIMDJSON_CPP
|
#define SIMDJSON_SRC_SIMDJSON_CPP
|
||||||
|
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
|
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
|
|
||||||
SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
|
SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
|
||||||
@@ -13,8 +15,11 @@ SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
|
|||||||
|
|
||||||
#include <simdjson/generic/dependencies.h>
|
#include <simdjson/generic/dependencies.h>
|
||||||
#include <generic/dependencies.h>
|
#include <generic/dependencies.h>
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
#include <generic/stage1/dependencies.h>
|
#include <generic/stage1/dependencies.h>
|
||||||
#include <generic/stage2/dependencies.h>
|
#include <generic/stage2/dependencies.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <implementation.cpp>
|
#include <implementation.cpp>
|
||||||
|
|
||||||
@@ -50,4 +55,3 @@ SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
|
|||||||
#undef SIMDJSON_CONDITIONAL_INCLUDE
|
#undef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
|
SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -2,6 +2,7 @@
|
|||||||
#define SIMDJSON_SRC_WESTMERE_CPP
|
#define SIMDJSON_SRC_WESTMERE_CPP
|
||||||
|
|
||||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#include "simdjson/feature_macros.h"
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
@@ -144,6 +145,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
return westmere::stage1::generic_validate_utf8(buf,len);
|
return westmere::stage1::generic_validate_utf8(buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
}
|
}
|
||||||
@@ -151,6 +153,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document
|
|||||||
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
|
|
||||||
SIMDJSON_NO_SANITIZE_MEMORY
|
SIMDJSON_NO_SANITIZE_MEMORY
|
||||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||||
@@ -161,14 +164,16 @@ simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(con
|
|||||||
return westmere::stringparsing::parse_wobbly_string(src, dst);
|
return westmere::stringparsing::parse_wobbly_string(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_FEATURE_DOM_API
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
return stage2(_doc);
|
return stage2(_doc);
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_FEATURE_DOM_API
|
||||||
} // namespace westmere
|
} // namespace westmere
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#include <simdjson/westmere/end.h>
|
#include <simdjson/westmere/end.h>
|
||||||
|
|
||||||
#endif // SIMDJSON_SRC_WESTMERE_CPP
|
#endif // SIMDJSON_SRC_WESTMERE_CPP
|
||||||
|
|||||||
@@ -29,4 +29,5 @@ add_cpp_test(checkimplementation LABELS other per_implementation)
|
|||||||
|
|
||||||
add_subdirectory(compilation_failure_tests)
|
add_subdirectory(compilation_failure_tests)
|
||||||
add_subdirectory(builder)
|
add_subdirectory(builder)
|
||||||
add_subdirectory(compile_time)
|
add_subdirectory(compile_time)
|
||||||
|
add_subdirectory(feature_flag_tests)
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
# All remaining tests link with simdjson proper
|
# All remaining tests link with simdjson proper
|
||||||
include_directories(..)
|
include_directories(..)
|
||||||
|
if(NOT SIMDJSON_FEATURE_BUILDER_API)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
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_custom_tests LABELS ondemand acceptance per_implementation)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
using namespace simdjson::literals;
|
||||||
|
|
||||||
namespace compile_time_json_tests {
|
namespace compile_time_json_tests {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "simdjson.h"
|
#include "simdjson.h"
|
||||||
|
#include "simdjson/padded_string_view.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
@@ -531,6 +532,35 @@ void simplepad() {
|
|||||||
if(error) { exit(-1); }
|
if(error) { exit(-1); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
|
void simpleinputpad_dom1() {
|
||||||
|
std::string_view json = "[1,2,3]";
|
||||||
|
simdjson::padded_input input(json);
|
||||||
|
dom::parser parser;
|
||||||
|
dom::element doc;
|
||||||
|
auto error = parser.parse(input).get(doc);
|
||||||
|
if(error) { exit(-1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void simpleinputpad_dom2() {
|
||||||
|
const char *jsonpointer = R"(
|
||||||
|
{
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
size_t len = strlen(jsonpointer);
|
||||||
|
simdjson::padded_input input(jsonpointer, len);
|
||||||
|
dom::parser parser;
|
||||||
|
dom::element doc;
|
||||||
|
auto error = parser.parse(input).get(doc);
|
||||||
|
if(error) { exit(-1); }
|
||||||
|
std::string_view val;
|
||||||
|
error = doc["key"].get(val);
|
||||||
|
if(error) { exit(-1); }
|
||||||
|
if(val != "value") { exit(-1); }
|
||||||
|
}
|
||||||
|
#endif // SIMDJSON_CPLUSPLUS17
|
||||||
|
|
||||||
void jsondollar() {
|
void jsondollar() {
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
|
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Feature flag tests: compile and run against the amalgamated single-header file.
|
||||||
|
# Each test uses target_compile_definitions to set its own feature macros,
|
||||||
|
# independent of the project-wide settings.
|
||||||
|
|
||||||
|
set(SINGLEHEADER_DIR ${PROJECT_SOURCE_DIR}/singleheader)
|
||||||
|
|
||||||
|
function(add_feature_flag_test TEST_NAME)
|
||||||
|
cmake_parse_arguments(PARSE_ARGV 1 ARG "" "" "DEFS")
|
||||||
|
add_executable(${TEST_NAME} ${TEST_NAME}.cpp ${SINGLEHEADER_DIR}/simdjson.cpp)
|
||||||
|
target_include_directories(${TEST_NAME} PRIVATE ${SINGLEHEADER_DIR})
|
||||||
|
target_compile_features(${TEST_NAME} PRIVATE cxx_std_17)
|
||||||
|
# Override any inherited feature flag definitions with our own.
|
||||||
|
target_compile_definitions(${TEST_NAME} PRIVATE ${ARG_DEFS})
|
||||||
|
# Remove inherited link libraries (simdjson-internal-flags brings -Werror
|
||||||
|
# which conflicts with the amalgamated header's warning profile).
|
||||||
|
set_target_properties(${TEST_NAME} PROPERTIES LINK_LIBRARIES "")
|
||||||
|
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
|
||||||
|
set_property(TEST ${TEST_NAME} APPEND PROPERTY LABELS feature_flags acceptance)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
add_feature_flag_test(dom_only DEFS
|
||||||
|
SIMDJSON_FEATURE_DOM_API=1 SIMDJSON_FEATURE_ONDEMAND_API=0 SIMDJSON_FEATURE_BUILDER_API=0)
|
||||||
|
# Note: OnDemand tests also enable DOM because the builtin infrastructure
|
||||||
|
# is currently included via the DOM/builtin path in the amalgamated header.
|
||||||
|
add_feature_flag_test(ondemand_only DEFS
|
||||||
|
SIMDJSON_FEATURE_DOM_API=1 SIMDJSON_FEATURE_ONDEMAND_API=1 SIMDJSON_FEATURE_BUILDER_API=0)
|
||||||
|
add_feature_flag_test(dom_and_ondemand DEFS
|
||||||
|
SIMDJSON_FEATURE_DOM_API=1 SIMDJSON_FEATURE_ONDEMAND_API=1 SIMDJSON_FEATURE_BUILDER_API=0)
|
||||||
|
add_feature_flag_test(builder_and_dom DEFS
|
||||||
|
SIMDJSON_FEATURE_DOM_API=1 SIMDJSON_FEATURE_ONDEMAND_API=0 SIMDJSON_FEATURE_BUILDER_API=1)
|
||||||
|
add_feature_flag_test(builder_and_ondemand DEFS
|
||||||
|
SIMDJSON_FEATURE_DOM_API=1 SIMDJSON_FEATURE_ONDEMAND_API=1 SIMDJSON_FEATURE_BUILDER_API=1)
|
||||||
|
add_feature_flag_test(builder_dom_and_ondemand DEFS
|
||||||
|
SIMDJSON_FEATURE_DOM_API=1 SIMDJSON_FEATURE_ONDEMAND_API=1 SIMDJSON_FEATURE_BUILDER_API=1)
|
||||||
|
add_feature_flag_test(builder_only DEFS
|
||||||
|
SIMDJSON_FEATURE_DOM_API=1 SIMDJSON_FEATURE_ONDEMAND_API=0 SIMDJSON_FEATURE_BUILDER_API=1)
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Test: Builder + DOM APIs (OnDemand disabled)
|
||||||
|
// Feature flags set via target_compile_definitions in CMakeLists.txt
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto json = R"({"key": "value"})"_padded;
|
||||||
|
|
||||||
|
// Use DOM API
|
||||||
|
simdjson::dom::parser parser;
|
||||||
|
simdjson::dom::element doc;
|
||||||
|
auto error = parser.parse(json).get(doc);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "DOM parse error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::string_view val;
|
||||||
|
error = doc["key"].get_string().get(val);
|
||||||
|
if (error || val != "value") {
|
||||||
|
std::cerr << "DOM key lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Builder API
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
sb.start_object();
|
||||||
|
sb.append_key_value("greeting", "hello");
|
||||||
|
sb.end_object();
|
||||||
|
std::string_view result;
|
||||||
|
error = sb.view().get(result);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "Builder error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (result != R"({"greeting":"hello"})") {
|
||||||
|
std::cerr << "Builder output mismatch: " << result << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Builder+DOM test passed." << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// Test: Builder + OnDemand APIs (DOM also enabled since Builder depends on it)
|
||||||
|
// Feature flags set via target_compile_definitions in CMakeLists.txt
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Use OnDemand API
|
||||||
|
auto json = R"({"key": "value"})"_padded;
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(json).get(doc);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "OnDemand parse error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::string_view val;
|
||||||
|
error = doc["key"].get_string().get(val);
|
||||||
|
if (error || val != "value") {
|
||||||
|
std::cerr << "OnDemand key lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Builder API
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
sb.start_array();
|
||||||
|
sb.append(1);
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append(2);
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append(3);
|
||||||
|
sb.end_array();
|
||||||
|
std::string_view result;
|
||||||
|
error = sb.view().get(result);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "Builder error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (result != "[1,2,3]") {
|
||||||
|
std::cerr << "Builder output mismatch: " << result << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Builder+OnDemand test passed." << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// Test: All three APIs enabled (Builder + DOM + OnDemand)
|
||||||
|
// Feature flags set via target_compile_definitions in CMakeLists.txt
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto json = R"({"name": "simdjson", "version": 5})"_padded;
|
||||||
|
|
||||||
|
// Use DOM API
|
||||||
|
simdjson::dom::parser dom_parser;
|
||||||
|
simdjson::dom::element dom_doc;
|
||||||
|
auto error = dom_parser.parse(json).get(dom_doc);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "DOM parse error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::string_view name;
|
||||||
|
error = dom_doc["name"].get_string().get(name);
|
||||||
|
if (error || name != "simdjson") {
|
||||||
|
std::cerr << "DOM name lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use OnDemand API
|
||||||
|
simdjson::ondemand::parser od_parser;
|
||||||
|
simdjson::ondemand::document od_doc;
|
||||||
|
error = od_parser.iterate(json).get(od_doc);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "OnDemand parse error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::string_view od_name;
|
||||||
|
error = od_doc["name"].get_string().get(od_name);
|
||||||
|
if (error || od_name != "simdjson") {
|
||||||
|
std::cerr << "OnDemand name lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Builder API
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
sb.start_object();
|
||||||
|
sb.append_key_value("name", "simdjson");
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append_key_value("version", 5);
|
||||||
|
sb.end_object();
|
||||||
|
std::string_view result;
|
||||||
|
error = sb.view().get(result);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "Builder error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (result != R"({"name":"simdjson","version":5})") {
|
||||||
|
std::cerr << "Builder output mismatch: " << result << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Builder+DOM+OnDemand test passed." << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Test: Builder API only (OnDemand disabled, DOM enabled since Builder depends on it)
|
||||||
|
// Feature flags set via target_compile_definitions in CMakeLists.txt
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Use Builder API
|
||||||
|
simdjson::builder::string_builder sb;
|
||||||
|
sb.start_object();
|
||||||
|
sb.append_key_value("count", 2);
|
||||||
|
sb.append_comma();
|
||||||
|
sb.append_key_value("name", "test");
|
||||||
|
sb.end_object();
|
||||||
|
std::string_view result;
|
||||||
|
auto error = sb.view().get(result);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "Builder error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (result != R"({"count":2,"name":"test"})") {
|
||||||
|
std::cerr << "Builder output mismatch: " << result << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Builder-only test passed." << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// Test: Both DOM and OnDemand APIs (Builder disabled)
|
||||||
|
// Feature flags set via target_compile_definitions in CMakeLists.txt
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto json = R"({"key": "value", "number": 42})"_padded;
|
||||||
|
|
||||||
|
// Use DOM API
|
||||||
|
simdjson::dom::parser dom_parser;
|
||||||
|
simdjson::dom::element dom_doc;
|
||||||
|
auto error = dom_parser.parse(json).get(dom_doc);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "DOM parse error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::string_view dom_val;
|
||||||
|
error = dom_doc["key"].get_string().get(dom_val);
|
||||||
|
if (error || dom_val != "value") {
|
||||||
|
std::cerr << "DOM key lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use OnDemand API
|
||||||
|
simdjson::ondemand::parser od_parser;
|
||||||
|
simdjson::ondemand::document od_doc;
|
||||||
|
error = od_parser.iterate(json).get(od_doc);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "OnDemand parse error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::string_view od_val;
|
||||||
|
error = od_doc["key"].get_string().get(od_val);
|
||||||
|
if (error || od_val != "value") {
|
||||||
|
std::cerr << "OnDemand key lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "DOM+OnDemand test passed." << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Test: DOM API only (OnDemand and Builder disabled)
|
||||||
|
// Feature flags set via target_compile_definitions in CMakeLists.txt
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
simdjson::dom::parser parser;
|
||||||
|
auto json = R"({"key": "value", "number": 42})"_padded;
|
||||||
|
simdjson::dom::element doc;
|
||||||
|
auto error = parser.parse(json).get(doc);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "DOM parse error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::string_view val;
|
||||||
|
error = doc["key"].get_string().get(val);
|
||||||
|
if (error || val != "value") {
|
||||||
|
std::cerr << "DOM key lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
int64_t num;
|
||||||
|
error = doc["number"].get_int64().get(num);
|
||||||
|
if (error || num != 42) {
|
||||||
|
std::cerr << "DOM number lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::cout << "DOM-only test passed." << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Test: OnDemand API only (Builder disabled)
|
||||||
|
// Note: DOM must remain enabled because the builtin infrastructure
|
||||||
|
// (SIMDJSON_BUILTIN_IMPLEMENTATION_IS) is currently included via the DOM path.
|
||||||
|
// Feature flags set via target_compile_definitions in CMakeLists.txt
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
auto json = R"({"key": "value", "number": 42})"_padded;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(json).get(doc);
|
||||||
|
if (error) {
|
||||||
|
std::cerr << "OnDemand parse error: " << error << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::string_view val;
|
||||||
|
error = doc["key"].get_string().get(val);
|
||||||
|
if (error || val != "value") {
|
||||||
|
std::cerr << "OnDemand key lookup failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::cout << "OnDemand-only test passed." << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ add_cpp_test(ondemand_convert_tests LABELS ondemand acceptance
|
|||||||
add_cpp_test(ondemand_unknown_tests LABELS ondemand acceptance per_implementation)
|
add_cpp_test(ondemand_unknown_tests LABELS ondemand acceptance per_implementation)
|
||||||
add_cpp_test(ondemand_wildcard_tests LABELS ondemand acceptance per_implementation)
|
add_cpp_test(ondemand_wildcard_tests LABELS ondemand acceptance per_implementation)
|
||||||
if(NOT SIMDJSON_SANITIZE)
|
if(NOT SIMDJSON_SANITIZE)
|
||||||
|
add_cpp_test(ondemand_padded_input LABELS ondemand acceptance per_implementation)
|
||||||
add_cpp_test(ondemand_cacheline LABELS ondemand acceptance per_implementation)
|
add_cpp_test(ondemand_cacheline LABELS ondemand acceptance per_implementation)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ long page_size() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
|
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
|
||||||
// page boundary.
|
// page boundary. Assumes len != 0.
|
||||||
bool need_allocation(const char *buf, size_t len) {
|
bool need_allocation(const char *buf, size_t len) {
|
||||||
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
|
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
|
||||||
+ simdjson::SIMDJSON_PADDING >= static_cast<uintptr_t>(page_size()));
|
+ simdjson::SIMDJSON_PADDING >= static_cast<uintptr_t>(page_size()));
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
#include "simdjson.h"
|
||||||
|
#include "simdjson/padded_string_view.h"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
|
|
||||||
|
bool test_padded_input_from_string_view() {
|
||||||
|
std::string_view json = "[1,2,3]";
|
||||||
|
simdjson::padded_input input(json);
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(input).get(doc);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_from_string_view (iterate error: %s)\n",
|
||||||
|
simdjson::error_message(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t count = 0;
|
||||||
|
for (auto val : doc) {
|
||||||
|
int64_t v;
|
||||||
|
error = val.get_int64().get(v);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_from_string_view (get_int64 error)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (count != 3) {
|
||||||
|
printf("FAILED: test_padded_input_from_string_view (expected 3 elements, got %zu)\n", count);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("OK: test_padded_input_from_string_view\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test_padded_input_from_cstring() {
|
||||||
|
const char *json = R"({"key": "value"})";
|
||||||
|
size_t len = std::strlen(json);
|
||||||
|
simdjson::padded_input input(json, len);
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(input).get(doc);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_from_cstring (iterate error: %s)\n",
|
||||||
|
simdjson::error_message(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string_view val;
|
||||||
|
error = doc["key"].get_string().get(val);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_from_cstring (get_string error)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (val != "value") {
|
||||||
|
printf("FAILED: test_padded_input_from_cstring (expected 'value', got '%.*s')\n",
|
||||||
|
(int)val.size(), val.data());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("OK: test_padded_input_from_cstring\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test_padded_input_is_view() {
|
||||||
|
// A short string at a "safe" position should typically be a view (no copy).
|
||||||
|
// We can't guarantee this in all environments, but we can at least test
|
||||||
|
// that is_view() returns a valid boolean and parsing works either way.
|
||||||
|
std::string_view json = "[1]";
|
||||||
|
simdjson::padded_input input(json);
|
||||||
|
bool view = input.is_view();
|
||||||
|
printf(" is_view() = %s\n", view ? "true" : "false");
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(input).get(doc);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_is_view (iterate error: %s)\n",
|
||||||
|
simdjson::error_message(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("OK: test_padded_input_is_view\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test_padded_input_nested_json() {
|
||||||
|
std::string_view json = R"({"a":{"b":[1,2,{"c":true}]}})";
|
||||||
|
simdjson::padded_input input(json);
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(input).get(doc);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_nested_json (iterate error: %s)\n",
|
||||||
|
simdjson::error_message(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool c_val;
|
||||||
|
error = doc["a"]["b"].at(2)["c"].get_bool().get(c_val);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_nested_json (get_bool error)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!c_val) {
|
||||||
|
printf("FAILED: test_padded_input_nested_json (expected true)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("OK: test_padded_input_nested_json\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test_padded_input_dom() {
|
||||||
|
std::string_view json = "[1,2,3]";
|
||||||
|
simdjson::padded_input input(json);
|
||||||
|
simdjson::dom::parser parser;
|
||||||
|
simdjson::dom::element doc;
|
||||||
|
auto error = parser.parse(input).get(doc);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_dom (parse error: %s)\n",
|
||||||
|
simdjson::error_message(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("OK: test_padded_input_dom\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test_padded_input_dom_object() {
|
||||||
|
const char *json = R"({"name":"simdjson","version":42})";
|
||||||
|
size_t len = std::strlen(json);
|
||||||
|
simdjson::padded_input input(json, len);
|
||||||
|
simdjson::dom::parser parser;
|
||||||
|
simdjson::dom::element doc;
|
||||||
|
auto error = parser.parse(input).get(doc);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_dom_object (parse error: %s)\n",
|
||||||
|
simdjson::error_message(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string_view name;
|
||||||
|
error = doc["name"].get(name);
|
||||||
|
if (error || name != "simdjson") {
|
||||||
|
printf("FAILED: test_padded_input_dom_object (name mismatch)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("OK: test_padded_input_dom_object\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test_padded_input_from_std_string() {
|
||||||
|
std::string json = R"({"key": "value"})";
|
||||||
|
// Reserve extra space to test capacity handling
|
||||||
|
json.reserve(json.size() + 100);
|
||||||
|
simdjson::padded_input input(json);
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(input).get(doc);
|
||||||
|
if (error) {
|
||||||
|
printf("FAILED: test_padded_input_from_std_string (iterate error: %s)\n",
|
||||||
|
simdjson::error_message(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string_view key;
|
||||||
|
error = doc["key"].get(key);
|
||||||
|
if (error || key != "value") {
|
||||||
|
printf("FAILED: test_padded_input_from_std_string (key/value mismatch)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("OK: test_padded_input_from_std_string\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
bool ok = true;
|
||||||
|
ok = test_padded_input_from_string_view() && ok;
|
||||||
|
ok = test_padded_input_from_cstring() && ok;
|
||||||
|
ok = test_padded_input_from_std_string() && ok;
|
||||||
|
ok = test_padded_input_is_view() && ok;
|
||||||
|
ok = test_padded_input_nested_json() && ok;
|
||||||
|
ok = test_padded_input_dom() && ok;
|
||||||
|
ok = test_padded_input_dom_object() && ok;
|
||||||
|
if (ok) {
|
||||||
|
printf("\nAll padded_input tests passed.\n");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
printf("\nSome padded_input tests FAILED.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !SIMDJSON_CPLUSPLUS17
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("padded_input requires C++17 or better. Skipping.\n");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SIMDJSON_CPLUSPLUS17
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "simdjson.h"
|
#include "simdjson.h"
|
||||||
|
#include "simdjson/padded_string_view.h"
|
||||||
#include "test_ondemand.h"
|
#include "test_ondemand.h"
|
||||||
#if __cpp_lib_optional >= 201606L
|
#if __cpp_lib_optional >= 201606L
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -49,6 +50,33 @@ bool simplepad() {
|
|||||||
return error == SUCCESS;
|
return error == SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
|
bool simpleinputpad1() {
|
||||||
|
std::string json = "[1]";
|
||||||
|
simdjson::padded_input padded_json(json);
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc;
|
||||||
|
auto error = parser.iterate(padded_json).get(doc);
|
||||||
|
return error == SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool simpleinputpad2() {
|
||||||
|
const char *jsonpointer = R"(
|
||||||
|
{
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
size_t len = strlen(jsonpointer);
|
||||||
|
|
||||||
|
simdjson::padded_input padded_json(jsonpointer, len);
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc;
|
||||||
|
auto error = parser.iterate(padded_json).get(doc);
|
||||||
|
return error == SUCCESS;
|
||||||
|
}
|
||||||
|
#endif // SIMDJSON_CPLUSPLUS17
|
||||||
|
|
||||||
bool string1() {
|
bool string1() {
|
||||||
const char * data = "my data"; // 7 bytes
|
const char * data = "my data"; // 7 bytes
|
||||||
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
||||||
|
|||||||
Reference in New Issue
Block a user