Merge pull request #629 from simdjson/jkeiser/parse-element

Return document::element from parser.parse()
This commit is contained in:
John Keiser 2020-03-28 08:45:14 -07:00 committed by GitHub
commit 9f265711a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 138 additions and 557 deletions

View File

@ -49,7 +49,7 @@ The simdjson library is easily consumable with a single .h and .cpp file.
#include "simdjson.h"
int main(void) {
simdjson::document::parser parser;
simdjson::document& tweets = parser.load("twitter.json");
simdjson::document::element tweets = parser.load("twitter.json");
std::cout << tweets["search_metadata"]["count"] << " results." << std::endl;
}
```

View File

@ -17,7 +17,7 @@ const padded_string EMPTY_ARRAY("[]", 2);
static void twitter_count(State& state) {
// Prints the number of results in twitter.json
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
uint64_t result_count = doc["search_metadata"]["count"];
if (result_count != 100) { return; }
@ -45,7 +45,7 @@ BENCHMARK(iterator_twitter_count);
static void twitter_default_profile(State& state) {
// Count unique users with a default profile.
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
set<string_view> default_users;
for (document::object tweet : doc["statuses"].as_array()) {
@ -62,7 +62,7 @@ BENCHMARK(twitter_default_profile);
static void twitter_image_sizes(State& state) {
// Count unique image sizes
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
set<tuple<uint64_t, uint64_t>> image_sizes;
for (document::object tweet : doc["statuses"].as_array()) {
@ -85,7 +85,7 @@ BENCHMARK(twitter_image_sizes);
static void error_code_twitter_count(State& state) noexcept {
// Prints the number of results in twitter.json
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
auto [value, error] = doc["search_metadata"]["count"].as_uint64_t();
if (error) { return; }
@ -97,7 +97,7 @@ BENCHMARK(error_code_twitter_count);
static void error_code_twitter_default_profile(State& state) noexcept {
// Count unique users with a default profile.
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
set<string_view> default_users;
@ -161,7 +161,7 @@ BENCHMARK(iterator_twitter_default_profile);
static void error_code_twitter_image_sizes(State& state) noexcept {
// Count unique image sizes
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
set<tuple<uint64_t, uint64_t>> image_sizes;
auto [statuses, error] = doc["statuses"].as_array();

View File

@ -29,7 +29,7 @@ static void parser_parse_exception(State& state) {
if (parser.set_capacity(EMPTY_ARRAY.length())) { return; }
for (auto _ : state) {
try {
UNUSED document &doc = parser.parse(EMPTY_ARRAY);
UNUSED document::element doc = parser.parse(EMPTY_ARRAY);
} catch(simdjson_error &j) {
return;
}
@ -56,7 +56,7 @@ static void document_parse_exception(State& state) {
for (auto _ : state) {
try {
document::parser parser;
UNUSED document &doc = parser.parse(EMPTY_ARRAY);
UNUSED document::element doc = parser.parse(EMPTY_ARRAY);
} catch(simdjson_error &j) {
return;
}

View File

@ -95,9 +95,9 @@ void simdjson_recurse(std::vector<int64_t> & v, simdjson::document::element elem
}
__attribute__((noinline)) std::vector<int64_t>
simdjson_just_dom(simdjson::document &doc) {
simdjson_just_dom(simdjson::document::element doc) {
std::vector<int64_t> answer;
simdjson_recurse(answer, doc.root());
simdjson_recurse(answer, doc);
remove_duplicates(answer);
return answer;
}
@ -106,8 +106,8 @@ __attribute__((noinline)) std::vector<int64_t>
simdjson_compute_stats(const simdjson::padded_string &p) {
std::vector<int64_t> answer;
simdjson::document::parser parser;
simdjson::document &doc = parser.parse(p);
simdjson_recurse(answer, doc.root());
simdjson::document::element doc = parser.parse(p);
simdjson_recurse(answer, doc);
remove_duplicates(answer);
return answer;
}
@ -368,7 +368,7 @@ int main(int argc, char *argv[]) {
BEST_TIME("sasjon (just parse) ", sasjon_just_parse(p), false, , repeat,
volume, !just_data);
simdjson::document::parser parser;
simdjson::document &doc = parser.parse(p);
simdjson::document::element doc = parser.parse(p);
BEST_TIME("simdjson (just dom) ", simdjson_just_dom(doc).size(), size,
, repeat, volume, !just_data);
char *buffer = (char *)malloc(p.size() + 1);

View File

@ -95,7 +95,7 @@ simdjson_compute_stats(const simdjson::padded_string &p) {
return s;
}
s.valid = true;
simdjson_recurse(s, doc.root());
simdjson_recurse(s, doc);
return s;
}

View File

@ -104,7 +104,7 @@ stat_t simdjson_compute_stats(const simdjson::padded_string &p) {
reinterpret_cast<const uint8_t *>(p.data()), p.size());
answer.byte_count = p.size();
answer.structural_indexes_count = parser.n_structural_indexes;
simdjson_recurse(answer, doc.root());
simdjson_recurse(answer, doc);
return answer;
}

View File

@ -38,7 +38,7 @@ The simdjson library offers a simple DOM tree API, which you can access by creat
```c++
document::parser parser;
document &doc = parser.load(filename); // load and parse a file
document::element doc = parser.load(filename); // load and parse a file
```
Or by creating a padded string (for efficiency reasons, simdjson requires a string with
@ -46,16 +46,14 @@ SIMDJSON_PADDING bytes at the end) and calling `parse()`:
```c++
document::parser parser;
document &doc = parser.parse("[1,2,3]"_padded); // parse a string
document::element doc = parser.parse("[1,2,3]"_padded); // parse a string
```
Using the Parsed JSON
---------------------
Once you have a document, you can navigate it with idiomatic C++ iterators, operators and casts.
Once you have an element, you can navigate it with idiomatic C++ iterators, operators and casts.
* **Document Root:** To get the top level JSON element, get `doc.root()`. Many of the
methods below will work on the document object itself, as well.
* **Extracting Values:** You can cast a JSON element to a native type: `double(element)` or
`double x = json_element`. This works for double, uint64_t, int64_t, bool,
document::object and document::array. You can also use is_*typename*()` to test if it is a
@ -112,7 +110,7 @@ auto cars_json = R"( [
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
document::parser parser;
document &cars = parser.parse(cars_json);
document::element cars = parser.parse(cars_json);
cout << cars["/0/tire_pressure/1"] << endl; // Prints 39.9
```
@ -123,7 +121,7 @@ All simdjson APIs that can fail return `simdjson_result<T>`, which is a &lt;valu
pair. The error codes and values can be accessed directly, reading the error like so:
```c++
auto [doc, error] = parser.parse(json); // doc is a document&
auto [doc, error] = parser.parse(json); // doc is a document::element
if (error) { cerr << error << endl; exit(1); }
// Use document here now that we've checked for the error
```
@ -138,7 +136,7 @@ behavior.
> circumvent this, you can use this instead:
>
> ```c++
> document &doc;
> document::element doc;
> error_code error;
> parser.parse(json).tie(doc, error); // <-- Assigns to doc and error just like "auto [doc, error]"
> ```
@ -199,7 +197,7 @@ for (document::element car_element : cars) {
Users more comfortable with an exception flow may choose to directly cast the `simdjson_result<T>` to the desired type:
```c++
document &doc = parser.parse(json); // Throws an exception if there was an error!
document::element doc = parser.parse(json); // Throws an exception if there was an error!
```
When used this way, a `simdjson_error` exception will be thrown if an error occurs, preventing the
@ -219,7 +217,7 @@ auto ndjson = R"(
{ "foo": 3 }
)"_padded;
document::parser parser;
for (document &doc : parser.load_many(filename)) {
for (document::element doc : parser.load_many(filename)) {
cout << doc["foo"] << endl;
}
// Prints 1 2 3

View File

@ -21,7 +21,7 @@ buffers hot in cache and keeping memory allocation and initialization to a minim
document::parser parser;
// This initializes buffers and a document big enough to handle this JSON.
document &doc = parser.parse("[ true, false ]"_padded);
document::element doc = parser.parse("[ true, false ]"_padded);
cout << doc << endl;
// This reuses the existing buffers, and reuses and *overwrites* the old document
@ -29,17 +29,16 @@ doc = parser.parse("[1, 2, 3]"_padded);
cout << doc << endl;
// This also reuses the existing buffers, and reuses and *overwrites* the old document
document &doc2 = parser.parse("true"_padded);
document::element doc2 = parser.parse("true"_padded);
// Even if you keep the old reference around, doc and doc2 refer to the same document.
cout << doc << endl;
cout << doc2 << endl;
```
It's not just internal buffers though. The simdjson library reuses the document itself. Notice that reference?
`document &doc`? That's key. You are only *borrowing* the document from simdjson, which purposely
reuses and overwrites it each time you call parse. This prevent wasteful and unnecessary memory
allocation in 99% of cases where JSON is just read, used, and converted to native values
or thrown away.
It's not just internal buffers though. The simdjson library reuses the document itself. document::element, document::object and document::array are *references* to the internal document.
You are only *borrowing* the document from simdjson, which purposely reuses and overwrites it each
time you call parse. This prevent wasteful and unnecessary memory allocation in 99% of cases where
JSON is just read, used, and converted to native values or thrown away.
> **You are only borrowing the document from the simdjson parser. Don't keep it long term!**
@ -47,38 +46,6 @@ This is key: don't keep the `document&`, `document::element`, `document::array`,
or `string_view` objects you get back from the API. Convert them to C++ native values, structs and
arrays that you own.
### Keeping documents around for longer
If you really need to keep parsed JSON documents around for a long time, you can **take** the
document by declaring an actual `document` value.
```c++
document::parser parser;
// This initializes buffers and a document big enough to handle this JSON.
// By casting to document instead of document&, it "steals" the document from the parser so that it
// cannot be overwritten.
document keep_doc = parser.parse("[ true, false ]"_padded);
// This reuses the existing buffers, but initializes a new document.
document &doc = parser.parse("[1, 2, 3]"_padded);
// Now keep_doc and doc refer to different documents.
cout << keep_doc << endl;
cout << doc << endl;
```
If you're using error codes, it can be done like this:
```c++
auto [doc_ref, error] = parser.parse(json); // doc_ref is a document&
if (error) { cerr << error << endl; exit(1); }
document keep_doc = doc_ref; // "steal" the document from the parser
```
This won't allocate anything or copy document memory: instead, it will *steal* the document memory
from the parser. The parser will simply allocate new document memory the next time you call parse.
Server Loops: Long-Running Processes and Memory Capacity
--------------------------------------------------------

View File

@ -59,7 +59,7 @@ public:
class parser;
class stream;
class doc_result;
class element_result;
class element_result;
class array_result;
class object_result;
@ -69,35 +69,6 @@ public:
* Get the root element of this document as a JSON array.
*/
element root() const noexcept;
/**
* Get the root element of this document as a JSON array.
*/
array_result as_array() const noexcept;
/**
* Get the root element of this document as a JSON object.
*/
object_result as_object() const noexcept;
/**
* Get the root element of this document.
*/
operator element() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
* Read the root element of this document as a JSON array.
*
* @return The JSON array.
* @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not an array
*/
operator array() const noexcept(false);
/**
* Read this element as a JSON object (key/value pairs).
*
* @return The JSON object.
* @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not an object
*/
operator object() const noexcept(false);
#endif // SIMDJSON_EXCEPTIONS
/**
* Dump the raw tape for debugging.
@ -107,93 +78,6 @@ public:
*/
bool dump_raw_tape(std::ostream &os) const noexcept;
/**
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc["/foo/a/1"] == 20
* doc["/"]["foo"]["a"].at(1) == 20
* doc[""]["foo"]["a"].at(1) == 20
*
* @return The value associated with the given JSON pointer, or:
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
*/
inline element_result operator[](std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc["/foo/a/1"] == 20
* doc["/"]["foo"]["a"].at(1) == 20
* doc[""]["foo"]["a"].at(1) == 20
*
* @return The value associated with the given JSON pointer, or:
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
*/
inline element_result operator[](const char *json_pointer) const noexcept;
/**
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc.at("/foo/a/1") == 20
* doc.at("/")["foo"]["a"].at(1) == 20
* doc.at("")["foo"]["a"].at(1) == 20
*
* @return The value associated with the given JSON pointer, or:
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
*/
inline element_result at(std::string_view json_pointer) const noexcept;
/**
* Get the value at the given index.
*
* @return The value at the given index, or:
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
*/
inline element_result at(size_t index) const noexcept;
/**
* Get the value associated with the given key.
*
* The key will be matched against **unescaped** JSON:
*
* document::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(std::string_view s) const noexcept;
/**
* Get the value associated with the given key.
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *s) const noexcept;
std::unique_ptr<uint64_t[]> tape;
std::unique_ptr<uint8_t[]> string_buf;// should be at least byte_capacity
@ -206,154 +90,6 @@ private:
template<typename T>
class minify;
/**
* A parsed document reference, or an error if the parse failed.
*
* document::parser parser;
* document &doc = parser.parse(json);
*
* ## Document Ownership
*
* The `document &` refers to an internal document the parser reuses on each `parse()` call. It will
* become invalidated on the next `parse()`.
*
* This is more efficient for common cases where documents are parsed and used one at a time. If you
* need to keep the document around longer, you may *take* it from the parser by casting it:
*
* document &doc = parser.parse(); // take ownership
*
* If you do this, the parser will automatically allocate a new document on the next `parse()` call.
*
* ## Error Codes vs. Exceptions
*
* This result type allows the user to pick whether to use exceptions or not.
*
* Use like this to avoid exceptions:
*
* auto [doc, error] = parser.parse(json);
* if (error) { exit(1); }
*
* Use like this if you'd prefer to use exceptions:
*
* document &doc = parser.parse(json);
*
*/
class document::doc_result : public simdjson_result<document&> {
public:
/**
* Read this document as a JSON objec.
*
* @return The object value, or:
* - UNEXPECTED_TYPE if the JSON document is not an object
*/
inline object_result as_object() const noexcept;
/**
* Read this document as a JSON array.
*
* @return The array value, or:
* - UNEXPECTED_TYPE if the JSON document is not an array
*/
inline array_result as_array() const noexcept;
/**
* Get the root element of this document.
*/
inline element_result root() const noexcept;
/**
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc["/foo/a/1"] == 20
* doc["/"]["foo"]["a"].at(1) == 20
* doc[""]["foo"]["a"].at(1) == 20
*
* @return The value associated with the given JSON pointer, or:
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
*/
inline element_result operator[](std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc["/foo/a/1"] == 20
* doc["/"]["foo"]["a"].at(1) == 20
* doc[""]["foo"]["a"].at(1) == 20
*
* @return The value associated with the given JSON pointer, or:
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
*/
inline element_result operator[](const char *json_pointer) const noexcept;
/**
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc.at("/foo/a/1") == 20
* doc.at("/")["foo"]["a"].at(1) == 20
* doc.at("")["foo"]["a"].at(1) == 20
*
* @return The value associated with the given JSON pointer, or:
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
*/
inline element_result at(std::string_view json_pointer) const noexcept;
/**
* Get the value at the given index.
*
* @return The value at the given index, or:
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
*/
inline element_result at(size_t index) const noexcept;
/**
* Get the value associated with the given key.
*
* The key will be matched against **unescaped** JSON:
*
* document::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(std::string_view s) const noexcept;
/**
* Get the value associated with the given key.
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
*/
inline element_result at_key(const char *s) const noexcept;
~doc_result()=default;
doc_result(document &doc, error_code error) noexcept;
friend class document::parser;
friend class document::stream;
}; // class document::doc_result
namespace internal {
/**
* The possible types in the tape. Internal only.
@ -579,7 +315,7 @@ public:
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* document::element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc["/foo/a/1"] == 20
* doc["/"]["foo"]["a"].at(1) == 20
* doc[""]["foo"]["a"].at(1) == 20
@ -596,7 +332,7 @@ public:
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* document::element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc["/foo/a/1"] == 20
* doc["/"]["foo"]["a"].at(1) == 20
* doc[""]["foo"]["a"].at(1) == 20
@ -613,7 +349,7 @@ public:
* Get the value associated with the given JSON pointer.
*
* document::parser parser;
* document &doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* document::element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* doc.at("/foo/a/1") == 20
* doc.at("/")["foo"]["a"].at(1) == 20
* doc.at("")["foo"]["a"].at(1) == 20
@ -662,6 +398,9 @@ public:
*/
inline element_result at_key(const char *s) const noexcept;
/** @private for debugging. Prints out the root element. */
inline bool dump_raw_tape(std::ostream &out) const noexcept;
private:
really_inline element(const document *_doc, size_t _json_index) noexcept;
friend class document;
@ -947,8 +686,7 @@ private:
friend class document::object;
};
/** The result of a JSON navigation that may fail. */
/** The result of a JSON navigation that may fail. */
class document::element_result : public simdjson_result<document::element> {
public:
really_inline element_result() noexcept;
@ -1070,7 +808,7 @@ public:
* Load a JSON document from a file and return a reference to it.
*
* document::parser parser;
* const document &doc = parser.load("jsonexamples/twitter.json");
* const document::element doc = parser.load("jsonexamples/twitter.json");
*
* ### IMPORTANT: Document Lifetime
*
@ -1090,13 +828,13 @@ public:
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
* - other json errors if parsing fails.
*/
inline doc_result load(const std::string& path) noexcept;
inline element_result load(const std::string& path) noexcept;
/**
* Load a file containing many JSON documents.
*
* document::parser parser;
* for (const document &doc : parser.parse_many(path)) {
* for (const document::element doc : parser.parse_many(path)) {
* cout << std::string(doc["title"]) << endl;
* }
*
@ -1153,7 +891,7 @@ public:
* Parse a JSON document and return a temporary reference to it.
*
* document::parser parser;
* const document &doc = parser.parse(buf, len);
* document::element doc = parser.parse(buf, len);
*
* ### IMPORTANT: Document Lifetime
*
@ -1184,13 +922,13 @@ public:
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
* - other json errors if parsing fails.
*/
inline doc_result parse(const uint8_t *buf, size_t len, bool realloc_if_needed = true) noexcept;
inline element_result parse(const uint8_t *buf, size_t len, bool realloc_if_needed = true) noexcept;
/**
* Parse a JSON document and return a temporary reference to it.
*
* document::parser parser;
* const document &doc = parser.parse(buf, len);
* const document::element doc = parser.parse(buf, len);
*
* ### IMPORTANT: Document Lifetime
*
@ -1221,13 +959,13 @@ public:
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
* - other json errors if parsing fails.
*/
really_inline doc_result parse(const char *buf, size_t len, bool realloc_if_needed = true) noexcept;
really_inline element_result parse(const char *buf, size_t len, bool realloc_if_needed = true) noexcept;
/**
* Parse a JSON document and return a temporary reference to it.
*
* document::parser parser;
* const document &doc = parser.parse(s);
* const document::element doc = parser.parse(s);
*
* ### IMPORTANT: Document Lifetime
*
@ -1256,13 +994,13 @@ public:
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
* - other json errors if parsing fails.
*/
really_inline doc_result parse(const std::string &s) noexcept;
really_inline element_result parse(const std::string &s) noexcept;
/**
* Parse a JSON document and return a temporary reference to it.
*
* document::parser parser;
* const document &doc = parser.parse(s);
* const document::element doc = parser.parse(s);
*
* ### IMPORTANT: Document Lifetime
*
@ -1281,16 +1019,16 @@ public:
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
* - other json errors if parsing fails.
*/
really_inline doc_result parse(const padded_string &s) noexcept;
really_inline element_result parse(const padded_string &s) noexcept;
// We do not want to allow implicit conversion from C string to std::string.
really_inline doc_result parse(const char *buf) noexcept = delete;
really_inline element_result parse(const char *buf) noexcept = delete;
/**
* Parse a buffer containing many JSON documents.
*
* document::parser parser;
* for (const document &doc : parser.parse_many(buf, len)) {
* for (const document::element doc : parser.parse_many(buf, len)) {
* cout << std::string(doc["title"]) << endl;
* }
*
@ -1352,7 +1090,7 @@ public:
* Parse a buffer containing many JSON documents.
*
* document::parser parser;
* for (const document &doc : parser.parse_many(buf, len)) {
* for (const document::element doc : parser.parse_many(buf, len)) {
* cout << std::string(doc["title"]) << endl;
* }
*
@ -1414,7 +1152,7 @@ public:
* Parse a buffer containing many JSON documents.
*
* document::parser parser;
* for (const document &doc : parser.parse_many(buf, len)) {
* for (const document::element doc : parser.parse_many(buf, len)) {
* cout << std::string(doc["title"]) << endl;
* }
*
@ -1475,7 +1213,7 @@ public:
* Parse a buffer containing many JSON documents.
*
* document::parser parser;
* for (const document &doc : parser.parse_many(buf, len)) {
* for (const document::element doc : parser.parse_many(buf, len)) {
* cout << std::string(doc["title"]) << endl;
* }
*
@ -1528,7 +1266,7 @@ public:
inline stream parse_many(const padded_string &s, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept;
// We do not want to allow implicit conversion from C string to std::string.
really_inline doc_result parse_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
really_inline element_result parse_many(const char *buf, size_t batch_size = DEFAULT_BATCH_SIZE) noexcept = delete;
/**
* The largest document this parser can automatically support.
@ -1730,11 +1468,6 @@ private:
//
inline simdjson_result<size_t> read_file(const std::string &path) noexcept;
#if SIMDJSON_EXCEPTIONS
// Used internally to get the document
inline const document &get_document() const noexcept(false);
#endif // SIMDJSON_EXCEPTIONS
friend class document::parser::Iterator;
friend class document::stream;
}; // class parser
@ -1743,7 +1476,7 @@ private:
* Minifies a JSON element or document, printing the smallest possible valid JSON.
*
* document::parser parser;
* document &doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
* document::element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
* cout << minify(doc) << endl; // prints [1,2,3]
*
*/
@ -1780,16 +1513,6 @@ private:
template<typename T>
inline std::ostream& operator<<(std::ostream& out, minify<T> formatter) { return formatter.print(out); }
/**
* Print JSON to an output stream.
*
* By default, the document will be printed minified.
*
* @param out The output stream.
* @param value The document to print.
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
*/
inline std::ostream& operator<<(std::ostream& out, const document &value) { return out << minify(value); }
/**
* Print JSON to an output stream.
*
@ -1833,18 +1556,6 @@ inline std::ostream& operator<<(std::ostream& out, const document::key_value_pai
#if SIMDJSON_EXCEPTIONS
/**
* Print JSON to an output stream.
*
* By default, the value will be printed minified.
*
* @param out The output stream.
* @param value The value to print.
* @throw simdjson_error if the result being printed has an error. If there is an error with the
* underlying output stream, that error will be propagated (simdjson_error will not be
* thrown).
*/
inline std::ostream& operator<<(std::ostream& out, const document::doc_result &value) noexcept(false) { return out << minify(value); }
/**
* Print JSON to an output stream.
*

View File

@ -24,7 +24,7 @@ public:
/**
* Get the current document (or error).
*/
really_inline doc_result operator*() noexcept;
really_inline element_result operator*() noexcept;
/**
* Advance to the next document.
*/

View File

@ -191,53 +191,11 @@ inline document::object::iterator document::object_result::end() const noexcept(
inline document::element document::root() const noexcept {
return element(this, 1);
}
inline document::array_result document::as_array() const noexcept {
return root().as_array();
}
inline document::object_result document::as_object() const noexcept {
return root().as_object();
}
inline document::operator element() const noexcept {
return root();
}
#if SIMDJSON_EXCEPTIONS
inline document::operator document::array() const noexcept(false) {
return root();
}
inline document::operator document::object() const noexcept(false) {
return root();
}
#endif
//#define REPORT_ERROR(CODE, MESSAGE) ((std::cerr << MESSAGE << std::endl), CODE)
#define REPORT_ERROR(CODE, MESSAGE) (CODE)
#define RETURN_ERROR(CODE, MESSAGE) return REPORT_ERROR((CODE), (MESSAGE));
inline document::element_result document::at(std::string_view json_pointer) const noexcept {
if (json_pointer == "") { return root(); }
// NOTE: JSON pointer requires a / at the beginning of the document; we allow it to be optional.
return root().at(json_pointer.substr(json_pointer[0] == '/' ? 1 : 0));
}
inline document::element_result document::at(size_t index) const noexcept {
return as_array().at(index);
}
inline document::element_result document::at_key(std::string_view key) const noexcept {
return as_object().at_key(key);
}
inline document::element_result document::at_key(const char *key) const noexcept {
return as_object().at_key(key);
}
inline document::element_result document::operator[](std::string_view json_pointer) const noexcept {
return at(json_pointer);
}
inline document::element_result document::operator[](const char *json_pointer) const noexcept {
return (*this)[std::string_view(json_pointer)];
}
WARN_UNUSED
inline error_code document::set_capacity(size_t capacity) noexcept {
if (capacity == 0) {
@ -353,76 +311,23 @@ inline bool document::dump_raw_tape(std::ostream &os) const noexcept {
return true;
}
//
// doc_result inline implementation
//
inline document::doc_result::doc_result(document &doc, error_code error) noexcept : simdjson_result<document&>(doc, error) { }
inline document::array_result document::doc_result::as_array() const noexcept {
return root().as_array();
}
inline document::object_result document::doc_result::as_object() const noexcept {
return root().as_object();
}
inline document::element_result document::doc_result::root() const noexcept {
if (error()) { return error(); }
return first.root();
}
inline document::element_result document::doc_result::operator[](std::string_view key) const noexcept {
if (error()) { return error(); }
return first[key];
}
inline document::element_result document::doc_result::operator[](const char *json_pointer) const noexcept {
return (*this)[std::string_view(json_pointer)];
}
inline document::element_result document::doc_result::at(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at(key);
}
inline document::element_result document::doc_result::at(size_t index) const noexcept {
if (error()) { return error(); }
return first.at(index);
}
inline document::element_result document::doc_result::at_key(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at_key(key);
}
inline document::element_result document::doc_result::at_key(const char *key) const noexcept {
if (error()) { return error(); }
return first.at_key(key);
}
//
// document::parser inline implementation
//
really_inline document::parser::parser(size_t max_capacity, size_t max_depth) noexcept
: _max_capacity{max_capacity}, _max_depth{max_depth}, loaded_bytes(nullptr, &aligned_free_char) {
}
: _max_capacity{max_capacity}, _max_depth{max_depth}, loaded_bytes(nullptr, &aligned_free_char) {}
inline bool document::parser::is_valid() const noexcept { return valid; }
inline int document::parser::get_error_code() const noexcept { return error; }
inline std::string document::parser::get_error_message() const noexcept { return error_message(int(error)); }
inline bool document::parser::print_json(std::ostream &os) const noexcept {
if (!is_valid()) { return false; }
os << minify(doc);
os << doc.root();
return true;
}
inline bool document::parser::dump_raw_tape(std::ostream &os) const noexcept {
return is_valid() ? doc.dump_raw_tape(os) : false;
}
#if SIMDJSON_EXCEPTIONS
inline const document &document::parser::get_document() const noexcept(false) {
if (!is_valid()) {
throw simdjson_error(error);
}
return doc;
}
#endif // SIMDJSON_EXCEPTIONS
inline simdjson_result<size_t> document::parser::read_file(const std::string &path) noexcept {
// Open the file
std::FILE *fp = std::fopen(path.c_str(), "rb");
@ -461,9 +366,9 @@ inline simdjson_result<size_t> document::parser::read_file(const std::string &pa
return bytes_read;
}
inline document::doc_result document::parser::load(const std::string &path) noexcept {
inline document::element_result document::parser::load(const std::string &path) noexcept {
auto [len, code] = read_file(path);
if (code) { return doc_result(doc, code); }
if (code) { return code; }
return parse(loaded_bytes.get(), len, false);
}
@ -473,35 +378,36 @@ inline document::stream document::parser::load_many(const std::string &path, siz
return stream(*this, (const uint8_t*)loaded_bytes.get(), len, batch_size, code);
}
inline document::doc_result document::parser::parse(const uint8_t *buf, size_t len, bool realloc_if_needed) noexcept {
inline document::element_result document::parser::parse(const uint8_t *buf, size_t len, bool realloc_if_needed) noexcept {
error_code code = ensure_capacity(len);
if (code) { return doc_result(doc, code); }
if (code) { return code; }
if (realloc_if_needed) {
const uint8_t *tmp_buf = buf;
buf = (uint8_t *)internal::allocate_padded_buffer(len);
if (buf == nullptr)
return doc_result(doc, MEMALLOC);
return MEMALLOC;
memcpy((void *)buf, tmp_buf, len);
}
code = simdjson::active_implementation->parse(buf, len, *this);
// We're indicating validity via the doc_result, so set the parse state back to invalid
valid = false;
error = UNINITIALIZED;
if (realloc_if_needed) {
aligned_free((void *)buf); // must free before we exit
}
return doc_result(doc, code);
if (code) { return code; }
// We're indicating validity via the element_result, so set the parse state back to invalid
valid = false;
error = UNINITIALIZED;
return doc.root();
}
really_inline document::doc_result document::parser::parse(const char *buf, size_t len, bool realloc_if_needed) noexcept {
really_inline document::element_result document::parser::parse(const char *buf, size_t len, bool realloc_if_needed) noexcept {
return parse((const uint8_t *)buf, len, realloc_if_needed);
}
really_inline document::doc_result document::parser::parse(const std::string &s) noexcept {
really_inline document::element_result document::parser::parse(const std::string &s) noexcept {
return parse(s.data(), s.length(), s.capacity() - s.length() < SIMDJSON_PADDING);
}
really_inline document::doc_result document::parser::parse(const padded_string &s) noexcept {
really_inline document::element_result document::parser::parse(const padded_string &s) noexcept {
return parse(s.data(), s.length(), false);
}
@ -1027,14 +933,14 @@ inline document::element_result document::element::at_key(const char *key) const
return as_object().at_key(key);
}
inline bool document::element::dump_raw_tape(std::ostream &out) const noexcept {
return doc->dump_raw_tape(out);
}
//
// minify inline implementation
//
template<>
inline std::ostream& minify<document>::print(std::ostream& out) {
return out << minify<document::element>(value.root());
}
template<>
inline std::ostream& minify<document::element>::print(std::ostream& out) {
using tape_type=internal::tape_type;
@ -1191,11 +1097,6 @@ inline std::ostream& minify<document::key_value_pair>::print(std::ostream& out)
#if SIMDJSON_EXCEPTIONS
template<>
inline std::ostream& minify<document::doc_result>::print(std::ostream& out) {
if (value.error()) { throw simdjson_error(value.error()); }
return out << minify<document>(value.first);
}
template<>
inline std::ostream& minify<document::element_result>::print(std::ostream& out) {
if (value.error()) { throw simdjson_error(value.error()); }

View File

@ -127,8 +127,10 @@ really_inline document::stream::iterator::iterator(stream& stream, bool _is_end)
: _stream{stream}, finished{_is_end} {
}
really_inline document::doc_result document::stream::iterator::operator*() noexcept {
return doc_result(_stream.parser.doc, _stream.error == SUCCESS_AND_HAS_MORE ? SUCCESS : _stream.error);
really_inline document::element_result document::stream::iterator::operator*() noexcept {
error_code error = _stream.error == SUCCESS_AND_HAS_MORE ? SUCCESS : _stream.error;
if (error) { return error; }
return _stream.parser.doc.root();
}
really_inline document::stream::iterator& document::stream::iterator::operator++() noexcept {

View File

@ -1526,7 +1526,7 @@ public:
* Load a JSON document from a file and return a reference to it.
*
* document::parser parser;
* const document &doc = parser.load("jsonexamples/twitter.json");
* const document::element doc = parser.load("jsonexamples/twitter.json");
*
* ### IMPORTANT: Document Lifetime
*

View File

@ -49,7 +49,7 @@ namespace number_tests {
buf[n] = '\0';
fflush(NULL);
auto [actual, error] = parser.parse(buf, n).root().as_int64_t();
auto [actual, error] = parser.parse(buf, n).as_int64_t();
if (error) { std::cerr << error << std::endl; return false; }
if (actual != i) {
std::cerr << "JSON '" << buf << " parsed to " << actual << " instead of " << i << std::endl;
@ -57,11 +57,9 @@ namespace number_tests {
}
}
}
printf("Small integers can be parsed.\n");
return true;
}
bool powers_of_two() {
std::cout << __func__ << std::endl;
char buf[1024];
@ -72,8 +70,7 @@ namespace number_tests {
auto n = sprintf(buf, "%.*e", std::numeric_limits<double>::max_digits10 - 1, expected);
buf[n] = '\0';
fflush(NULL);
auto [actual, error] = parser.parse(buf, n).root().as_double();
auto [actual, error] = parser.parse(buf, n).as_double();
if (error) { std::cerr << error << std::endl; return false; }
int ulp = f64_ulp_dist(actual,expected);
if(ulp > maxulp) maxulp = ulp;
@ -82,7 +79,6 @@ namespace number_tests {
return false;
}
}
printf("Powers of 2 can be parsed, maxulp = %d.\n", maxulp);
return true;
}
@ -168,7 +164,7 @@ namespace number_tests {
buf[n] = '\0';
fflush(NULL);
auto [actual, error] = parser.parse(buf, n).root().as_double();
auto [actual, error] = parser.parse(buf, n).as_double();
if (error) { std::cerr << error << std::endl; return false; }
double expected = ((i >= -307) ? testing_power_of_ten[i + 307]: std::pow(10, i));
int ulp = (int) f64_ulp_dist(actual, expected);
@ -462,7 +458,7 @@ namespace parse_api_tests {
document::parser parser;
auto [doc, error] = parser.parse(BASIC_JSON);
if (error) { cerr << error << endl; return false; }
if (!doc.root().is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
if (!doc.is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
return true;
}
bool parser_parse_many() {
@ -471,7 +467,7 @@ namespace parse_api_tests {
int count = 0;
for (auto [doc, error] : parser.parse_many(BASIC_NDJSON)) {
if (error) { cerr << error << endl; return false; }
if (!doc.root().is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
if (!doc.is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
count++;
}
if (count != 2) { cerr << "parse_many returned " << count << " documents, expected 2" << endl; return false; }
@ -494,7 +490,7 @@ namespace parse_api_tests {
document::parser parser;
auto [doc, error] = parser.load(JSON_TEST_PATH);
if (error) { cerr << error << endl; return false; }
if (!doc.root().is_object()) { cerr << "Document did not parse as an object" << endl; return false; }
if (!doc.is_object()) { cerr << "Document did not parse as an object" << endl; return false; }
return true;
}
bool parser_load_many() {
@ -503,7 +499,7 @@ namespace parse_api_tests {
int count = 0;
for (auto [doc, error] : parser.load_many(NDJSON_TEST_PATH)) {
if (error) { cerr << error << endl; return false; }
if (!doc.root().is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
if (!doc.is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
count++;
}
if (count != 793) { cerr << "Expected 793 documents, but load_many loaded " << count << " documents." << endl; return false; }
@ -515,16 +511,16 @@ namespace parse_api_tests {
bool parser_parse_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
const document& doc = parser.parse(BASIC_JSON);
if (!doc.root().is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
document::element doc = parser.parse(BASIC_JSON);
if (!doc.is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
return true;
}
bool parser_parse_many_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
int count = 0;
for (const document &doc : parser.parse_many(BASIC_NDJSON)) {
if (!doc.root().is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
for (const document::element doc : parser.parse_many(BASIC_NDJSON)) {
if (!doc.is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
count++;
}
if (count != 2) { cerr << "parse_many returned " << count << " documents, expected 2" << endl; return false; }
@ -534,16 +530,16 @@ namespace parse_api_tests {
bool parser_load_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
const document &doc = parser.load(JSON_TEST_PATH);
if (!doc.root().is_object()) { cerr << "Document did not parse as an object" << endl; return false; }
const document::element doc = parser.load(JSON_TEST_PATH);
if (!doc.is_object()) { cerr << "Document did not parse as an object" << endl; return false; }
return true;
}
bool parser_load_many_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
int count = 0;
for (const document &doc : parser.load_many(NDJSON_TEST_PATH)) {
if (!doc.root().is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
for (const document::element doc : parser.load_many(NDJSON_TEST_PATH)) {
if (!doc.is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
count++;
}
if (count != 793) { cerr << "Expected 1 document, but load_many loaded " << count << " documents." << endl; return false; }
@ -927,7 +923,7 @@ namespace dom_api_tests {
int i = 0;
document::parser parser;
document &doc = parser.parse(json);
document::element doc = parser.parse(json);
for (auto [key, value] : doc.as_object()) {
if (key != expected_key[i] || uint64_t(value) != expected_value[i]) { cerr << "Expected " << expected_key[i] << " = " << expected_value[i] << ", got " << key << "=" << uint64_t(value) << endl; return false; }
i++;
@ -943,7 +939,7 @@ namespace dom_api_tests {
int i=0;
document::parser parser;
document &doc = parser.parse(json);
document::element doc = parser.parse(json);
for (uint64_t value : doc.as_array()) {
if (value != expected_value[i]) { cerr << "Expected " << expected_value[i] << ", got " << value << endl; return false; }
i++;
@ -1017,7 +1013,7 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "a": 1, "b": 2, "c": 3})");
document::parser parser;
document &doc = parser.parse(json);
document::element doc = parser.parse(json);
if (uint64_t(doc["a"]) != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << uint64_t(doc["a"]) << endl; return false; }
return true;
}
@ -1035,7 +1031,7 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
// Prints the number of results in twitter.json
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
uint64_t result_count = doc["search_metadata"]["count"];
if (result_count != 100) { cerr << "Expected twitter.json[metadata_count][count] = 100, got " << result_count << endl; return false; }
return true;
@ -1046,7 +1042,7 @@ namespace dom_api_tests {
// Print users with a default profile.
set<string_view> default_users;
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
for (document::object tweet : doc["statuses"].as_array()) {
document::object user = tweet["user"];
if (user["default_profile"]) {
@ -1062,7 +1058,7 @@ namespace dom_api_tests {
// Print image names and sizes
set<pair<uint64_t, uint64_t>> image_sizes;
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
document::element doc = parser.load(JSON_TEST_PATH);
for (document::object tweet : doc["statuses"].as_array()) {
auto [media, not_found] = tweet["entities"]["media"];
if (!not_found) {
@ -1217,7 +1213,7 @@ namespace format_tests {
bool print_element_result_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["foo"];
return assert_minified(s, "1");
@ -1225,7 +1221,7 @@ namespace format_tests {
bool print_minify_element_result_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["foo"]);
return assert_minified(s, "1");
@ -1234,7 +1230,7 @@ namespace format_tests {
bool print_element_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
document::element value = doc["foo"];
ostringstream s;
s << value;
@ -1243,7 +1239,7 @@ namespace format_tests {
bool print_minify_element_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
document::element value = doc["foo"];
ostringstream s;
s << minify(value);
@ -1253,7 +1249,7 @@ namespace format_tests {
bool print_array_result_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["bar"].as_array();
return assert_minified(s, "[1,2,3]");
@ -1261,7 +1257,7 @@ namespace format_tests {
bool print_minify_array_result_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["bar"].as_array());
return assert_minified(s, "[1,2,3]");
@ -1270,7 +1266,7 @@ namespace format_tests {
bool print_object_result_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["baz"].as_object();
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
@ -1278,7 +1274,7 @@ namespace format_tests {
bool print_minify_object_result_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["baz"].as_object());
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
@ -1287,7 +1283,7 @@ namespace format_tests {
bool print_array_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
document::array value = doc["bar"];
ostringstream s;
s << value;
@ -1296,7 +1292,7 @@ namespace format_tests {
bool print_minify_array_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
document::array value = doc["bar"];
ostringstream s;
s << minify(value);
@ -1306,7 +1302,7 @@ namespace format_tests {
bool print_object_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
document::object value = doc["baz"];
ostringstream s;
s << value;
@ -1315,7 +1311,7 @@ namespace format_tests {
bool print_minify_object_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element doc = parser.parse(DOCUMENT);
document::object value = doc["baz"];
ostringstream s;
s << minify(value);

View File

@ -74,8 +74,8 @@ namespace parser_load {
bool parser_load_many_chain() {
TEST_START();
document::parser parser;
for (auto doc_result : parser.load_many(NONEXISTENT_FILE)) {
auto [val, error] = doc_result["foo"].as_uint64_t();
for (auto doc : parser.load_many(NONEXISTENT_FILE)) {
auto [val, error] = doc["foo"].as_uint64_t();
ASSERT_ERROR(error, IO_ERROR);
TEST_SUCCEED();
}

View File

@ -60,23 +60,29 @@ bool json_pointer_failure_test(const char *json_pointer, error_code expected_fai
int main() {
if (
json_pointer_success_test("/~1~001abc/1/\\\" 0/0", "value0") &&
json_pointer_success_test("/~1~001abc/1/\\\" 0/1", "value1") &&
json_pointer_failure_test("/~1~001abc/1/\\\" 0/2", INDEX_OUT_OF_BOUNDS) && // index actually out of bounds
json_pointer_success_test("/arr") && // get array
json_pointer_failure_test("/arr/0", INDEX_OUT_OF_BOUNDS) && // array index 0 out of bounds on empty array
json_pointer_success_test("/~1~001abc") && // get object
json_pointer_success_test("/0", "0 ok") && // object index with integer-ish key
json_pointer_success_test("/01", "01 ok") && // object index with key that would be an invalid integer
json_pointer_success_test("/", "empty ok") && // object index with empty key
json_pointer_failure_test("/~01abc", NO_SUCH_FIELD) && // Test that we don't try to compare the literal key
json_pointer_failure_test("/~1~001abc/01", INVALID_JSON_POINTER) && // Leading 0 in integer index
json_pointer_failure_test("/~1~001abc/", INVALID_JSON_POINTER) && // Empty index to array
json_pointer_failure_test("/~1~001abc/-", INDEX_OUT_OF_BOUNDS) && // End index is always out of bounds
json_pointer_success_test("") &&
json_pointer_success_test("~1~001abc") &&
json_pointer_success_test("~1~001abc/1") &&
json_pointer_success_test("~1~001abc/1/\\\" 0") &&
json_pointer_success_test("~1~001abc/1/\\\" 0/0", "value0") &&
json_pointer_success_test("~1~001abc/1/\\\" 0/1", "value1") &&
json_pointer_failure_test("~1~001abc/1/\\\" 0/2", INDEX_OUT_OF_BOUNDS) && // index actually out of bounds
json_pointer_success_test("arr") && // get array
json_pointer_failure_test("arr/0", INDEX_OUT_OF_BOUNDS) && // array index 0 out of bounds on empty array
json_pointer_success_test("~1~001abc") && // get object
json_pointer_success_test("0", "0 ok") && // object index with integer-ish key
json_pointer_success_test("01", "01 ok") && // object index with key that would be an invalid integer
json_pointer_success_test("", "empty ok") && // object index with empty key
json_pointer_failure_test("~01abc", NO_SUCH_FIELD) && // Test that we don't try to compare the literal key
json_pointer_failure_test("~1~001abc/01", INVALID_JSON_POINTER) && // Leading 0 in integer index
json_pointer_failure_test("~1~001abc/", INVALID_JSON_POINTER) && // Empty index to array
json_pointer_failure_test("~1~001abc/-", INDEX_OUT_OF_BOUNDS) && // End index is always out of bounds
true
) {
std::cout << "Success!" << std::endl;
return 0;
} else {
std::cerr << "Failed!" << std::endl;
return 1;
}
}

View File

@ -99,7 +99,7 @@ void parser_parse_many_exception() {
auto json = "[1, 2, 3] true [ true, false ]"_padded;
cout << "Parsing " << json.data() << " ..." << endl;
document::parser parser;
for (const document &doc : parser.parse_many(json)) {
for (const document::element doc : parser.parse_many(json)) {
cout << doc << endl;
}
}

View File

@ -141,7 +141,7 @@ stat_t simdjson_compute_stats(const simdjson::padded_string &p) {
s.structural_indexes_count = parser.n_structural_indexes;
// simdjson::document::iterator iter(doc);
recurse(doc.root(), s, 0);
recurse(doc, s, 0);
return s;
}