mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5c9a310cf | |||
| 6d308a08c5 | |||
| 9e477ddb00 | |||
| b7c4d1eeef | |||
| 4a2f10ebcf | |||
| 41cb909604 | |||
| 91908ade4d | |||
| 9a32c48098 | |||
| d996ffc494 | |||
| d56fdc3d04 | |||
| 1dce4fed6e | |||
| cae5e5342f | |||
| 4e609aa955 | |||
| d28e5534d9 |
-42
@@ -1,46 +1,4 @@
|
||||
kind: pipeline
|
||||
name: i386-gcc # we do not support 32-bit systems, but we run tests
|
||||
platform: { os: linux, arch: amd64 }
|
||||
steps:
|
||||
- name: Build and Test
|
||||
image: i386/ubuntu
|
||||
environment:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
|
||||
- apt-get install -y g++ cmake gcc git
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . $BUILD_FLAGS
|
||||
- ctest $CTEST_FLAGS
|
||||
---
|
||||
kind: pipeline
|
||||
name: i386-clang # we do not support 32-bit systems, but we run tests
|
||||
platform: { os: linux, arch: amd64 }
|
||||
steps:
|
||||
- name: Build and Test
|
||||
image: i386/ubuntu
|
||||
environment:
|
||||
CC: clang-6.0
|
||||
CXX: clang++-6.0
|
||||
BUILD_FLAGS: -- -j
|
||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
|
||||
- apt-get install -y clang++-6.0 cmake git
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . $BUILD_FLAGS
|
||||
- ctest $CTEST_FLAGS
|
||||
---
|
||||
kind: pipeline
|
||||
name: gcc9
|
||||
platform: { os: linux, arch: amd64 }
|
||||
steps:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
xcversion select 11.2.1
|
||||
xcversion select 11.7
|
||||
mkdir builddebug &&
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
|
||||
@@ -17,15 +17,9 @@ jobs:
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: Release
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
||||
type: Release
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: Debug
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
|
||||
type: Debug
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
|
||||
@@ -19,15 +19,9 @@ jobs:
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
||||
type: Release
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
|
||||
type: Release
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
|
||||
type: Debug
|
||||
- msystem: "MINGW32"
|
||||
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
|
||||
type: Debug
|
||||
env:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 1.0.0
|
||||
VERSION 1.0.1
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "1.0.0"
|
||||
PROJECT_NUMBER = "1.0.1"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
Vendored
+2
-1
@@ -13,8 +13,9 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
|
||||
if(SIMDJSON_GOOGLE_BENCHMARKS)
|
||||
set_off(BENCHMARK_ENABLE_TESTING)
|
||||
set_off(BENCHMARK_ENABLE_INSTALL)
|
||||
set_off(BENCHMARK_ENABLE_WERROR)
|
||||
|
||||
import_dependency(google_benchmarks google/benchmark 8982e1e)
|
||||
import_dependency(google_benchmarks google/benchmark f91b6b4)
|
||||
add_dependency(google_benchmarks)
|
||||
endif()
|
||||
|
||||
|
||||
+45
-28
@@ -127,19 +127,23 @@ 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)).
|
||||
As required by the standard, your JSON document should be Unicode (UTF-8) strings.
|
||||
As required by the standard, your JSON document should be in a Unicode (UTF-8) string. The whole
|
||||
string, from the beginning to the end, needs to be valid: we do not attempt to tolerate bad
|
||||
inputs before or after a document.
|
||||
|
||||
|
||||
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 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"`):
|
||||
|
||||
```c++
|
||||
ondemand::parser parser;
|
||||
auto json = padded_string::load("twitter.json");
|
||||
auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json'.
|
||||
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
|
||||
```
|
||||
|
||||
Or by creating a padded string---for efficiency reasons, simdjson requires a string with a few
|
||||
bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
|
||||
You can also create a padded string---for efficiency reasons, simdjson requires a string
|
||||
with a few bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
|
||||
|
||||
```c++
|
||||
ondemand::parser parser;
|
||||
@@ -232,12 +236,21 @@ transcode the UTF-8 strings produced by the simdjson library to other formats. S
|
||||
Using the Parsed JSON
|
||||
---------------------
|
||||
|
||||
We recommend that you first compile and run your code in Debug mode (with `NDEBUG`
|
||||
undefined). When you do so, the simdjson library runs additional sanity tests on
|
||||
your code to help ensure that you are using the library in a safe manner. Once
|
||||
your code has been tested, you can then run it in Release mode (with `NDEBUG`
|
||||
defined) for best performance. Alternatively, you can set the macro
|
||||
`SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including the `simdjson.h` header
|
||||
to enable these additional checks: just make sure you remove the definition once your
|
||||
code has been tested.
|
||||
|
||||
Once you have a document (`simdjson::ondemand::document`), you can navigate it with
|
||||
idiomatic C++ iterators, operators and casts. Besides the documents instances and
|
||||
idiomatic C++ iterators, operators and casts. Besides the document instances and
|
||||
native types (`double`, `uint64_t`, `int64_t`, `bool`), we also access
|
||||
Unicode (UTF-8) strings (`std::string_view`), objects (`simdjson::ondemand::object`)
|
||||
and arrays (`simdjson::ondemand::array`).
|
||||
We also have a generic type (`simdjson::ondemand::value`) which represent a potential
|
||||
We also have a generic type (`simdjson::ondemand::value`) which represents a potential
|
||||
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside an array or an object. Both generic types (`simdjson::ondemand::document` and `simdjson::ondemand::value`) have a `type()` method returning
|
||||
a `json_type` value describing the value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`, `json_type::boolean`, `json_type::null`).
|
||||
|
||||
@@ -246,6 +259,7 @@ should review our section [dynamic number types](#dynamic-number-types). Indeed,
|
||||
we have an additional `ondemand::number` type which may represent either integers
|
||||
or floating-point values, depending on how the numbers are formatted.
|
||||
floating-point values followed by an integer.
|
||||
|
||||
While you are accessing the document, the `document` instance should remain in scope:
|
||||
it is your "iterator" which keeps track of where you are in the JSON document.
|
||||
By design, there is one and only one `document` instance per JSON document.
|
||||
@@ -268,7 +282,9 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
||||
scan through the object looking for the field with the matching string, doing a character-by-character
|
||||
comparison. For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance.
|
||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. Furthermore, you can only consume one field at a time, on the same object. Thus
|
||||
if you have retrieved `content["bids"].get_array()` and you later call `content["asks"].get_array()`, then the first array should no longer be accessed: it would be unsafe to do so.
|
||||
You can detect such mistakes by first compiling and running the code in Debug mode: an OUT_OF_ORDER_ITERATION error is generated.
|
||||
|
||||
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
|
||||
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching by default.
|
||||
@@ -683,30 +699,23 @@ auto cars_json = R"( [
|
||||
] )"_padded;
|
||||
|
||||
ondemand::parser parser;
|
||||
ondemand::document cars;
|
||||
std::vector<double> measured;
|
||||
parser.iterate(cars_json).get(cars);
|
||||
ondemand::document cars = parser.iterate(cars_json);
|
||||
std::vector<car_type> content;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ondemand::object obj;
|
||||
std::string json_pointer = "/" + std::to_string(i);
|
||||
// Each successive at_pointer call invalidates
|
||||
// previously parsed values, strings, objects and array.
|
||||
cars.at_pointer(json_pointer).get(obj);
|
||||
ondemand::object obj(cars.at_pointer(json_pointer).get_object());
|
||||
// We materialize the object.
|
||||
std::string_view make;
|
||||
ASSERT_SUCCESS(obj["make"].get(make));
|
||||
std::string_view model;
|
||||
ASSERT_SUCCESS(obj["model"].get(model));
|
||||
uint64_t year;
|
||||
ASSERT_SUCCESS(obj["year"].get(year));
|
||||
std::string_view make = obj["make"];
|
||||
std::string_view model = obj["model"];
|
||||
uint64_t year(obj["year"]);
|
||||
// We materialize the array.
|
||||
ondemand::array arr;
|
||||
ASSERT_SUCCESS(obj["tire_pressure"].get(arr));
|
||||
ondemand::array arr(obj["tire_pressure"].get_array());
|
||||
std::vector<double> values;
|
||||
for(auto x : arr) {
|
||||
double value_double;
|
||||
ASSERT_SUCCESS(x.get(value_double));
|
||||
double value_double(x.get_double());
|
||||
values.push_back(value_double);
|
||||
}
|
||||
content.emplace_back(make, model, year, std::move(values));
|
||||
@@ -1153,11 +1162,19 @@ The `raw_json_token()` should be fast and free of allocation.
|
||||
Newline-Delimited JSON (ndjson) and JSON lines
|
||||
----------------------------------------------
|
||||
|
||||
The simdjson library also supports multithreaded JSON streaming through a large file containing many
|
||||
smaller JSON documents in either [ndjson](http://ndjson.org) or [JSON lines](http://jsonlines.org)
|
||||
format. If your JSON documents all contain arrays or objects, we even support direct file
|
||||
concatenation without whitespace. The concatenated file has no size restrictions (including larger
|
||||
than 4GB), though each individual document must be no larger than 4 GB.
|
||||
When processing large inputs (e.g., in the context of data engineering), engineers commonly
|
||||
serialize data into streams of multiple JSON documents. That is, instead of one large
|
||||
(e.g., 2 GB) JSON document containing multiple records, it is often preferable to
|
||||
write out multiple records as independent JSON documents, to be read one-by-one.
|
||||
|
||||
The simdjson library also supports multithreaded JSON streaming through a large file
|
||||
containing many smaller JSON documents in either [ndjson](http://ndjson.org)
|
||||
or [JSON lines](http://jsonlines.org) format. If your JSON documents all contain arrays
|
||||
or objects, we even support direct file concatenation without whitespace. However, if there
|
||||
is content between your JSON documents, it should be exclusively ASCII white-space characters.
|
||||
|
||||
The concatenated file has no size restrictions (including larger than 4GB), though each
|
||||
individual document must be no larger than 4 GB.
|
||||
|
||||
Here is an example:
|
||||
|
||||
|
||||
+6
-2
@@ -1,7 +1,9 @@
|
||||
iterate_many
|
||||
==========
|
||||
|
||||
An interface providing features to work with files or streams containing multiple small JSON documents. Given an input such as
|
||||
When serializing large databases, it is often better to write out many independent JSON
|
||||
documents, instead of one large monolithic document containing many records. The simdjson
|
||||
library provides high-speed access to files or streams containing multiple small JSON documents separated by ASCII white-space characters. Given an input such as
|
||||
```JSON
|
||||
{"text":"a"}
|
||||
{"text":"b"}
|
||||
@@ -114,7 +116,9 @@ Whitespace Characters:
|
||||
- **Linefeed**
|
||||
- **Carriage return**
|
||||
- **Horizontal tab**
|
||||
- **Nothing**
|
||||
|
||||
If your documents are all objects or arrays, then you may even have nothing between them.
|
||||
E.g., `[1,2]{"32":1}` is recognized as two documents.
|
||||
|
||||
Some official formats **(non-exhaustive list)**:
|
||||
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
|
||||
|
||||
@@ -709,42 +709,6 @@ in production systems:
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Long-Running Processes and Memory Capacity
|
||||
|
||||
The On Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. Similarly to the DOM-based approach (see [here](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#server-loops-long-running-processes-and-memory-capacity)]), On Demand also lets you adjust the maximal capacity that the parser can process:
|
||||
|
||||
* You can set an upper bound (*max_capacity*) when construction the parser:
|
||||
```C++
|
||||
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
|
||||
auto doc = parser.iterate(json);
|
||||
for (web_request request : listen()) {
|
||||
padded_string json;
|
||||
padded_string json = padded_string::load(request.body);
|
||||
auto error = parser.iterate(json);
|
||||
// If the document was above our limit, emit 413 = payload too large
|
||||
if (error == CAPACITY) { request.respond(413); continue; }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The capacity will grow as the parser encounters larger documents up to 1 MB.
|
||||
|
||||
* You can also allocate a *fixed capacity* that will never grow:
|
||||
```C++
|
||||
ondemand::parser parser(1000*1000);
|
||||
parser.allocate(1000*1000) // Fix the capacity to 1 MB
|
||||
auto doc = parser.iterate(json);
|
||||
for (web_request request : listen()) {
|
||||
padded_string json;
|
||||
padded_string json = padded_string::load(request.body);
|
||||
auto error = parser.iterate(json);
|
||||
// If the document was above our limit, emit 413 = payload too large
|
||||
if (error == CAPACITY) { request.respond(413); continue; }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
You can also manually set the maximal capacity using the method `set_max_capacity()`.
|
||||
### Benefits of the On Demand Approach
|
||||
|
||||
We expect that the On Demand approach has many of the performance benefits of the schema-based approach, while providing a flexibility that is similar to that of the DOM-based approach.
|
||||
@@ -764,7 +728,6 @@ There are currently additional technical limitations which we expect to resolve
|
||||
|
||||
* The simdjson library offers runtime dispatching which allows you to compile one binary and have it run at full speed on different processors, taking advantage of the specific features of the processor. The On Demand API has limited runtime dispatch support. Under x64 systems, to fully benefit from the On Demand API, we recommend that you compile your code for a specific processor. E.g., if your processor supports AVX2 instructions, you should compile your binary executable with AVX2 instruction support (by using your compiler's commands). If you are sufficiently technically proficient, you can implement runtime dispatching within your application, by compiling your On Demand code for different processors.
|
||||
* There is an initial phase which scans the entire document quickly, irrespective of the size of the document. We plan to break this phase into distinct steps for large files in a future release as we have done with other components of our API (e.g., `parse_many`).
|
||||
* The On Demand API does not support JSON Pointer. This capability is currently limited to our core API.
|
||||
|
||||
### Applicability of the On Demand Approach
|
||||
|
||||
|
||||
@@ -56,6 +56,43 @@ or simply
|
||||
```
|
||||
|
||||
|
||||
Server Loops: Long-Running Processes and Memory Capacity
|
||||
---------------------------------
|
||||
|
||||
The On Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. On Demand also lets you adjust the maximal capacity that the parser can process:
|
||||
|
||||
* You can set an upper bound (*max_capacity*) when construction the parser:
|
||||
```C++
|
||||
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
|
||||
auto doc = parser.iterate(json);
|
||||
for (web_request request : listen()) {
|
||||
padded_string json;
|
||||
padded_string json = padded_string::load(request.body);
|
||||
auto error = parser.iterate(json);
|
||||
// If the document was above our limit, emit 413 = payload too large
|
||||
if (error == CAPACITY) { request.respond(413); continue; }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The capacity will grow as the parser encounters larger documents up to 1 MB.
|
||||
|
||||
* You can also allocate a *fixed capacity* that will never grow:
|
||||
```C++
|
||||
ondemand::parser parser(1000*1000);
|
||||
parser.allocate(1000*1000) // Fix the capacity to 1 MB
|
||||
auto doc = parser.iterate(json);
|
||||
for (web_request request : listen()) {
|
||||
padded_string json;
|
||||
padded_string json = padded_string::load(request.body);
|
||||
auto error = parser.iterate(json);
|
||||
// If the document was above our limit, emit 413 = payload too large
|
||||
if (error == CAPACITY) { request.respond(413); continue; }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
You can also manually set the maximal capacity using the method `set_max_capacity()`.
|
||||
|
||||
Large files and huge page support
|
||||
---------------------------------
|
||||
|
||||
|
||||
+17
-15
@@ -8,24 +8,26 @@
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
FuzzData fd(Data, Size);
|
||||
const auto batch_size=static_cast<size_t>(fd.getInt<0,1000>());
|
||||
const auto json=simdjson::padded_string{fd.remainder_as_stringview()};
|
||||
const auto batch_size = static_cast<size_t>(fd.getInt<0,1000>());
|
||||
const auto json = simdjson::padded_string{fd.remainder_as_stringview()};
|
||||
simdjson::dom::parser parser;
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
simdjson::dom::document_stream docs;
|
||||
if(parser.parse_many(json,batch_size).get(docs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t bool_count=0;
|
||||
simdjson::dom::document_stream docs;
|
||||
if(parser.parse_many(json,batch_size).get(docs)) { return 0; }
|
||||
size_t bool_count1 = 0;
|
||||
size_t total_count1 = 0;
|
||||
for (auto doc : docs) {
|
||||
bool_count+=doc.is_bool();
|
||||
total_count1++;
|
||||
bool_count1 += doc.is_bool();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
} catch(...) {
|
||||
// Restart, if we made it this far, the document *must* be accessible.
|
||||
if(parser.parse_many(json,batch_size).get(docs)) { return EXIT_FAILURE; }
|
||||
size_t bool_count2 = 0;
|
||||
size_t total_count2 = 0;
|
||||
for (auto doc : docs) {
|
||||
total_count2++;
|
||||
bool_count2 += doc.is_bool();
|
||||
}
|
||||
#endif
|
||||
// They should agree!!!
|
||||
if((total_count2 != total_count1) || (bool_count2 != bool_count1)) { return EXIT_FAILURE; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,10 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
|
||||
size_t i = 0;
|
||||
// Fast path for the case where we have no control character, no ", and no backslash.
|
||||
// This should include most keys.
|
||||
constexpr static bool needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
//
|
||||
// We would like to use 'bool' but some compilers take offense to bitwise operation
|
||||
// with bool types.
|
||||
constexpr static char needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
@@ -169,6 +172,8 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
for(;i + 8 <= unescaped.length(); i += 8) {
|
||||
// Poor's man vectorization. This could get much faster if we used SIMD.
|
||||
//
|
||||
// It is not the case that replacing '|' with '||' would be neutral performance-wise.
|
||||
if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])]
|
||||
| needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])]
|
||||
| needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])]
|
||||
|
||||
@@ -609,7 +609,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
|
||||
}
|
||||
@@ -732,7 +732,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -782,7 +782,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -830,9 +830,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
|
||||
// instance.
|
||||
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
|
||||
return i;
|
||||
|
||||
@@ -527,7 +527,7 @@ simdjson_really_inline simdjson_result<value> document_reference::find_field_uno
|
||||
simdjson_really_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
|
||||
simdjson_really_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
|
||||
simdjson_really_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
|
||||
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); };
|
||||
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
|
||||
simdjson_really_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
|
||||
simdjson_really_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
|
||||
simdjson_really_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
|
||||
@@ -715,4 +715,4 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
}
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -303,6 +303,14 @@ public:
|
||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||
*
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -326,6 +334,13 @@ public:
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -399,7 +414,7 @@ public:
|
||||
* type.
|
||||
*
|
||||
* number.get_number_type() is number_type::signed_integer if we have
|
||||
* a integer in [-9223372036854775808,9223372036854775808)
|
||||
* an integer in [-9223372036854775808,9223372036854775808)
|
||||
* You can recover the value by calling number.get_int64() and you
|
||||
* have that number.is_int64() is true.
|
||||
*
|
||||
@@ -541,6 +556,7 @@ public:
|
||||
simdjson_really_inline document_reference() noexcept;
|
||||
simdjson_really_inline document_reference(document &d) noexcept;
|
||||
simdjson_really_inline document_reference(const document_reference &other) noexcept = default;
|
||||
simdjson_really_inline document_reference& operator=(const document_reference &other) noexcept = default;
|
||||
simdjson_really_inline void rewind() noexcept;
|
||||
simdjson_really_inline simdjson_result<array> get_array() & noexcept;
|
||||
simdjson_really_inline simdjson_result<object> get_object() & noexcept;
|
||||
|
||||
@@ -37,6 +37,13 @@ public:
|
||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -63,6 +70,13 @@ public:
|
||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||
* that only one field is returned.
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
|
||||
@@ -54,6 +54,11 @@ public:
|
||||
* ondemand::parser parser;
|
||||
* document doc = parser.iterate(json);
|
||||
*
|
||||
* It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
|
||||
* Otherwise the iterate method may return an error. In particular, the whole input should be
|
||||
* valid: we do not attempt to tolerate incorrect content either before or after a JSON
|
||||
* document.
|
||||
*
|
||||
* ### IMPORTANT: Validate what you use
|
||||
*
|
||||
* Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
|
||||
@@ -166,13 +171,15 @@ public:
|
||||
* ### Format
|
||||
*
|
||||
* The buffer must contain a series of one or more JSON documents, concatenated into a single
|
||||
* buffer, separated by whitespace. It effectively parses until it has a fully valid document,
|
||||
* buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
|
||||
* then starts parsing the next document at that point. (It does this with more parallelism and
|
||||
* lookahead than you might think, though.)
|
||||
*
|
||||
* documents that consist of an object or array may omit the whitespace between them, concatenating
|
||||
* with no separator. documents that consist of a single primitive (i.e. documents that are not
|
||||
* arrays or objects) MUST be separated with whitespace.
|
||||
* with no separator. Documents that consist of a single primitive (i.e. documents that are not
|
||||
* arrays or objects) MUST be separated with ASCII whitespace.
|
||||
*
|
||||
* The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
|
||||
*
|
||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
||||
|
||||
@@ -375,7 +375,7 @@ public:
|
||||
* type.
|
||||
*
|
||||
* number.get_number_type() is number_type::signed_integer if we have
|
||||
* a integer in [-9223372036854775808,9223372036854775808)
|
||||
* an integer in [-9223372036854775808,9223372036854775808)
|
||||
* You can recover the value by calling number.get_int64() and you
|
||||
* have that number.is_int64() is true.
|
||||
*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION 1.0.0
|
||||
#define SIMDJSON_VERSION 1.0.1
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
@@ -19,7 +19,7 @@ enum {
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 0
|
||||
SIMDJSON_VERSION_REVISION = 1
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ int main(int argc, char *argv[]) {
|
||||
std::cerr << "Please specify at least one file name and" << std::endl;
|
||||
std::cerr << "up to two files." << std::endl;
|
||||
std::cerr << "The first file should be a JSON document." << std::endl;
|
||||
std::cerr << "The secod file should container many JSON documents."
|
||||
std::cerr << "The second file should container many JSON documents."
|
||||
<< std::endl;
|
||||
std::cerr << "Try the test files: jsonexamples/twitter.json "
|
||||
"jsonexamples/amazon_cellphones.ndjson"
|
||||
@@ -39,7 +39,7 @@ int main(int argc, char *argv[]) {
|
||||
std::cout << error << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "document has the following type at the root: " << type
|
||||
std::cout << "if valid, the document has the following type at the root: " << type
|
||||
<< std::endl;
|
||||
|
||||
if (argc == 2) {
|
||||
@@ -73,8 +73,9 @@ int main(int argc, char *argv[]) {
|
||||
std::cout << error << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
std::cout << "iterate_many valid" << std::endl;
|
||||
std::cout << "found " << counter << " documents" << std::endl;
|
||||
std::cout << "I found " << counter << " potential JSON documents." << std::endl;
|
||||
}
|
||||
std::cout << "For more information on how simdjson works, please refer to our documentation." << std::endl;
|
||||
std::cout << "https://github.com/simdjson/simdjson/blob/master/doc/basics.md" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2021-09-07 14:34:40 -0400. Do not edit! */
|
||||
/* auto-generated on 2021-10-20 12:15:35 -0400. Do not edit! */
|
||||
/* begin file src/simdjson.cpp */
|
||||
#include "simdjson.h"
|
||||
|
||||
|
||||
+87
-35
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2021-09-07 14:34:40 -0400. Do not edit! */
|
||||
/* auto-generated on 2021-10-20 12:15:35 -0400. Do not edit! */
|
||||
/* begin file include/simdjson.h */
|
||||
#ifndef SIMDJSON_H
|
||||
#define SIMDJSON_H
|
||||
@@ -2189,7 +2189,7 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION 1.0.0
|
||||
#define SIMDJSON_VERSION 1.0.1
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
@@ -2204,7 +2204,7 @@ enum {
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 0
|
||||
SIMDJSON_VERSION_REVISION = 1
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -8995,7 +8995,10 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
|
||||
size_t i = 0;
|
||||
// Fast path for the case where we have no control character, no ", and no backslash.
|
||||
// This should include most keys.
|
||||
constexpr static bool needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
//
|
||||
// We would like to use 'bool' but some compilers take offense to bitwise operation
|
||||
// with bool types.
|
||||
constexpr static char needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
@@ -9007,6 +9010,8 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
for(;i + 8 <= unescaped.length(); i += 8) {
|
||||
// Poor's man vectorization. This could get much faster if we used SIMD.
|
||||
//
|
||||
// It is not the case that replacing '|' with '||' would be neutral performance-wise.
|
||||
if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])]
|
||||
| needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])]
|
||||
| needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])]
|
||||
@@ -11264,7 +11269,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
|
||||
}
|
||||
@@ -11387,7 +11392,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -11437,7 +11442,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -11485,9 +11490,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
|
||||
// instance.
|
||||
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
|
||||
return i;
|
||||
@@ -13095,7 +13102,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
|
||||
}
|
||||
@@ -13218,7 +13225,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -13268,7 +13275,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -13316,9 +13323,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
|
||||
// instance.
|
||||
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
|
||||
return i;
|
||||
@@ -15411,7 +15420,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
|
||||
}
|
||||
@@ -15534,7 +15543,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -15584,7 +15593,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -15632,9 +15641,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
|
||||
// instance.
|
||||
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
|
||||
return i;
|
||||
@@ -17826,7 +17837,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
|
||||
}
|
||||
@@ -17949,7 +17960,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -17999,7 +18010,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -18047,9 +18058,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
|
||||
// instance.
|
||||
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
|
||||
return i;
|
||||
@@ -20099,7 +20112,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
|
||||
}
|
||||
@@ -20222,7 +20235,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -20272,7 +20285,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
@@ -20320,9 +20333,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
|
||||
// - That is smaller than the smallest possible 20-digit number the user could write:
|
||||
// 10,000,000,000,000,000,000.
|
||||
// - Therefore, if the number is positive and lower than that, it's overflow.
|
||||
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
|
||||
// - The value we are looking at is less than or equal to INT64_MAX.
|
||||
//
|
||||
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
|
||||
// instance.
|
||||
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
|
||||
}
|
||||
|
||||
return i;
|
||||
@@ -22888,6 +22903,14 @@ public:
|
||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||
*
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -22911,6 +22934,13 @@ public:
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -22984,7 +23014,7 @@ public:
|
||||
* type.
|
||||
*
|
||||
* number.get_number_type() is number_type::signed_integer if we have
|
||||
* a integer in [-9223372036854775808,9223372036854775808)
|
||||
* an integer in [-9223372036854775808,9223372036854775808)
|
||||
* You can recover the value by calling number.get_int64() and you
|
||||
* have that number.is_int64() is true.
|
||||
*
|
||||
@@ -23126,6 +23156,7 @@ public:
|
||||
simdjson_really_inline document_reference() noexcept;
|
||||
simdjson_really_inline document_reference(document &d) noexcept;
|
||||
simdjson_really_inline document_reference(const document_reference &other) noexcept = default;
|
||||
simdjson_really_inline document_reference& operator=(const document_reference &other) noexcept = default;
|
||||
simdjson_really_inline void rewind() noexcept;
|
||||
simdjson_really_inline simdjson_result<array> get_array() & noexcept;
|
||||
simdjson_really_inline simdjson_result<object> get_object() & noexcept;
|
||||
@@ -23684,7 +23715,7 @@ public:
|
||||
* type.
|
||||
*
|
||||
* number.get_number_type() is number_type::signed_integer if we have
|
||||
* a integer in [-9223372036854775808,9223372036854775808)
|
||||
* an integer in [-9223372036854775808,9223372036854775808)
|
||||
* You can recover the value by calling number.get_int64() and you
|
||||
* have that number.is_int64() is true.
|
||||
*
|
||||
@@ -24050,6 +24081,13 @@ public:
|
||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -24076,6 +24114,13 @@ public:
|
||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||
* that only one field is returned.
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
@@ -24271,6 +24316,11 @@ public:
|
||||
* ondemand::parser parser;
|
||||
* document doc = parser.iterate(json);
|
||||
*
|
||||
* It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
|
||||
* Otherwise the iterate method may return an error. In particular, the whole input should be
|
||||
* valid: we do not attempt to tolerate incorrect content either before or after a JSON
|
||||
* document.
|
||||
*
|
||||
* ### IMPORTANT: Validate what you use
|
||||
*
|
||||
* Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
|
||||
@@ -24383,13 +24433,15 @@ public:
|
||||
* ### Format
|
||||
*
|
||||
* The buffer must contain a series of one or more JSON documents, concatenated into a single
|
||||
* buffer, separated by whitespace. It effectively parses until it has a fully valid document,
|
||||
* buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
|
||||
* then starts parsing the next document at that point. (It does this with more parallelism and
|
||||
* lookahead than you might think, though.)
|
||||
*
|
||||
* documents that consist of an object or array may omit the whitespace between them, concatenating
|
||||
* with no separator. documents that consist of a single primitive (i.e. documents that are not
|
||||
* arrays or objects) MUST be separated with whitespace.
|
||||
* with no separator. Documents that consist of a single primitive (i.e. documents that are not
|
||||
* arrays or objects) MUST be separated with ASCII whitespace.
|
||||
*
|
||||
* The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
|
||||
*
|
||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
||||
@@ -27789,7 +27841,7 @@ simdjson_really_inline simdjson_result<value> document_reference::find_field_uno
|
||||
simdjson_really_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
|
||||
simdjson_really_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
|
||||
simdjson_really_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
|
||||
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); };
|
||||
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
|
||||
simdjson_really_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
|
||||
simdjson_really_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
|
||||
simdjson_really_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
|
||||
|
||||
@@ -858,7 +858,24 @@ namespace document_stream_tests {
|
||||
for (auto doc : docs) {
|
||||
bool_count += doc.is_bool();
|
||||
}
|
||||
return true;
|
||||
return (bool_count == 0);
|
||||
}
|
||||
|
||||
bool fuzzaccess() {
|
||||
std::cout << "Running " << __func__ << std::endl;
|
||||
// Issue 38801 in oss-fuzz
|
||||
auto json = "\xff \n~~\n{}"_padded;
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::document_stream docs;
|
||||
ASSERT_SUCCESS(parser.parse_many(json).get(docs));
|
||||
size_t bool_count = 0;
|
||||
size_t total_count = 0;
|
||||
|
||||
for (auto doc : docs) {
|
||||
total_count++;
|
||||
bool_count += doc.is_bool();
|
||||
}
|
||||
return (bool_count == 0) && (total_count == 1);
|
||||
}
|
||||
|
||||
bool baby_fuzzer() {
|
||||
@@ -892,7 +909,8 @@ namespace document_stream_tests {
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return baby_fuzzer() &&
|
||||
return fuzzaccess() &&
|
||||
baby_fuzzer() &&
|
||||
issue1649() &&
|
||||
adversarial_single_document_array() &&
|
||||
adversarial_single_document() &&
|
||||
|
||||
@@ -179,7 +179,6 @@ static bool has_extension(const char *filename, const char *extension) {
|
||||
|
||||
bool validate(const char *dirname) {
|
||||
parse_error = 0;
|
||||
size_t total_count = 0;
|
||||
const char *extension = ".json";
|
||||
size_t dirlen = std::strlen(dirname);
|
||||
struct dirent **entry_list;
|
||||
@@ -215,7 +214,6 @@ bool validate(const char *dirname) {
|
||||
float_count = 0;
|
||||
int_count = 0;
|
||||
invalid_count = 0;
|
||||
total_count += float_count + int_count + invalid_count;
|
||||
simdjson::dom::parser parser;
|
||||
auto err = parser.parse(p).error();
|
||||
bool isok = (err == simdjson::error_code::SUCCESS);
|
||||
|
||||
@@ -9,10 +9,190 @@ namespace document_stream_tests {
|
||||
bool process_doc(T &docref) {
|
||||
int64_t val;
|
||||
ASSERT_SUCCESS(docref.at_pointer("/4").get(val));
|
||||
//ASSERT_SUCCESS(err);
|
||||
ASSERT_EQUAL(val, 5);
|
||||
return true;
|
||||
}
|
||||
bool truncated_utf8() {
|
||||
TEST_START();
|
||||
// truncated UTF-8
|
||||
auto json = "\"document1\" \xC3"_padded;
|
||||
|
||||
ondemand::parser parser;
|
||||
ondemand::document_stream stream;
|
||||
auto oderror = parser.iterate_many(json).get(stream);
|
||||
if (oderror) {
|
||||
std::cerr << "ondemand iterate_many error: " << oderror << std::endl;
|
||||
return false;
|
||||
}
|
||||
int document_index = 0;
|
||||
auto i = stream.begin();
|
||||
for (; i != stream.end(); ++i) {
|
||||
ondemand::document_reference doc;
|
||||
auto err = (*i).get(doc);
|
||||
document_index++;
|
||||
// With the fallback routine, we might detect a 'document' since
|
||||
// it does not do UTF-8 validation in stage one, but it will do
|
||||
// so when we access the document.
|
||||
if(err == SUCCESS) {
|
||||
ondemand::json_type t;
|
||||
err = doc.type().get(t);
|
||||
}
|
||||
if((err == SUCCESS) && (document_index != 1)) {
|
||||
std::cerr << "Only the first document should be valid." << std::endl;
|
||||
return false;
|
||||
}
|
||||
if((err != SUCCESS) && (document_index != 2)) {
|
||||
std::cerr << "ondemand iterate_many error: " << err << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(document_index < 1) {
|
||||
std::cerr << "ondemand should have accessed at least one document" << std::endl;
|
||||
return false;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool issue1729() {
|
||||
// This example is not a good application of iterate_many since there is
|
||||
// a single JSON document.
|
||||
TEST_START();
|
||||
auto json = R"({
|
||||
"t": 5649,
|
||||
"ng": 5,
|
||||
"lu": 4086,
|
||||
"g": [{
|
||||
"t": "Temps",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 3,
|
||||
"l": [
|
||||
"Low Temp",
|
||||
"High Temp",
|
||||
"Smooth Avg"
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan"
|
||||
],
|
||||
"d": [
|
||||
80.48750305,
|
||||
80.82499694,
|
||||
80.65625
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": "Pump Status",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 3,
|
||||
"l": [
|
||||
"Pump",
|
||||
"Thermal",
|
||||
"Light"
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan"
|
||||
],
|
||||
"d": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": "Lux",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 4,
|
||||
"l": [
|
||||
"Value",
|
||||
"Smooth",
|
||||
"Low",
|
||||
"High"
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan",
|
||||
"yellow"
|
||||
],
|
||||
"d": [
|
||||
2274.62939453,
|
||||
2277.45947265,
|
||||
4050,
|
||||
4500
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": "Temp Diff",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 4,
|
||||
"l": [
|
||||
"dFarenheit",
|
||||
"sum",
|
||||
"Low",
|
||||
"High"
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan",
|
||||
"yellow"
|
||||
],
|
||||
"d": [
|
||||
0,
|
||||
0,
|
||||
0.5,
|
||||
10
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": "Power",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 3,
|
||||
"l": [
|
||||
"watts (est. ligth) ",
|
||||
"watts (1.9~gpm) ",
|
||||
"watts (1gpm) "
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan"
|
||||
],
|
||||
"d": [
|
||||
181.78063964,
|
||||
114.88922882,
|
||||
59.35943603
|
||||
]
|
||||
}
|
||||
]
|
||||
})"_padded;
|
||||
|
||||
ondemand::parser parser;
|
||||
ondemand::document_stream stream;
|
||||
auto oderror = parser.iterate_many(json).get(stream);
|
||||
if (oderror) {
|
||||
std::cerr << "ondemand iterate_many error: " << oderror << std::endl;
|
||||
return false;
|
||||
}
|
||||
auto i = stream.begin();
|
||||
for (; i != stream.end(); ++i) {
|
||||
ondemand::document_reference doc;
|
||||
auto err = (*i).get(doc);
|
||||
if(err != SUCCESS) {
|
||||
std::cerr << "ondemand iterate_many error: " << err << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool issue1683() {
|
||||
TEST_START();
|
||||
@@ -511,8 +691,34 @@ namespace document_stream_tests {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool fuzzaccess() {
|
||||
TEST_START();
|
||||
// Issue 38801 in oss-fuzz
|
||||
auto json = "\xff \n~~\n{}"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document_stream docs;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(docs));
|
||||
size_t bool_count = 0;
|
||||
size_t total_count = 0;
|
||||
for (auto doc : docs) {
|
||||
total_count++;
|
||||
bool b;
|
||||
if(doc.get_bool().get(b) == SUCCESS) { bool_count +=b; }
|
||||
// If we don't access the document at all, other than get_bool(),
|
||||
// then some simdjson kernels will allow you to iterate through
|
||||
// 3 'documents'. By asking for the type, we make the iteration
|
||||
// terminate after the first 'document'.
|
||||
ondemand::json_type t;
|
||||
if(doc.type().get(t) != SUCCESS) { break; }
|
||||
}
|
||||
return (bool_count == 0) && (total_count == 1);
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
truncated_utf8() &&
|
||||
issue1729() &&
|
||||
fuzzaccess() &&
|
||||
issue1683() &&
|
||||
issue1668() &&
|
||||
issue1668_long() &&
|
||||
|
||||
@@ -346,8 +346,49 @@ namespace json_pointer_tests {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool json_pointer_invalidation_exceptions() {
|
||||
TEST_START();
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
|
||||
ondemand::parser parser;
|
||||
std::vector<double> measured;
|
||||
ondemand::document cars = parser.iterate(cars_json);
|
||||
std::vector<car_type> content;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::string json_pointer = "/" + std::to_string(i);
|
||||
// Each successive at_pointer call invalidates
|
||||
// previously parsed values, strings, objects and array.
|
||||
ondemand::object obj(cars.at_pointer(json_pointer).get_object());
|
||||
// We materialize the object.
|
||||
std::string_view make = obj["make"];
|
||||
std::string_view model = obj["model"];
|
||||
uint64_t year(obj["year"]);
|
||||
// We materialize the array.
|
||||
ondemand::array arr(obj["tire_pressure"].get_array());
|
||||
std::vector<double> values;
|
||||
for(auto x : arr) {
|
||||
double value_double(x.get_double());
|
||||
values.push_back(value_double);
|
||||
}
|
||||
content.emplace_back(make, model, year, std::move(values));
|
||||
}
|
||||
std::string expected[] = {"Toyota", "Kia", "Toyota"};
|
||||
for (car_type c : content) {
|
||||
std::cout << c.make << " " << c.model << " " << c.year << "\n";
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
json_pointer_invalidation_exceptions() &&
|
||||
#endif
|
||||
many_json_pointers_array() &&
|
||||
many_json_pointers_object() &&
|
||||
many_json_pointers_object_array() &&
|
||||
|
||||
@@ -54,12 +54,12 @@ namespace number_in_string_tests {
|
||||
|
||||
bool array_int() {
|
||||
TEST_START();
|
||||
auto json = R"(["1", "2", "-3", "1000", "-7844"])"_padded;
|
||||
auto json = R"(["1", "2", "-3", "1000", "-7844", "-9223372036854775807", "9223372036854775807"])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t counter{0};
|
||||
std::vector<int> expected = {1, 2, -3, 1000, -7844};
|
||||
std::vector<int64_t> expected = {1, 2, -3, 1000, -7844, INT64_C(-9223372036854775807), INT64_C(9223372036854775807) };
|
||||
int64_t i;
|
||||
for (auto value : doc) {
|
||||
ASSERT_SUCCESS(value.get_int64_in_string().get(i));
|
||||
@@ -70,12 +70,12 @@ namespace number_in_string_tests {
|
||||
|
||||
bool array_unsigned() {
|
||||
TEST_START();
|
||||
auto json = R"(["1", "2", "24", "9000", "156934"])"_padded;
|
||||
auto json = R"(["1", "2", "24", "9000", "156934", "10588030077111859193", "18446744073709551615"])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t counter{0};
|
||||
std::vector<int> expected = {1, 2, 24, 9000, 156934};
|
||||
std::vector<uint64_t> expected = {1, 2, 24, 9000, 156934, UINT64_C(10588030077111859193), UINT64_C(18446744073709551615)};
|
||||
uint64_t u;
|
||||
for (auto value : doc) {
|
||||
ASSERT_SUCCESS(value.get_uint64_in_string().get(u));
|
||||
@@ -86,7 +86,7 @@ namespace number_in_string_tests {
|
||||
|
||||
bool object() {
|
||||
TEST_START();
|
||||
auto json = R"({"a":"1.2", "b":"-2.342e2", "c":"22", "d":"-112358", "e":"1080", "f":"123456789"})"_padded;
|
||||
auto json = R"({"a":"1.2", "b":"-2.342e2", "c":"22", "d":"-112358", "e":"1080", "f":"123456789", "g":"10588030077111859193"})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
@@ -110,6 +110,8 @@ namespace number_in_string_tests {
|
||||
ASSERT_EQUAL(u,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.find_field("f").get_uint64_in_string().get(u));
|
||||
ASSERT_EQUAL(u,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.find_field("g").get_uint64_in_string().get(u));
|
||||
ASSERT_EQUAL(u, UINT64_C(10588030077111859193));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,61 @@ using namespace simdjson;
|
||||
namespace object_tests {
|
||||
using namespace std;
|
||||
using simdjson::ondemand::json_type;
|
||||
|
||||
bool issue1723() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::padded_string docdata = R"({
|
||||
"contents":
|
||||
{
|
||||
"bids":[
|
||||
{"offset":"1", "price":"1.1", "size":"4.1"}
|
||||
],
|
||||
"asks":[
|
||||
{"offset":"1111", "price":"1.100", "size":"114.1"}
|
||||
]
|
||||
|
||||
}
|
||||
})"_padded;
|
||||
simdjson::ondemand::document doc;
|
||||
auto error = parser.iterate(docdata).get(doc);
|
||||
if(error) { return false; }
|
||||
ondemand::object content;
|
||||
error = doc.get_object().find_field("contents").get(content);
|
||||
if(error) { return false; }
|
||||
ondemand::array bids;
|
||||
error = content["bids"].get_array().get(bids);
|
||||
if(error) { return false; }
|
||||
for (auto aux : bids) {
|
||||
uint64_t id;
|
||||
error = aux["offset"].get_uint64_in_string().get(id);
|
||||
if(error) { return false; }
|
||||
double price;
|
||||
error = aux["price"].get_double_in_string().get(price);
|
||||
if(error) { return false; }
|
||||
double size;
|
||||
error = aux["size"].get_double_in_string().get(size);
|
||||
if(error) { return false; }
|
||||
std::cout << id << " " << price << " " << size << std::endl;
|
||||
}
|
||||
ondemand::array asks;
|
||||
error = content["asks"].get_array().get(asks);
|
||||
if(error) { return false; }
|
||||
for (auto aux : asks) {
|
||||
uint64_t id;
|
||||
error = aux["offset"].get_uint64_in_string().get(id);
|
||||
if(error) { return false; }
|
||||
double price;
|
||||
error = aux["price"].get_double_in_string().get(price);
|
||||
if(error) { return false; }
|
||||
double size;
|
||||
error = aux["size"].get_double_in_string().get(size);
|
||||
if(error) { return false; }
|
||||
std::cout << id << " " << price << " " << size << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// In this test, no non-trivial object in an array have a missing key
|
||||
bool no_missing_keys() {
|
||||
TEST_START();
|
||||
@@ -123,6 +178,42 @@ namespace object_tests {
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool issue1723_except() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::padded_string docdata = R"({
|
||||
"contents":
|
||||
{
|
||||
"bids":[
|
||||
{"offset":"1", "price":"1.1", "size":"4.1"}
|
||||
],
|
||||
"asks":[
|
||||
{"offset":"1111", "price":"1.100", "size":"114.1"}
|
||||
]
|
||||
|
||||
}
|
||||
})"_padded;
|
||||
simdjson::ondemand::document doc = parser.iterate(docdata);
|
||||
ondemand::object content = doc.get_object().find_field("contents");
|
||||
ondemand::array bids = content["bids"].get_array();
|
||||
std::cout << "bids:" << std::endl;
|
||||
for (auto aux : bids) {
|
||||
uint64_t id = aux["offset"].get_uint64_in_string();
|
||||
double price = aux["price"].get_double_in_string();
|
||||
double size = aux["size"].get_double_in_string();
|
||||
std::cout << id << " " << price << " " << size << std::endl;
|
||||
}
|
||||
ondemand::array asks = content["asks"].get_array();
|
||||
std::cout << "asks:" << std::endl;
|
||||
for (auto aux : asks) {
|
||||
uint64_t id = aux["offset"].get_uint64_in_string();
|
||||
double price = aux["price"].get_double_in_string();
|
||||
double size = aux["size"].get_double_in_string();
|
||||
std::cout << id << " " << price << " " << size << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// used in issue_1521
|
||||
// difficult to use as a lambda because it is recursive.
|
||||
void broken_descend(ondemand::object node) {
|
||||
@@ -824,12 +915,14 @@ namespace object_tests {
|
||||
|
||||
bool run() {
|
||||
return
|
||||
issue1723() &&
|
||||
value_search_unescaped_key() &&
|
||||
missing_key_continue() &&
|
||||
no_missing_keys() &&
|
||||
missing_keys() &&
|
||||
missing_keys_for_empty_top_level_object() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
issue1723_except() &&
|
||||
fixed_broken_issue_1521() &&
|
||||
issue_1521() &&
|
||||
broken_issue_1521() &&
|
||||
|
||||
Reference in New Issue
Block a user