Compare commits

...

13 Commits

Author SHA1 Message Date
Daniel Lemire 0d2455029d Preparing patch release. 2022-11-23 10:59:48 -05:00
Daniel Lemire e94f027310 Serialize 0 as 0.0 (#1921)
* Serialize 0 as 0.0

* Extending the '.0'.
2022-11-23 10:31:42 -05:00
sean 2b766e4c09 Fix: Add padded_string_view overload for parser::parse (#1916) 2022-11-23 09:22:39 -05:00
Daniel Lemire a5db75e1a6 Adding more development checks to the DOM front-end (#1915)
* This adds SIMDJSON_DEVELOPMENT_CHECKS to the DOM API to help users
in the scenario of issue 1914.

* More documentation and warnings.

* Updating following comments by Tyson
2022-10-17 09:11:09 -04:00
Daniel Lemire 4bd66cb891 We branch on GCC for performance. (#1913) 2022-10-16 13:15:35 -04:00
Daniel Lemire 960a7ebba1 Switching to iterate_many 2022-10-06 11:59:12 -04:00
Daniel Lemire d520062f8e Bumping API 2022-10-06 11:50:33 -04:00
Daniel Lemire db08d78ed0 Documents better the type method and makes is_null return an error condition in some instances (#1909) 2022-10-06 11:47:40 -04:00
Daniel Lemire 46292b8d4b Update basics.md 2022-10-05 08:50:52 -04:00
Tyson Andre 46241287c6 Check for trailing tokens in json2msgpack ondemand benchmark (#1908)
Related to #1904

Users of the simdjson library will see json2msgpack as an available
example of how to recursively process json with the ondemand parser,
and checking for trailing tokens in a document is one part of json validation.

These checks shouldn't affect benchmark results performance.
The benchmark is run on the 631KB twitter.json file.
2022-10-05 08:49:09 -04:00
Daniel Lemire 137cb14bcc Documenting how one can check for the end of the document. (#1907) 2022-10-04 20:23:52 -04:00
Daniel Lemire 5e6be3ed7a Minor fix (documentation and safety) regarding max. depth in ondemand. (#1906) 2022-10-04 12:24:20 -04:00
Tyson Andre c6ab52eebb [skip ci] Add an .editorconfig for .cpp/.h/.md for whitespace settings (#1901)
Make it less likely to accidentally introduce tabs, trailing whitespace,
carriage returns, non-utf8 in files, or files without trailing newlines.

https://editorconfig.org/ has plugins for various editors/IDEs and is
enabled by default in some IDEs.
2022-10-03 11:14:00 -04:00
38 changed files with 451 additions and 191 deletions
+12
View File
@@ -0,0 +1,12 @@
# https://editorconfig.org/
root = true
# Conservatively avoid changing defaults for other file types, e.g. raw json files for test cases,
# Makefiles, etc.
[*.{cpp,h,md}]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
tab_width = 2
trim_trailing_whitespace = true
+1
View File
@@ -78,6 +78,7 @@
.gitattributes export-ignore .gitattributes export-ignore
.gitignore export-ignore .gitignore export-ignore
.editorconfig export-ignore
# Sources # Sources
*.c text eol=lf diff=c *.c text eol=lf diff=c
-34
View File
@@ -1,34 +0,0 @@
name: Macos (Xcode 11)
on: [push, pull_request]
jobs:
macos-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
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 .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cd .. &&
mkdir build &&
cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
+3 -3
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project( project(
simdjson simdjson
# The version number is modified by tools/release.py # The version number is modified by tools/release.py
VERSION 2.2.3 VERSION 3.0.1
DESCRIPTION "Parsing gigabytes of JSON per second" DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/" HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ---- # ---- Options, variables ----
# These version numbers are modified by tools/release.py # These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "13.0.0" CACHE STRING "simdjson library version") set(SIMDJSON_LIB_VERSION "14.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "13" CACHE STRING "simdjson library soversion") set(SIMDJSON_LIB_SOVERSION "14" CACHE STRING "simdjson library soversion")
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON) option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = "2.2.3" PROJECT_NUMBER = "3.0.1"
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
+1 -1
View File
@@ -3,7 +3,7 @@
[![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html) [![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html)
![VS16-CI](https://github.com/simdjson/simdjson/workflows/VS16-CI/badge.svg) ![VS16-CI](https://github.com/simdjson/simdjson/workflows/VS16-CI/badge.svg)
![MinGW64-CI](https://github.com/simdjson/simdjson/workflows/MinGW64-CI/badge.svg) ![MinGW64-CI](https://github.com/simdjson/simdjson/workflows/MinGW64-CI/badge.svg)
[![][license img]][license] [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.org/api/2.0.0/index.html) [![][license img]][license] [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.org/api/3.0.0/index.html)
simdjson : Parsing gigabytes of JSON per second simdjson : Parsing gigabytes of JSON per second
=============================================== ===============================================
+72 -3
View File
@@ -51,6 +51,7 @@ private:
simdjson_inline void simdjson_inline void
write_raw_string(simdjson::ondemand::raw_json_string rjs); write_raw_string(simdjson::ondemand::raw_json_string rjs);
inline void recursive_processor(simdjson::ondemand::value element); inline void recursive_processor(simdjson::ondemand::value element);
inline void recursive_processor_ref(simdjson::ondemand::value& element);
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
uint8_t *buff{}; uint8_t *buff{};
@@ -74,17 +75,34 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
write_byte(0xc2 + doc.get_bool()); write_byte(0xc2 + doc.get_bool());
break; break;
case simdjson::ondemand::json_type::null: case simdjson::ondemand::json_type::null:
write_byte(0xc0); // We check that the value is indeed null
// otherwise: an error is thrown.
if(doc.is_null()) {
write_byte(0xc0);
}
break; break;
case simdjson::ondemand::json_type::array: case simdjson::ondemand::json_type::array:
case simdjson::ondemand::json_type::object: case simdjson::ondemand::json_type::object:
default: default:
// impossible // impossible
break; SIMDJSON_UNREACHABLE();
} }
} else { } else {
simdjson::ondemand::value val = doc; simdjson::ondemand::value val = doc;
#define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER))
#if SIMDJSON_GCC_COMPILER
// the GCC compiler does well with by-value passing.
// GCC has superior recursive inlining:
// https://stackoverflow.com/questions/29186186/why-does-gcc-generate-a-faster-program-than-clang-in-this-recursive-fibonacci-co
// https://godbolt.org/z/TeK4doE51
recursive_processor(val); recursive_processor(val);
#else
recursive_processor_ref(val);
#endif
}
if (doc.current_location().error() == simdjson::SUCCESS) {
// Example of error detection - this won't be reached on twitter.json in the benchmark.
throw "There are unexpectedly tokens after the end of the json in the json2msgpack sample data";
} }
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf)); return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
} }
@@ -156,7 +174,58 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
write_byte(0xc2 + element.get_bool()); write_byte(0xc2 + element.get_bool());
break; break;
case simdjson::ondemand::json_type::null: case simdjson::ondemand::json_type::null:
write_byte(0xc0); // We check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
write_byte(0xc0);
}
break;
default:
SIMDJSON_UNREACHABLE();
}
}
void simdjson2msgpack::recursive_processor_ref(simdjson::ondemand::value& element) {
switch (element.type()) {
case simdjson::ondemand::json_type::array: {
uint32_t counter = 0;
write_byte(0xdd);
uint8_t *location = skip_uint32();
for (auto child : element.get_array()) {
counter++;
simdjson::ondemand::value v = child.value();
recursive_processor_ref(v);
}
write_uint32_at(counter, location);
} break;
case simdjson::ondemand::json_type::object: {
uint32_t counter = 0;
write_byte(0xdf);
uint8_t *location = skip_uint32();
for (auto field : element.get_object()) {
counter++;
write_raw_string(field.key());
simdjson::ondemand::value v = field.value();
recursive_processor_ref(v);
}
write_uint32_at(counter, location);
} break;
case simdjson::ondemand::json_type::number:
write_double(element.get_double());
break;
case simdjson::ondemand::json_type::string:
write_raw_string(element.get_raw_json_string());
break;
case simdjson::ondemand::json_type::boolean:
write_byte(0xc2 + element.get_bool());
break;
case simdjson::ondemand::json_type::null:
// We check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
write_byte(0xc0);
}
break; break;
default: default:
SIMDJSON_UNREACHABLE(); SIMDJSON_UNREACHABLE();
+27 -8
View File
@@ -482,8 +482,20 @@ support for users who avoid exceptions. See [the simdjson error handling documen
std::cout << "Number of fields: " << count << std::endl; // Prints "Number of fields: 2" std::cout << "Number of fields: " << count << std::endl; // Prints "Number of fields: 2"
``` ```
* **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document * **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document
with a known type, and are trying to generically inspect or walk over JSON elements. To do that, you can use iterators and the `type()` method. You can also represent arbitrary JSON values with with a known type, and are trying to generically inspect or walk over JSON elements.
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You may also access [raw strings](#raw-strings). You can also represent arbitrary JSON values with
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`.
You can query the type of a document or a value with the `type()` method.
The `type()` method does not consume or validate documents and values, but it tells you whether they are
- arrays (`json_type::array`),
- objects (`json_type::object`)
- numbers (`json_type::number`),
- strings (`json_type::string`),
- Booleans (`json_type::boolean`),
- null (`json_type::null`).
You must still validate and consume the values (e.g., call `is_null()`) after calling `type()`.
You may also access [raw strings](#raw-strings).
For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`. For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`.
```c++ ```c++
void recursive_print_json(ondemand::value element) { void recursive_print_json(ondemand::value element) {
@@ -532,7 +544,11 @@ support for users who avoid exceptions. See [the simdjson error handling documen
cout << element.get_bool(); cout << element.get_bool();
break; break;
case ondemand::json_type::null: case ondemand::json_type::null:
cout << "null"; // We check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
cout << "null";
}
break; break;
} }
} }
@@ -931,11 +947,11 @@ bool parse() {
// Iterating through an array of objects // Iterating through an array of objects
auto error = parser.iterate(cars_json).get(doc); auto error = parser.iterate(cars_json).get(doc);
if(error) { std::cerr << error << std::endl; return false; } if(error) { std::cerr << error << std::endl; return false; }
ondemand::array cars; ondemand::array cars; // invalid until the get() succeeds
error = doc.get_array().get(cars); error = doc.get_array().get(cars);
for (auto car_value : cars) { for (auto car_value : cars) {
ondemand::object car; ondemand::object car; // invalid until the get() succeeds
error = car_value.get_object().get(car); error = car_value.get_object().get(car);
if(error) { std::cerr << error << std::endl; return false; } if(error) { std::cerr << error << std::endl; return false; }
@@ -976,7 +992,7 @@ For safety, you should only use our ondemand instances (e.g., `ondemand::object`
after you have initialized them and checked that there is no error: after you have initialized them and checked that there is no error:
```c++ ```c++
ondemand::object car; ondemand::object car; // invalid until the get() succeeds
// the `car` instance should not use used before it is initialized // the `car` instance should not use used before it is initialized
error = car_value.get_object().get(car); error = car_value.get_object().get(car);
if(error) { if(error) {
@@ -994,7 +1010,7 @@ having to handle exceptions.
ondemand::document doc; ondemand::document doc;
auto error = parser.iterate(json).get(doc); auto error = parser.iterate(json).get(doc);
if(error) { return false; } if(error) { return false; }
ondemand::object object; ondemand::object object; // invalid until the get() succeeds
error = doc.get_object().get(object); error = doc.get_object().get(object);
if(error) { return false; } if(error) { return false; }
for(auto field : object) { for(auto field : object) {
@@ -1110,6 +1126,9 @@ for (auto val : doc) {
std::cout << doc.current_location() << std::endl; // Throws OUT_OF_BOUNDS std::cout << doc.current_location() << std::endl; // Throws OUT_OF_BOUNDS
``` ```
Conversely, if `doc.current_location().error() == simdjson::SUCCESS`,
then the document has more content.
Finally, the `current_location()` method may also be used even when no exceptions/errors Finally, the `current_location()` method may also be used even when no exceptions/errors
are thrown. This can be helpful for users that want to know the current state of iteration during parsing. For example: are thrown. This can be helpful for users that want to know the current state of iteration during parsing. For example:
@@ -1118,7 +1137,7 @@ auto json = R"( [[1,2,3], -23.4, {"key": "value"}, true] )"_padded;
ondemand::parser parser; ondemand::parser parser;
auto doc = parser.iterate(json); auto doc = parser.iterate(json);
for (auto val : doc) { for (auto val : doc) {
ondemand::object obj; ondemand::object obj; // invalid until the get() succeeds
auto error = val.get_object().get(obj); // Only get objects auto error = val.get_object().get(obj); // Only get objects
if (!error) { if (!error) {
std::cout << doc.current_location() << std::endl; // Prints ""key": "value"}, true] " std::cout << doc.current_location() << std::endl; // Prints ""key": "value"}, true] "
+1 -1
View File
@@ -1,5 +1,5 @@
We take our documentation seriously. Please start reading the documentation before you attempt to use simdjson. We hope you will enjoy reading us. We take our documentation seriously. Please start reading the documentation before you attempt to use simdjson. We hope you will enjoy reading us.
* Basics: https://github.com/simdjson/simdjson/blob/master/doc/basics.md is an overview of how to use simdjson and its APIs. * Basics: https://github.com/simdjson/simdjson/blob/master/doc/basics.md is an overview of how to use simdjson and its APIs.
* parse_many: https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible. * iterate_many: https://github.com/simdjson/simdjson/blob/master/doc/iterate_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
* Performance: https://github.com/simdjson/simdjson/blob/master/doc/performance.md shows some more advanced scenarios and how to tune for them. * Performance: https://github.com/simdjson/simdjson/blob/master/doc/performance.md shows some more advanced scenarios and how to tune for them.
+9 -9
View File
@@ -47,7 +47,7 @@ dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padde
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance. The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
You cannot copy a `parser` instance, you may only move it. You cannot copy a `parser` instance, you may only move it.
If you need to keep a document around long term, you can keep or move the parser instance. Note that moving a parser instance, or keeping one in a movable data structure like vector or map, can cause any outstanding `element`, `object` or `array` instances to be invalidated. If you need to store a parser in a movable data structure, you should use a `std::unique_ptr` to avoid this invalidation(e.g., `std::unique_ptr<dom::parser> parser(new dom::parser{})`). If you need to keep a document around long term, you can keep or move the parser instance. Note that moving a parser instance, or keeping one in a movable data structure like vector or map, can cause any outstanding `element`, `object` or `array` instances to be invalidated. The `element`, `object` or `array` instances are mere thin wrappers akin to an `std::vector<int>::iterator`: they are invalid when default constructed, they must be tied to a valid document instance. If you need to store a parser in a movable data structure, you should use a `std::unique_ptr` to avoid this invalidation(e.g., `std::unique_ptr<dom::parser> parser(new dom::parser{})`).
During the`load` or `parse` calls, neither the input file nor the input string are ever modified. After calling `load` or `parse`, the source (either a file or a string) can be safely discarded. All of the JSON data is stored in the `parser` instance. The parsed document is also immutable in simdjson: you do not modify it by accessing it. During the`load` or `parse` calls, neither the input file nor the input string are ever modified. After calling `load` or `parse`, the source (either a file or a string) can be safely discarded. All of the JSON data is stored in the `parser` instance. The parsed document is also immutable in simdjson: you do not modify it by accessing it.
@@ -167,7 +167,7 @@ While the simdjson library can be used in any project using C++ 11 and above, fi
```c++ ```c++
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
dom::parser parser; dom::parser parser;
dom::object object; dom::object object; // invalid until the get() succeeds
auto error = parser.parse(json).get(object); auto error = parser.parse(json).get(object);
if (error) { cerr << error << endl; return; } if (error) { cerr << error << endl; return; }
for (auto [key, value] : object) { for (auto [key, value] : object) {
@@ -181,7 +181,7 @@ For comparison, here is the C++ 11 version of the same code:
// C++ 11 version for comparison // C++ 11 version for comparison
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
dom::parser parser; dom::parser parser;
dom::object object; dom::object object; // invalid until the get() succeeds
auto error = parser.parse(json).get(object); auto error = parser.parse(json).get(object);
if (error) { cerr << error << endl; return; } if (error) { cerr << error << endl; return; }
for (dom::key_value_pair field : object) { for (dom::key_value_pair field : object) {
@@ -227,7 +227,7 @@ dom::parser parser;
dom::element cars = parser.parse(cars_json); dom::element cars = parser.parse(cars_json);
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9 cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
for (dom::element car_element : cars) { for (dom::element car_element : cars) {
dom::object car; dom::object car; // invalid until the get() succeeds
simdjson::error_code error; simdjson::error_code error;
if ((error = car_element.get(car))) { std::cerr << error << std::endl; return; } if ((error = car_element.get(car))) { std::cerr << error << std::endl; return; }
double x = car.at_pointer("/tire_pressure/1"); double x = car.at_pointer("/tire_pressure/1");
@@ -283,11 +283,11 @@ it selects the key "count" within that object.
int main(void) { int main(void) {
simdjson::dom::parser parser; simdjson::dom::parser parser;
simdjson::dom::element tweets; simdjson::dom::element tweets; // invalid until the get() succeeds
auto error = parser.load("twitter.json").get(tweets); auto error = parser.load("twitter.json").get(tweets);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; } if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
simdjson::dom::element res; simdjson::dom::element res; // invalid until the get() succeeds
if ((error = tweets["search_metadata"]["count"].get(res))) { if ((error = tweets["search_metadata"]["count"].get(res))) {
std::cerr << "could not access keys" << std::endl; std::cerr << "could not access keys" << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -311,7 +311,7 @@ Observe how we use the `at` method when querying an index into an array, and not
int main(void) { int main(void) {
simdjson::dom::parser parser; simdjson::dom::parser parser;
simdjson::dom::element tweets; simdjson::dom::element tweets; // invalid until the get() succeeds
auto error = parser.load("twitter.json").get(tweets); auto error = parser.load("twitter.json").get(tweets);
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; } if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
uint64_t identifier; uint64_t identifier;
@@ -336,7 +336,7 @@ auto cars_json = R"( [
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] } { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded; ] )"_padded;
dom::parser parser; dom::parser parser;
dom::array cars; dom::array cars; // invalid until the get() succeeds
auto error = parser.parse(cars_json).get(cars); auto error = parser.parse(cars_json).get(cars);
if (error) { cerr << error << endl; exit(1); } if (error) { cerr << error << endl; exit(1); }
@@ -382,7 +382,7 @@ auto abstract_json = R"( [
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} } { "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
] )"_padded; ] )"_padded;
dom::parser parser; dom::parser parser;
dom::array array; dom::array array; // invalid until after the next line
auto error = parser.parse(abstract_json).get(array); auto error = parser.parse(abstract_json).get(array);
if (error) { cerr << error << endl; exit(1); } if (error) { cerr << error << endl; exit(1); }
// Iterate through an array of objects // Iterate through an array of objects
+7
View File
@@ -322,4 +322,11 @@ namespace std {
# define simdjson_fallthrough do {} while (0) /* fallthrough */ # define simdjson_fallthrough do {} while (0) /* fallthrough */
#endif // simdjson_fallthrough #endif // simdjson_fallthrough
#if SIMDJSON_DEVELOPMENT_CHECKS
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0)
#else
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { } while (0)
#endif
#endif // SIMDJSON_COMMON_DEFS_H #endif // SIMDJSON_COMMON_DEFS_H
+6
View File
@@ -53,18 +53,23 @@ namespace dom {
simdjson_inline array::array() noexcept : tape{} {} simdjson_inline array::array() noexcept : tape{} {}
simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {} simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
inline array::iterator array::begin() const noexcept { inline array::iterator array::begin() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.json_index + 1); return internal::tape_ref(tape.doc, tape.json_index + 1);
} }
inline array::iterator array::end() const noexcept { inline array::iterator array::end() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.after_element() - 1); return internal::tape_ref(tape.doc, tape.after_element() - 1);
} }
inline size_t array::size() const noexcept { inline size_t array::size() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.scope_count(); return tape.scope_count();
} }
inline size_t array::number_of_slots() const noexcept { inline size_t array::number_of_slots() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.matching_brace_index() - tape.json_index; return tape.matching_brace_index() - tape.json_index;
} }
inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept { inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(json_pointer.empty()) { // an empty string means that we return the current node if(json_pointer.empty()) { // an empty string means that we return the current node
return element(this->tape); // copy the current node return element(this->tape); // copy the current node
} else if(json_pointer[0] != '/') { // otherwise there is an error } else if(json_pointer[0] != '/') { // otherwise there is an error
@@ -105,6 +110,7 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
} }
inline simdjson_result<element> array::at(size_t index) const noexcept { inline simdjson_result<element> array::at(size_t index) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i=0; size_t i=0;
for (auto element : *this) { for (auto element : *this) {
if (i == index) { return element; } if (i == index) { return element; }
+12
View File
@@ -186,11 +186,13 @@ simdjson_inline element::element() noexcept : tape{} {}
simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { } simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
inline element_type element::type() const noexcept { inline element_type element::type() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
auto tape_type = tape.tape_ref_type(); auto tape_type = tape.tape_ref_type();
return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type); return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type);
} }
inline simdjson_result<bool> element::get_bool() const noexcept { inline simdjson_result<bool> element::get_bool() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(tape.is_true()) { if(tape.is_true()) {
return true; return true;
} else if(tape.is_false()) { } else if(tape.is_false()) {
@@ -199,6 +201,7 @@ inline simdjson_result<bool> element::get_bool() const noexcept {
return INCORRECT_TYPE; return INCORRECT_TYPE;
} }
inline simdjson_result<const char *> element::get_c_str() const noexcept { inline simdjson_result<const char *> element::get_c_str() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::STRING: { case internal::tape_type::STRING: {
return tape.get_c_str(); return tape.get_c_str();
@@ -208,6 +211,7 @@ inline simdjson_result<const char *> element::get_c_str() const noexcept {
} }
} }
inline simdjson_result<size_t> element::get_string_length() const noexcept { inline simdjson_result<size_t> element::get_string_length() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::STRING: { case internal::tape_type::STRING: {
return tape.get_string_length(); return tape.get_string_length();
@@ -217,6 +221,7 @@ inline simdjson_result<size_t> element::get_string_length() const noexcept {
} }
} }
inline simdjson_result<std::string_view> element::get_string() const noexcept { inline simdjson_result<std::string_view> element::get_string() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::STRING: case internal::tape_type::STRING:
return tape.get_string_view(); return tape.get_string_view();
@@ -225,6 +230,7 @@ inline simdjson_result<std::string_view> element::get_string() const noexcept {
} }
} }
inline simdjson_result<uint64_t> element::get_uint64() const noexcept { inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken
if(tape.is_int64()) { if(tape.is_int64()) {
int64_t result = tape.next_tape_value<int64_t>(); int64_t result = tape.next_tape_value<int64_t>();
@@ -238,6 +244,7 @@ inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
return tape.next_tape_value<int64_t>(); return tape.next_tape_value<int64_t>();
} }
inline simdjson_result<int64_t> element::get_int64() const noexcept { inline simdjson_result<int64_t> element::get_int64() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken
if(tape.is_uint64()) { if(tape.is_uint64()) {
uint64_t result = tape.next_tape_value<uint64_t>(); uint64_t result = tape.next_tape_value<uint64_t>();
@@ -252,6 +259,7 @@ inline simdjson_result<int64_t> element::get_int64() const noexcept {
return tape.next_tape_value<int64_t>(); return tape.next_tape_value<int64_t>();
} }
inline simdjson_result<double> element::get_double() const noexcept { inline simdjson_result<double> element::get_double() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
// Performance considerations: // Performance considerations:
// 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight // 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight
// comparison. // comparison.
@@ -273,6 +281,7 @@ inline simdjson_result<double> element::get_double() const noexcept {
return tape.next_tape_value<double>(); return tape.next_tape_value<double>();
} }
inline simdjson_result<array> element::get_array() const noexcept { inline simdjson_result<array> element::get_array() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::START_ARRAY: case internal::tape_type::START_ARRAY:
return array(tape); return array(tape);
@@ -281,6 +290,7 @@ inline simdjson_result<array> element::get_array() const noexcept {
} }
} }
inline simdjson_result<object> element::get_object() const noexcept { inline simdjson_result<object> element::get_object() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::START_OBJECT: case internal::tape_type::START_OBJECT:
return object(tape); return object(tape);
@@ -360,6 +370,7 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
} }
inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept { inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::START_OBJECT: case internal::tape_type::START_OBJECT:
return object(tape).at_pointer(json_pointer); return object(tape).at_pointer(json_pointer);
@@ -395,6 +406,7 @@ inline simdjson_result<element> element::at_key_case_insensitive(std::string_vie
} }
inline bool element::dump_raw_tape(std::ostream &out) const noexcept { inline bool element::dump_raw_tape(std::ostream &out) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.doc->dump_raw_tape(out); return tape.doc->dump_raw_tape(out);
} }
+4
View File
@@ -65,12 +65,15 @@ namespace dom {
simdjson_inline object::object() noexcept : tape{} {} simdjson_inline object::object() noexcept : tape{} {}
simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { } simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
inline object::iterator object::begin() const noexcept { inline object::iterator object::begin() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.json_index + 1); return internal::tape_ref(tape.doc, tape.json_index + 1);
} }
inline object::iterator object::end() const noexcept { inline object::iterator object::end() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.after_element() - 1); return internal::tape_ref(tape.doc, tape.after_element() - 1);
} }
inline size_t object::size() const noexcept { inline size_t object::size() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.scope_count(); return tape.scope_count();
} }
@@ -81,6 +84,7 @@ inline simdjson_result<element> object::operator[](const char *key) const noexce
return at_key(key); return at_key(key);
} }
inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept { inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(json_pointer.empty()) { // an empty string means that we return the current node if(json_pointer.empty()) { // an empty string means that we return the current node
return element(this->tape); // copy the current node return element(this->tape); // copy the current node
} else if(json_pointer[0] != '/') { // otherwise there is an error } else if(json_pointer[0] != '/') { // otherwise there is an error
+3
View File
@@ -148,6 +148,9 @@ simdjson_inline simdjson_result<element> parser::parse(const std::string &s) & n
simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept { simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept {
return parse(s.data(), s.length(), false); return parse(s.data(), s.length(), false);
} }
simdjson_inline simdjson_result<element> parser::parse(const padded_string_view &v) & noexcept {
return parse(v.data(), v.length(), false);
}
inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept { inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; } if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
+3
View File
@@ -199,6 +199,9 @@ public:
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */ /** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_inline simdjson_result<element> parse(const padded_string &s) & noexcept; simdjson_inline simdjson_result<element> parse(const padded_string &s) & noexcept;
simdjson_inline simdjson_result<element> parse(const padded_string &s) && =delete; simdjson_inline simdjson_result<element> parse(const padded_string &s) && =delete;
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) & noexcept;
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) && =delete;
/** @private We do not want to allow implicit conversion from C string to std::string. */ /** @private We do not want to allow implicit conversion from C string to std::string. */
simdjson_inline simdjson_result<element> parse(const char *buf) noexcept = delete; simdjson_inline simdjson_result<element> parse(const char *buf) noexcept = delete;
@@ -94,7 +94,7 @@ simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string()
simdjson_inline simdjson_result<bool> document::get_bool() noexcept { simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
return get_root_value_iterator().get_root_bool(); return get_root_value_iterator().get_root_bool();
} }
simdjson_inline bool document::is_null() noexcept { simdjson_inline simdjson_result<bool> document::is_null() noexcept {
return get_root_value_iterator().is_root_null(); return get_root_value_iterator().is_root_null();
} }
@@ -354,7 +354,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
if (error()) { return error(); } if (error()) { return error(); }
return first.get_value(); return first.get_value();
} }
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_null() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_null() noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -504,7 +504,7 @@ simdjson_inline simdjson_result<std::string_view> document_reference::get_string
simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_raw_json_string(); } simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_raw_json_string(); }
simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_bool(); } simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_bool(); }
simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); } simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
simdjson_inline bool document_reference::is_null() noexcept { return doc->is_null(); } simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->is_null(); }
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); } simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
@@ -636,7 +636,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
if (error()) { return error(); } if (error()) { return error(); }
return first.get_value(); return first.get_value();
} }
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -648,7 +648,7 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
if (error()) { return error(); } if (error()) { return error(); }
return first.is_scalar(); return first.is_scalar();
} }
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.is_negative(); return first.is_negative();
} }
+13 -8
View File
@@ -126,11 +126,14 @@ public:
simdjson_inline simdjson_result<value> get_value() noexcept; simdjson_inline simdjson_result<value> get_value() noexcept;
/** /**
* Checks if this JSON value is null. * Checks if this JSON value is null. If and only if the value is
* null, then it is consumed (we advance). If we find a token that
* begins with 'n' but is not 'null', then an error is returned.
* *
* @returns Whether the value is null. * @returns Whether the value is null.
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
*/ */
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
/** /**
* Get this value as the given type. * Get this value as the given type.
@@ -363,7 +366,9 @@ public:
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept; simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
/** /**
* Get the type of this JSON value. * Get the type of this JSON value. It does not validate or consume the value.
* E.g., you must still call "is_null()" to check that a value is null even if
* "type()" returns json_type::null.
* *
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
@@ -595,7 +600,7 @@ public:
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<value> get_value() noexcept; simdjson_inline simdjson_result<value> get_value() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept; simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
simdjson_inline operator document&() const noexcept; simdjson_inline operator document&() const noexcept;
@@ -660,7 +665,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept; template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept; template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
@@ -727,7 +732,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
@@ -754,8 +759,8 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
simdjson_inline simdjson_result<bool> is_scalar() noexcept; simdjson_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_inline simdjson_result<const char *> current_location() noexcept; simdjson_inline simdjson_result<const char *> current_location() noexcept;
simdjson_inline int32_t current_depth() const noexcept; simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
simdjson_inline bool is_negative() noexcept; simdjson_inline simdjson_result<bool> is_negative() noexcept;
simdjson_inline simdjson_result<bool> is_integer() noexcept; simdjson_inline simdjson_result<bool> is_integer() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> get_number() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> get_number() noexcept;
@@ -325,6 +325,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
SIMDJSON_ASSUME(_depth == child_depth - 1); SIMDJSON_ASSUME(_depth == child_depth - 1);
#if SIMDJSON_DEVELOPMENT_CHECKS #if SIMDJSON_DEVELOPMENT_CHECKS
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO #ifndef SIMDJSON_CLANG_VISUAL_STUDIO
SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]); SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
#endif #endif
#endif #endif
@@ -335,11 +336,13 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
#if SIMDJSON_DEVELOPMENT_CHECKS #if SIMDJSON_DEVELOPMENT_CHECKS
simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept { simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
return parser->start_positions[depth]; SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
} }
simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept { simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
parser->start_positions[depth] = position; SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
} }
#endif #endif
+10 -1
View File
@@ -230,13 +230,22 @@ public:
/** The maximum capacity of this parser (the largest document it is allowed to process). */ /** The maximum capacity of this parser (the largest document it is allowed to process). */
simdjson_inline size_t max_capacity() const noexcept; simdjson_inline size_t max_capacity() const noexcept;
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept; simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
/** The maximum depth of this parser (the most deeply nested objects and arrays it can process). */ /**
* The maximum depth of this parser (the most deeply nested objects and arrays it can process).
* This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
* The document's instance current_depth() method should be used to monitor the parsing
* depth and limit it if desired.
*/
simdjson_inline size_t max_depth() const noexcept; simdjson_inline size_t max_depth() const noexcept;
/** /**
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
* and `max_depth` depth. * and `max_depth` depth.
* *
* The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
* The document's instance current_depth() method should be used to monitor the parsing
* depth and limit it if desired.
*
* @param capacity The new capacity. * @param capacity The new capacity.
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH. * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
* @return The error, if there is one. * @return The error, if there is one.
@@ -4,23 +4,27 @@
namespace simdjson { namespace simdjson {
/** /**
* Create a string-view instance out of a document instance. The string-view instance * Create a string-view instance out of a document instance. The string-view instance
* contains JSON text that is suitable to be parsed as JSON again. * contains JSON text that is suitable to be parsed as JSON again. It does not
* validate the content.
*/ */
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document& x) noexcept; inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document& x) noexcept;
/** /**
* Create a string-view instance out of a value instance. The string-view instance * Create a string-view instance out of a value instance. The string-view instance
* contains JSON text that is suitable to be parsed as JSON again. The value must * contains JSON text that is suitable to be parsed as JSON again. The value must
* not have been accessed previously. * not have been accessed previously. It does not
* validate the content.
*/ */
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::value& x) noexcept; inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::value& x) noexcept;
/** /**
* Create a string-view instance out of an object instance. The string-view instance * Create a string-view instance out of an object instance. The string-view instance
* contains JSON text that is suitable to be parsed as JSON again. * contains JSON text that is suitable to be parsed as JSON again. It does not
* validate the content.
*/ */
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::object& x) noexcept; inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::object& x) noexcept;
/** /**
* Create a string-view instance out of an array instance. The string-view instance * Create a string-view instance out of an array instance. The string-view instance
* contains JSON text that is suitable to be parsed as JSON again. * contains JSON text that is suitable to be parsed as JSON again. It does not
* validate the content.
*/ */
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::array& x) noexcept; inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::array& x) noexcept;
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x); inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x);
@@ -39,7 +43,8 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand { namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand {
/** /**
* Print JSON to an output stream. * Print JSON to an output stream. It does not
* validate the content.
* *
* @param out The output stream. * @param out The output stream.
* @param value The element. * @param value The element.
@@ -50,7 +55,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value> x); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value> x);
#endif #endif
/** /**
* Print JSON to an output stream. * Print JSON to an output stream. It does not
* validate the content.
* *
* @param out The output stream. * @param out The output stream.
* @param value The array. * @param value The array.
@@ -61,7 +67,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::array> x); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::array> x);
#endif #endif
/** /**
* Print JSON to an output stream. * Print JSON to an output stream. It does not
* validate the content.
* *
* @param out The output stream. * @param out The output stream.
* @param value The array. * @param value The array.
@@ -76,7 +83,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference>&& x); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference>&& x);
#endif #endif
/** /**
* Print JSON to an output stream. * Print JSON to an output stream. It does not
* validate the content.
* *
* @param out The output stream. * @param out The output stream.
* @param value The object. * @param value The object.
@@ -54,10 +54,9 @@ simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
simdjson_inline simdjson_result<bool> value::get_bool() noexcept { simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
return iter.get_bool(); return iter.get_bool();
} }
simdjson_inline bool value::is_null() noexcept { simdjson_inline simdjson_result<bool> value::is_null() noexcept {
return iter.is_null(); return iter.is_null();
} }
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); } template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); } template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); } template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
@@ -311,8 +310,8 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
if (error()) { return error(); } if (error()) { return error(); }
return first.get_bool(); return first.get_bool();
} }
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_null() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_null() noexcept {
if (error()) { return false; } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -404,7 +403,7 @@ simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENT
return first.current_location(); return first.current_location();
} }
simdjson_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept { simdjson_inline simdjson_result<int32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.current_depth(); return first.current_depth();
} }
+10 -5
View File
@@ -150,11 +150,14 @@ public:
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
/** /**
* Checks if this JSON value is null. * Checks if this JSON value is null. If and only if the value is
* null, then it is consumed (we advance). If we find a token that
* begins with 'n' but is not 'null', then an error is returned.
* *
* @returns Whether the value is null. * @returns Whether the value is null.
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
*/ */
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
/** /**
@@ -334,7 +337,9 @@ public:
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept; simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
/** /**
* Get the type of this JSON value. * Get the type of this JSON value. It does not validate or consume the value.
* E.g., you must still call "is_null()" to check that a value is null even if
* "type()" returns json_type::null.
* *
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
@@ -583,7 +588,7 @@ public:
simdjson_inline simdjson_result<std::string_view> get_string() noexcept; simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() noexcept; template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
@@ -676,7 +681,7 @@ public:
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */ /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
simdjson_inline simdjson_result<const char *> current_location() noexcept; simdjson_inline simdjson_result<const char *> current_location() noexcept;
/** @copydoc simdjson_inline int32_t current_depth() const noexcept */ /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
simdjson_inline int32_t current_depth() const noexcept; simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
}; };
@@ -468,8 +468,11 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse
if (error) { return incorrect_type_error("Not a boolean"); } if (error) { return incorrect_type_error("Not a boolean"); }
return simdjson_result<bool>(!not_true); return simdjson_result<bool>(!not_true);
} }
simdjson_inline bool value_iterator::parse_null(const uint8_t *json) const noexcept { simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
return !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]); bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
// if we start with 'n', we must be a null
if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
return is_null_string;
} }
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string() noexcept { simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string() noexcept {
@@ -516,10 +519,11 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_b
if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); } if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
return result; return result;
} }
simdjson_inline bool value_iterator::is_null() noexcept { simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
auto result = parse_null(peek_non_root_scalar("null")); bool is_null_value;
if(result) { advance_non_root_scalar("null"); } SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
return result; if(is_null_value) { advance_non_root_scalar("null"); }
return is_null_value;
} }
simdjson_inline bool value_iterator::is_negative() noexcept { simdjson_inline bool value_iterator::is_negative() noexcept {
return numberparsing::is_negative(peek_non_root_scalar("numbersign")); return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
@@ -289,7 +289,7 @@ public:
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
simdjson_warn_unused simdjson_inline bool is_negative() noexcept; simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
@@ -350,7 +350,7 @@ protected:
inline std::string to_string() const noexcept; inline std::string to_string() const noexcept;
simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept; simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
simdjson_inline bool parse_null(const uint8_t *json) const noexcept; simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept; simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
simdjson_inline const uint8_t *peek_start() const noexcept; simdjson_inline const uint8_t *peek_start() const noexcept;
simdjson_inline uint32_t peek_start_length() const noexcept; simdjson_inline uint32_t peek_start_length() const noexcept;
+3 -1
View File
@@ -17,7 +17,9 @@ simdjson_inline tape_ref::tape_ref(const dom::document *_doc, size_t _json_index
simdjson_inline bool tape_ref::is_document_root() const noexcept { simdjson_inline bool tape_ref::is_document_root() const noexcept {
return json_index == 1; // should we ever change the structure of the tape, this should get updated. return json_index == 1; // should we ever change the structure of the tape, this should get updated.
} }
simdjson_inline bool tape_ref::usable() const noexcept {
return doc != nullptr; // when the document pointer is null, this tape_ref is uninitialized (should not be accessed).
}
// Some value types have a specific on-tape word value. It can be faster // Some value types have a specific on-tape word value. It can be faster
// to check the type by doing a word-to-word comparison instead of extracting the // to check the type by doing a word-to-word comparison instead of extracting the
// most significant 8 bits. // most significant 8 bits.
+1
View File
@@ -38,6 +38,7 @@ public:
simdjson_inline const char * get_c_str() const noexcept; simdjson_inline const char * get_c_str() const noexcept;
inline std::string_view get_string_view() const noexcept; inline std::string_view get_string_view() const noexcept;
simdjson_inline bool is_document_root() const noexcept; simdjson_inline bool is_document_root() const noexcept;
simdjson_inline bool usable() const noexcept;
/** The document this element references. */ /** The document this element references. */
const dom::document *doc; const dom::document *doc;
+4 -4
View File
@@ -4,22 +4,22 @@
#define SIMDJSON_SIMDJSON_VERSION_H #define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */ /** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION 2.2.3 #define SIMDJSON_VERSION 3.0.1
namespace simdjson { namespace simdjson {
enum { enum {
/** /**
* The major version (MAJOR.minor.revision) of simdjson being used. * The major version (MAJOR.minor.revision) of simdjson being used.
*/ */
SIMDJSON_VERSION_MAJOR = 2, SIMDJSON_VERSION_MAJOR = 3,
/** /**
* The minor version (major.MINOR.revision) of simdjson being used. * The minor version (major.MINOR.revision) of simdjson being used.
*/ */
SIMDJSON_VERSION_MINOR = 2, SIMDJSON_VERSION_MINOR = 0,
/** /**
* The revision (major.minor.REVISION) of simdjson being used. * The revision (major.minor.REVISION) of simdjson being used.
*/ */
SIMDJSON_VERSION_REVISION = 3 SIMDJSON_VERSION_REVISION = 1
}; };
} // namespace simdjson } // namespace simdjson
+6 -8
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2022-10-02 16:25:39 -0400. Do not edit! */ /* auto-generated on 2022-11-23 10:31:42 -0500. Do not edit! */
/* begin file src/simdjson.cpp */ /* begin file src/simdjson.cpp */
#include "simdjson.h" #include "simdjson.h"
@@ -868,9 +868,9 @@ inline char *format_buffer(char *buf, int len, int decimal_exponent,
std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k)); std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));
// Make it look like a floating-point number (#362, #378) // Make it look like a floating-point number (#362, #378)
// buf[n + 0] = '.'; buf[n + 0] = '.';
// buf[n + 1] = '0'; buf[n + 1] = '0';
return buf + (static_cast<size_t>(n)); return buf + (static_cast<size_t>(n)) + 2;
} }
if (0 < n && n <= max_exp) { if (0 < n && n <= max_exp) {
@@ -933,10 +933,8 @@ char *to_chars(char *first, const char *last, double value) {
{ {
*first++ = '0'; *first++ = '0';
// Make it look like a floating-point number (#362, #378) // Make it look like a floating-point number (#362, #378)
if(negative) { *first++ = '.';
*first++ = '.'; *first++ = '0';
*first++ = '0';
}
return first; return first;
} }
// Compute v = buffer * 10^decimal_exponent. // Compute v = buffer * 10^decimal_exponent.
+119 -48
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2022-10-02 16:25:39 -0400. Do not edit! */ /* auto-generated on 2022-11-23 10:31:42 -0500. Do not edit! */
/* begin file include/simdjson.h */ /* begin file include/simdjson.h */
#ifndef SIMDJSON_H #ifndef SIMDJSON_H
#define SIMDJSON_H #define SIMDJSON_H
@@ -43,22 +43,22 @@
#define SIMDJSON_SIMDJSON_VERSION_H #define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */ /** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION 2.2.3 #define SIMDJSON_VERSION 3.0.1
namespace simdjson { namespace simdjson {
enum { enum {
/** /**
* The major version (MAJOR.minor.revision) of simdjson being used. * The major version (MAJOR.minor.revision) of simdjson being used.
*/ */
SIMDJSON_VERSION_MAJOR = 2, SIMDJSON_VERSION_MAJOR = 3,
/** /**
* The minor version (major.MINOR.revision) of simdjson being used. * The minor version (major.MINOR.revision) of simdjson being used.
*/ */
SIMDJSON_VERSION_MINOR = 2, SIMDJSON_VERSION_MINOR = 0,
/** /**
* The revision (major.minor.REVISION) of simdjson being used. * The revision (major.minor.REVISION) of simdjson being used.
*/ */
SIMDJSON_VERSION_REVISION = 3 SIMDJSON_VERSION_REVISION = 1
}; };
} // namespace simdjson } // namespace simdjson
@@ -2253,6 +2253,13 @@ namespace std {
# define simdjson_fallthrough do {} while (0) /* fallthrough */ # define simdjson_fallthrough do {} while (0) /* fallthrough */
#endif // simdjson_fallthrough #endif // simdjson_fallthrough
#if SIMDJSON_DEVELOPMENT_CHECKS
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0)
#else
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { } while (0)
#endif
#endif // SIMDJSON_COMMON_DEFS_H #endif // SIMDJSON_COMMON_DEFS_H
/* end file include/simdjson/common_defs.h */ /* end file include/simdjson/common_defs.h */
@@ -4048,6 +4055,7 @@ public:
simdjson_inline const char * get_c_str() const noexcept; simdjson_inline const char * get_c_str() const noexcept;
inline std::string_view get_string_view() const noexcept; inline std::string_view get_string_view() const noexcept;
simdjson_inline bool is_document_root() const noexcept; simdjson_inline bool is_document_root() const noexcept;
simdjson_inline bool usable() const noexcept;
/** The document this element references. */ /** The document this element references. */
const dom::document *doc; const dom::document *doc;
@@ -4533,6 +4541,9 @@ public:
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */ /** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_inline simdjson_result<element> parse(const padded_string &s) & noexcept; simdjson_inline simdjson_result<element> parse(const padded_string &s) & noexcept;
simdjson_inline simdjson_result<element> parse(const padded_string &s) && =delete; simdjson_inline simdjson_result<element> parse(const padded_string &s) && =delete;
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) & noexcept;
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) && =delete;
/** @private We do not want to allow implicit conversion from C string to std::string. */ /** @private We do not want to allow implicit conversion from C string to std::string. */
simdjson_inline simdjson_result<element> parse(const char *buf) noexcept = delete; simdjson_inline simdjson_result<element> parse(const char *buf) noexcept = delete;
@@ -6844,18 +6855,23 @@ namespace dom {
simdjson_inline array::array() noexcept : tape{} {} simdjson_inline array::array() noexcept : tape{} {}
simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {} simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
inline array::iterator array::begin() const noexcept { inline array::iterator array::begin() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.json_index + 1); return internal::tape_ref(tape.doc, tape.json_index + 1);
} }
inline array::iterator array::end() const noexcept { inline array::iterator array::end() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.after_element() - 1); return internal::tape_ref(tape.doc, tape.after_element() - 1);
} }
inline size_t array::size() const noexcept { inline size_t array::size() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.scope_count(); return tape.scope_count();
} }
inline size_t array::number_of_slots() const noexcept { inline size_t array::number_of_slots() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.matching_brace_index() - tape.json_index; return tape.matching_brace_index() - tape.json_index;
} }
inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept { inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(json_pointer.empty()) { // an empty string means that we return the current node if(json_pointer.empty()) { // an empty string means that we return the current node
return element(this->tape); // copy the current node return element(this->tape); // copy the current node
} else if(json_pointer[0] != '/') { // otherwise there is an error } else if(json_pointer[0] != '/') { // otherwise there is an error
@@ -6896,6 +6912,7 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
} }
inline simdjson_result<element> array::at(size_t index) const noexcept { inline simdjson_result<element> array::at(size_t index) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i=0; size_t i=0;
for (auto element : *this) { for (auto element : *this) {
if (i == index) { return element; } if (i == index) { return element; }
@@ -7130,11 +7147,13 @@ simdjson_inline element::element() noexcept : tape{} {}
simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { } simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
inline element_type element::type() const noexcept { inline element_type element::type() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
auto tape_type = tape.tape_ref_type(); auto tape_type = tape.tape_ref_type();
return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type); return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type);
} }
inline simdjson_result<bool> element::get_bool() const noexcept { inline simdjson_result<bool> element::get_bool() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(tape.is_true()) { if(tape.is_true()) {
return true; return true;
} else if(tape.is_false()) { } else if(tape.is_false()) {
@@ -7143,6 +7162,7 @@ inline simdjson_result<bool> element::get_bool() const noexcept {
return INCORRECT_TYPE; return INCORRECT_TYPE;
} }
inline simdjson_result<const char *> element::get_c_str() const noexcept { inline simdjson_result<const char *> element::get_c_str() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::STRING: { case internal::tape_type::STRING: {
return tape.get_c_str(); return tape.get_c_str();
@@ -7152,6 +7172,7 @@ inline simdjson_result<const char *> element::get_c_str() const noexcept {
} }
} }
inline simdjson_result<size_t> element::get_string_length() const noexcept { inline simdjson_result<size_t> element::get_string_length() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::STRING: { case internal::tape_type::STRING: {
return tape.get_string_length(); return tape.get_string_length();
@@ -7161,6 +7182,7 @@ inline simdjson_result<size_t> element::get_string_length() const noexcept {
} }
} }
inline simdjson_result<std::string_view> element::get_string() const noexcept { inline simdjson_result<std::string_view> element::get_string() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::STRING: case internal::tape_type::STRING:
return tape.get_string_view(); return tape.get_string_view();
@@ -7169,6 +7191,7 @@ inline simdjson_result<std::string_view> element::get_string() const noexcept {
} }
} }
inline simdjson_result<uint64_t> element::get_uint64() const noexcept { inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken
if(tape.is_int64()) { if(tape.is_int64()) {
int64_t result = tape.next_tape_value<int64_t>(); int64_t result = tape.next_tape_value<int64_t>();
@@ -7182,6 +7205,7 @@ inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
return tape.next_tape_value<int64_t>(); return tape.next_tape_value<int64_t>();
} }
inline simdjson_result<int64_t> element::get_int64() const noexcept { inline simdjson_result<int64_t> element::get_int64() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken
if(tape.is_uint64()) { if(tape.is_uint64()) {
uint64_t result = tape.next_tape_value<uint64_t>(); uint64_t result = tape.next_tape_value<uint64_t>();
@@ -7196,6 +7220,7 @@ inline simdjson_result<int64_t> element::get_int64() const noexcept {
return tape.next_tape_value<int64_t>(); return tape.next_tape_value<int64_t>();
} }
inline simdjson_result<double> element::get_double() const noexcept { inline simdjson_result<double> element::get_double() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
// Performance considerations: // Performance considerations:
// 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight // 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight
// comparison. // comparison.
@@ -7217,6 +7242,7 @@ inline simdjson_result<double> element::get_double() const noexcept {
return tape.next_tape_value<double>(); return tape.next_tape_value<double>();
} }
inline simdjson_result<array> element::get_array() const noexcept { inline simdjson_result<array> element::get_array() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::START_ARRAY: case internal::tape_type::START_ARRAY:
return array(tape); return array(tape);
@@ -7225,6 +7251,7 @@ inline simdjson_result<array> element::get_array() const noexcept {
} }
} }
inline simdjson_result<object> element::get_object() const noexcept { inline simdjson_result<object> element::get_object() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::START_OBJECT: case internal::tape_type::START_OBJECT:
return object(tape); return object(tape);
@@ -7304,6 +7331,7 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
} }
inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept { inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) { switch (tape.tape_ref_type()) {
case internal::tape_type::START_OBJECT: case internal::tape_type::START_OBJECT:
return object(tape).at_pointer(json_pointer); return object(tape).at_pointer(json_pointer);
@@ -7339,6 +7367,7 @@ inline simdjson_result<element> element::at_key_case_insensitive(std::string_vie
} }
inline bool element::dump_raw_tape(std::ostream &out) const noexcept { inline bool element::dump_raw_tape(std::ostream &out) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.doc->dump_raw_tape(out); return tape.doc->dump_raw_tape(out);
} }
@@ -7946,12 +7975,15 @@ namespace dom {
simdjson_inline object::object() noexcept : tape{} {} simdjson_inline object::object() noexcept : tape{} {}
simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { } simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
inline object::iterator object::begin() const noexcept { inline object::iterator object::begin() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.json_index + 1); return internal::tape_ref(tape.doc, tape.json_index + 1);
} }
inline object::iterator object::end() const noexcept { inline object::iterator object::end() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.after_element() - 1); return internal::tape_ref(tape.doc, tape.after_element() - 1);
} }
inline size_t object::size() const noexcept { inline size_t object::size() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.scope_count(); return tape.scope_count();
} }
@@ -7962,6 +7994,7 @@ inline simdjson_result<element> object::operator[](const char *key) const noexce
return at_key(key); return at_key(key);
} }
inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept { inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(json_pointer.empty()) { // an empty string means that we return the current node if(json_pointer.empty()) { // an empty string means that we return the current node
return element(this->tape); // copy the current node return element(this->tape); // copy the current node
} else if(json_pointer[0] != '/') { // otherwise there is an error } else if(json_pointer[0] != '/') { // otherwise there is an error
@@ -8767,6 +8800,9 @@ simdjson_inline simdjson_result<element> parser::parse(const std::string &s) & n
simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept { simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept {
return parse(s.data(), s.length(), false); return parse(s.data(), s.length(), false);
} }
simdjson_inline simdjson_result<element> parser::parse(const padded_string_view &v) & noexcept {
return parse(v.data(), v.length(), false);
}
inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept { inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; } if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
@@ -8873,7 +8909,9 @@ simdjson_inline tape_ref::tape_ref(const dom::document *_doc, size_t _json_index
simdjson_inline bool tape_ref::is_document_root() const noexcept { simdjson_inline bool tape_ref::is_document_root() const noexcept {
return json_index == 1; // should we ever change the structure of the tape, this should get updated. return json_index == 1; // should we ever change the structure of the tape, this should get updated.
} }
simdjson_inline bool tape_ref::usable() const noexcept {
return doc != nullptr; // when the document pointer is null, this tape_ref is uninitialized (should not be accessed).
}
// Some value types have a specific on-tape word value. It can be faster // Some value types have a specific on-tape word value. It can be faster
// to check the type by doing a word-to-word comparison instead of extracting the // to check the type by doing a word-to-word comparison instead of extracting the
// most significant 8 bits. // most significant 8 bits.
@@ -23792,7 +23830,7 @@ public:
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
simdjson_warn_unused simdjson_inline bool is_negative() noexcept; simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept; simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
@@ -23853,7 +23891,7 @@ protected:
inline std::string to_string() const noexcept; inline std::string to_string() const noexcept;
simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept; simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
simdjson_inline bool parse_null(const uint8_t *json) const noexcept; simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept; simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
simdjson_inline const uint8_t *peek_start() const noexcept; simdjson_inline const uint8_t *peek_start() const noexcept;
simdjson_inline uint32_t peek_start_length() const noexcept; simdjson_inline uint32_t peek_start_length() const noexcept;
@@ -24454,11 +24492,14 @@ public:
simdjson_inline simdjson_result<value> get_value() noexcept; simdjson_inline simdjson_result<value> get_value() noexcept;
/** /**
* Checks if this JSON value is null. * Checks if this JSON value is null. If and only if the value is
* null, then it is consumed (we advance). If we find a token that
* begins with 'n' but is not 'null', then an error is returned.
* *
* @returns Whether the value is null. * @returns Whether the value is null.
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
*/ */
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
/** /**
* Get this value as the given type. * Get this value as the given type.
@@ -24691,7 +24732,9 @@ public:
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept; simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
/** /**
* Get the type of this JSON value. * Get the type of this JSON value. It does not validate or consume the value.
* E.g., you must still call "is_null()" to check that a value is null even if
* "type()" returns json_type::null.
* *
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
@@ -24923,7 +24966,7 @@ public:
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<value> get_value() noexcept; simdjson_inline simdjson_result<value> get_value() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept; simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
simdjson_inline operator document&() const noexcept; simdjson_inline operator document&() const noexcept;
@@ -24988,7 +25031,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> get_value() noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> get_value() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept; template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept; template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
@@ -25055,7 +25098,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> get_value() noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> get_value() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
simdjson_inline operator SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array() & noexcept(false); simdjson_inline operator SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array() & noexcept(false);
@@ -25082,8 +25125,8 @@ public:
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::json_type> type() noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::json_type> type() noexcept;
simdjson_inline simdjson_result<bool> is_scalar() noexcept; simdjson_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_inline simdjson_result<const char *> current_location() noexcept; simdjson_inline simdjson_result<const char *> current_location() noexcept;
simdjson_inline int32_t current_depth() const noexcept; simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
simdjson_inline bool is_negative() noexcept; simdjson_inline simdjson_result<bool> is_negative() noexcept;
simdjson_inline simdjson_result<bool> is_integer() noexcept; simdjson_inline simdjson_result<bool> is_integer() noexcept;
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::number> get_number() noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::number> get_number() noexcept;
@@ -25248,11 +25291,14 @@ public:
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
/** /**
* Checks if this JSON value is null. * Checks if this JSON value is null. If and only if the value is
* null, then it is consumed (we advance). If we find a token that
* begins with 'n' but is not 'null', then an error is returned.
* *
* @returns Whether the value is null. * @returns Whether the value is null.
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
*/ */
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
/** /**
@@ -25432,7 +25478,9 @@ public:
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept; simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
/** /**
* Get the type of this JSON value. * Get the type of this JSON value. It does not validate or consume the value.
* E.g., you must still call "is_null()" to check that a value is null even if
* "type()" returns json_type::null.
* *
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally * NOTE: If you're only expecting a value to be one type (a typical case), it's generally
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
@@ -25681,7 +25729,7 @@ public:
simdjson_inline simdjson_result<std::string_view> get_string() noexcept; simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline bool is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() noexcept; template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
@@ -25774,7 +25822,7 @@ public:
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */ /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
simdjson_inline simdjson_result<const char *> current_location() noexcept; simdjson_inline simdjson_result<const char *> current_location() noexcept;
/** @copydoc simdjson_inline int32_t current_depth() const noexcept */ /** @copydoc simdjson_inline int32_t current_depth() const noexcept */
simdjson_inline int32_t current_depth() const noexcept; simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
}; };
@@ -26315,13 +26363,22 @@ public:
/** The maximum capacity of this parser (the largest document it is allowed to process). */ /** The maximum capacity of this parser (the largest document it is allowed to process). */
simdjson_inline size_t max_capacity() const noexcept; simdjson_inline size_t max_capacity() const noexcept;
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept; simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
/** The maximum depth of this parser (the most deeply nested objects and arrays it can process). */ /**
* The maximum depth of this parser (the most deeply nested objects and arrays it can process).
* This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
* The document's instance current_depth() method should be used to monitor the parsing
* depth and limit it if desired.
*/
simdjson_inline size_t max_depth() const noexcept; simdjson_inline size_t max_depth() const noexcept;
/** /**
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
* and `max_depth` depth. * and `max_depth` depth.
* *
* The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
* The document's instance current_depth() method should be used to monitor the parsing
* depth and limit it if desired.
*
* @param capacity The new capacity. * @param capacity The new capacity.
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH. * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
* @return The error, if there is one. * @return The error, if there is one.
@@ -26725,23 +26782,27 @@ public:
namespace simdjson { namespace simdjson {
/** /**
* Create a string-view instance out of a document instance. The string-view instance * Create a string-view instance out of a document instance. The string-view instance
* contains JSON text that is suitable to be parsed as JSON again. * contains JSON text that is suitable to be parsed as JSON again. It does not
* validate the content.
*/ */
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document& x) noexcept; inline simdjson_result<std::string_view> to_json_string(SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document& x) noexcept;
/** /**
* Create a string-view instance out of a value instance. The string-view instance * Create a string-view instance out of a value instance. The string-view instance
* contains JSON text that is suitable to be parsed as JSON again. The value must * contains JSON text that is suitable to be parsed as JSON again. The value must
* not have been accessed previously. * not have been accessed previously. It does not
* validate the content.
*/ */
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value& x) noexcept; inline simdjson_result<std::string_view> to_json_string(SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value& x) noexcept;
/** /**
* Create a string-view instance out of an object instance. The string-view instance * Create a string-view instance out of an object instance. The string-view instance
* contains JSON text that is suitable to be parsed as JSON again. * contains JSON text that is suitable to be parsed as JSON again. It does not
* validate the content.
*/ */
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::object& x) noexcept; inline simdjson_result<std::string_view> to_json_string(SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::object& x) noexcept;
/** /**
* Create a string-view instance out of an array instance. The string-view instance * Create a string-view instance out of an array instance. The string-view instance
* contains JSON text that is suitable to be parsed as JSON again. * contains JSON text that is suitable to be parsed as JSON again. It does not
* validate the content.
*/ */
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array& x) noexcept; inline simdjson_result<std::string_view> to_json_string(SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array& x) noexcept;
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document> x); inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document> x);
@@ -26760,7 +26821,8 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
namespace simdjson { namespace SIMDJSON_BUILTIN_IMPLEMENTATION { namespace ondemand { namespace simdjson { namespace SIMDJSON_BUILTIN_IMPLEMENTATION { namespace ondemand {
/** /**
* Print JSON to an output stream. * Print JSON to an output stream. It does not
* validate the content.
* *
* @param out The output stream. * @param out The output stream.
* @param value The element. * @param value The element.
@@ -26771,7 +26833,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_BUILTIN_IM
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> x); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> x);
#endif #endif
/** /**
* Print JSON to an output stream. * Print JSON to an output stream. It does not
* validate the content.
* *
* @param out The output stream. * @param out The output stream.
* @param value The array. * @param value The array.
@@ -26782,7 +26845,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_BUILTIN_IM
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array> x); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array> x);
#endif #endif
/** /**
* Print JSON to an output stream. * Print JSON to an output stream. It does not
* validate the content.
* *
* @param out The output stream. * @param out The output stream.
* @param value The array. * @param value The array.
@@ -26797,7 +26861,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_BUILTIN_IM
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document_reference>&& x); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document_reference>&& x);
#endif #endif
/** /**
* Print JSON to an output stream. * Print JSON to an output stream. It does not
* validate the content.
* *
* @param out The output stream. * @param out The output stream.
* @param value The object. * @param value The object.
@@ -27775,6 +27840,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
SIMDJSON_ASSUME(_depth == child_depth - 1); SIMDJSON_ASSUME(_depth == child_depth - 1);
#if SIMDJSON_DEVELOPMENT_CHECKS #if SIMDJSON_DEVELOPMENT_CHECKS
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO #ifndef SIMDJSON_CLANG_VISUAL_STUDIO
SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]); SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
#endif #endif
#endif #endif
@@ -27785,11 +27851,13 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
#if SIMDJSON_DEVELOPMENT_CHECKS #if SIMDJSON_DEVELOPMENT_CHECKS
simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept { simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
return parser->start_positions[depth]; SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
} }
simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept { simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
parser->start_positions[depth] = position; SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
} }
#endif #endif
@@ -28301,8 +28369,11 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse
if (error) { return incorrect_type_error("Not a boolean"); } if (error) { return incorrect_type_error("Not a boolean"); }
return simdjson_result<bool>(!not_true); return simdjson_result<bool>(!not_true);
} }
simdjson_inline bool value_iterator::parse_null(const uint8_t *json) const noexcept { simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
return !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]); bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
// if we start with 'n', we must be a null
if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
return is_null_string;
} }
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string() noexcept { simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string() noexcept {
@@ -28349,10 +28420,11 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_b
if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); } if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
return result; return result;
} }
simdjson_inline bool value_iterator::is_null() noexcept { simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
auto result = parse_null(peek_non_root_scalar("null")); bool is_null_value;
if(result) { advance_non_root_scalar("null"); } SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
return result; if(is_null_value) { advance_non_root_scalar("null"); }
return is_null_value;
} }
simdjson_inline bool value_iterator::is_negative() noexcept { simdjson_inline bool value_iterator::is_negative() noexcept {
return numberparsing::is_negative(peek_non_root_scalar("numbersign")); return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
@@ -29337,7 +29409,7 @@ simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string()
simdjson_inline simdjson_result<bool> document::get_bool() noexcept { simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
return get_root_value_iterator().get_root_bool(); return get_root_value_iterator().get_root_bool();
} }
simdjson_inline bool document::is_null() noexcept { simdjson_inline simdjson_result<bool> document::is_null() noexcept {
return get_root_value_iterator().is_root_null(); return get_root_value_iterator().is_root_null();
} }
@@ -29597,7 +29669,7 @@ simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value
if (error()) { return error(); } if (error()) { return error(); }
return first.get_value(); return first.get_value();
} }
simdjson_inline bool simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document>::is_null() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document>::is_null() noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -29747,7 +29819,7 @@ simdjson_inline simdjson_result<std::string_view> document_reference::get_string
simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_raw_json_string(); } simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_raw_json_string(); }
simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_bool(); } simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_bool(); }
simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); } simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
simdjson_inline bool document_reference::is_null() noexcept { return doc->is_null(); } simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->is_null(); }
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); } simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
@@ -29879,7 +29951,7 @@ simdjson_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value
if (error()) { return error(); } if (error()) { return error(); }
return first.get_value(); return first.get_value();
} }
simdjson_inline bool simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -29891,7 +29963,7 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENT
if (error()) { return error(); } if (error()) { return error(); }
return first.is_scalar(); return first.is_scalar();
} }
simdjson_inline bool simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.is_negative(); return first.is_negative();
} }
@@ -30021,10 +30093,9 @@ simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
simdjson_inline simdjson_result<bool> value::get_bool() noexcept { simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
return iter.get_bool(); return iter.get_bool();
} }
simdjson_inline bool value::is_null() noexcept { simdjson_inline simdjson_result<bool> value::is_null() noexcept {
return iter.is_null(); return iter.is_null();
} }
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); } template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); } template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); } template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
@@ -30278,8 +30349,8 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENT
if (error()) { return error(); } if (error()) { return error(); }
return first.get_bool(); return first.get_bool();
} }
simdjson_inline bool simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value>::is_null() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value>::is_null() noexcept {
if (error()) { return false; } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -30371,7 +30442,7 @@ simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_BUILTIN_I
return first.current_location(); return first.current_location();
} }
simdjson_inline int32_t simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept { simdjson_inline simdjson_result<int32_t> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.current_depth(); return first.current_depth();
} }
+5 -7
View File
@@ -860,9 +860,9 @@ inline char *format_buffer(char *buf, int len, int decimal_exponent,
std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k)); std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));
// Make it look like a floating-point number (#362, #378) // Make it look like a floating-point number (#362, #378)
// buf[n + 0] = '.'; buf[n + 0] = '.';
// buf[n + 1] = '0'; buf[n + 1] = '0';
return buf + (static_cast<size_t>(n)); return buf + (static_cast<size_t>(n)) + 2;
} }
if (0 < n && n <= max_exp) { if (0 < n && n <= max_exp) {
@@ -925,10 +925,8 @@ char *to_chars(char *first, const char *last, double value) {
{ {
*first++ = '0'; *first++ = '0';
// Make it look like a floating-point number (#362, #378) // Make it look like a floating-point number (#362, #378)
if(negative) { *first++ = '.';
*first++ = '.'; *first++ = '0';
*first++ = '0';
}
return first; return first;
} }
// Compute v = buffer * 10^decimal_exponent. // Compute v = buffer * 10^decimal_exponent.
+5 -1
View File
@@ -160,7 +160,11 @@ namespace ondemand_treewalk {
cout << element.get_bool(); cout << element.get_bool();
break; break;
case ondemand::json_type::null: case ondemand::json_type::null:
cout << "null"; // We check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
cout << "null";
}
break; break;
} }
} }
+33 -12
View File
@@ -119,7 +119,9 @@ namespace error_tests {
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc) { SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc) {
simdjson_result<ondemand::value> val = doc["val"]; simdjson_result<ondemand::value> val = doc["val"];
// Get everything that can fail in both forward and backwards order // Get everything that can fail in both forward and backwards order
ASSERT_EQUAL( val.is_null(), false ); bool is_null_value;
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
@@ -131,15 +133,18 @@ namespace error_tests {
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.get_bool() );
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) { SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) {
ondemand::value val; ondemand::value val;
ASSERT_SUCCESS( doc["val"].get(val) ); ASSERT_SUCCESS( doc["val"].get(val) );
// Get everything that can fail in both forward and backwards order // Get everything that can fail in both forward and backwards order
ASSERT_EQUAL( val.is_null(), false ); bool is_null_value;
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
@@ -151,14 +156,17 @@ namespace error_tests {
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.get_bool() );
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
json = R"(true)"_padded; json = R"(true)"_padded;
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](simdjson_result<ondemand::document> val) { SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](simdjson_result<ondemand::document> val) {
// Get everything that can fail in both forward and backwards order // Get everything that can fail in both forward and backwards order
ASSERT_EQUAL( val.is_null(), false ); bool is_null_value;
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
@@ -170,14 +178,17 @@ namespace error_tests {
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool()); ASSERT_SUCCESS( val.get_bool());
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) { SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) {
ondemand::document val; ondemand::document val;
ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order
ASSERT_EQUAL( val.is_null(), false ); bool is_null_value;
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
@@ -189,8 +200,9 @@ namespace error_tests {
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.get_bool() );
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
@@ -216,13 +228,16 @@ namespace error_tests {
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), true ); bool is_null_value;
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, true );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) { SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) {
ondemand::value val; ondemand::value val;
ASSERT_SUCCESS( doc["val"].get(val) ); ASSERT_SUCCESS( doc["val"].get(val) );
// Get everything that can fail in both forward and backwards order // Get everything that can fail in both forward and backwards order
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
@@ -236,7 +251,9 @@ namespace error_tests {
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), true ); bool is_null_value;
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, true );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
json = R"(null)"_padded; json = R"(null)"_padded;
@@ -255,7 +272,9 @@ namespace error_tests {
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), true ); bool is_null_value;
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, true );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) { SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) {
@@ -274,7 +293,9 @@ namespace error_tests {
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), true ); bool is_null_value;
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, true );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
TEST_SUCCEED(); TEST_SUCCEED();
@@ -71,7 +71,7 @@ namespace json_pointer_tests {
ASSERT_SUCCESS(val.get_bool().error()); ASSERT_SUCCESS(val.get_bool().error());
break; break;
case ondemand::json_type::null: case ondemand::json_type::null:
ASSERT_TRUE(val.is_null()); ASSERT_SUCCESS(val.is_null().error());
break; break;
default: default:
TEST_FAIL("unexpected type"); TEST_FAIL("unexpected type");
+3 -1
View File
@@ -271,7 +271,9 @@ namespace misc_tests {
ASSERT_SUCCESS(global.get(global_object)); ASSERT_SUCCESS(global.get(global_object));
ondemand::value shadowable; ondemand::value shadowable;
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable)); ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
ASSERT_TRUE(!shadowable.is_null()); bool is_null_value;
ASSERT_SUCCESS(shadowable.is_null().get(is_null_value));
ASSERT_TRUE(!is_null_value);
ondemand::value badvalue; ondemand::value badvalue;
auto error = global_object["writable"].get(badvalue); auto error = global_object["writable"].get(badvalue);
if(error == SUCCESS) { if(error == SUCCESS) {
+10 -2
View File
@@ -87,7 +87,11 @@ void recursive_print_json(ondemand::value element) {
cout << element.get_bool(); cout << element.get_bool();
break; break;
case ondemand::json_type::null: case ondemand::json_type::null:
cout << "null"; // we check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
cout << "null";
}
break; break;
} }
} }
@@ -166,7 +170,11 @@ void recursive_print_json_breakline(ondemand::value element) {
cout << element.get_bool(); cout << element.get_bool();
break; break;
case ondemand::json_type::null: case ondemand::json_type::null:
cout << "null"; // We check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
cout << "null";
}
break; break;
} }
} }
+12 -4
View File
@@ -206,11 +206,15 @@ namespace scalar_tests {
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) { SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc; ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(doc) ); ASSERT_SUCCESS( std::move(doc_result).get(doc) );
ASSERT_EQUAL( doc.is_null(), true ); bool is_null_value;
ASSERT_SUCCESS( doc.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, true );
return true; return true;
})); }));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) { SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
ASSERT_EQUAL( doc_result.is_null(), true ); bool is_null_value;
ASSERT_SUCCESS( doc_result.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, true );
return true; return true;
})); }));
json = "[null]"_padded; json = "[null]"_padded;
@@ -219,7 +223,9 @@ namespace scalar_tests {
for (auto value_result : doc_result) { for (auto value_result : doc_result) {
ondemand::value value; ondemand::value value;
ASSERT_SUCCESS( value_result.get(value) ); ASSERT_SUCCESS( value_result.get(value) );
ASSERT_EQUAL( value.is_null(), true ); bool is_null_value;
ASSERT_SUCCESS( value.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, true );
count++; count++;
} }
ASSERT_EQUAL( count, 1 ); ASSERT_EQUAL( count, 1 );
@@ -228,7 +234,9 @@ namespace scalar_tests {
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc_result) { SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc_result) {
int count = 0; int count = 0;
for (auto value_result : doc_result) { for (auto value_result : doc_result) {
ASSERT_EQUAL( value_result.is_null(), true ); bool is_null_value;
ASSERT_SUCCESS( value_result.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, true );
count++; count++;
} }
ASSERT_EQUAL( count, 1 ); ASSERT_EQUAL( count, 1 );
+12
View File
@@ -63,7 +63,19 @@ int main(int argc, const char *argv[]) {
simdjson::ondemand::document doc; simdjson::ondemand::document doc;
error = parser.iterate(docdata).get(doc); error = parser.iterate(docdata).get(doc);
if(error != simdjson::SUCCESS) { std::cout << error << std::endl; return EXIT_FAILURE; } if(error != simdjson::SUCCESS) { std::cout << error << std::endl; return EXIT_FAILURE; }
// This locates the document and captures a string_view instance, it does
// not validate the document:
std::cout << doc; std::cout << doc;
// check if there is more content
const char * endofstream;
if(doc.current_location().get(endofstream) == simdjson::SUCCESS) {
// there is more content !
// let us find what it is:
size_t len = docdata.data() + docdata.size() - endofstream;
std::string_view content{endofstream, len};
std::cerr << "\nThere is leftover content: '" << content << "'" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
simdjson::dom::parser parser; simdjson::dom::parser parser;