Remove document::parse and document::load

This commit is contained in:
John Keiser 2020-03-25 14:43:23 -07:00
parent 5aec2671ea
commit 2e420169c3
11 changed files with 143 additions and 467 deletions

View File

@ -16,7 +16,8 @@ const padded_string EMPTY_ARRAY("[]", 2);
static void twitter_count(State& state) {
// Prints the number of results in twitter.json
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
uint64_t result_count = doc["search_metadata"]["count"];
if (result_count != 100) { return; }
@ -43,7 +44,8 @@ BENCHMARK(iterator_twitter_count);
static void twitter_default_profile(State& state) {
// Count unique users with a default profile.
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
set<string_view> default_users;
for (document::object tweet : doc["statuses"].as_array()) {
@ -59,7 +61,8 @@ BENCHMARK(twitter_default_profile);
static void twitter_image_sizes(State& state) {
// Count unique image sizes
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &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()) {
@ -81,7 +84,8 @@ BENCHMARK(twitter_image_sizes);
static void error_code_twitter_count(State& state) noexcept {
// Prints the number of results in twitter.json
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
auto [value, error] = doc["search_metadata"]["count"].as_uint64_t();
if (error) { return; }
@ -92,7 +96,8 @@ BENCHMARK(error_code_twitter_count);
static void error_code_twitter_default_profile(State& state) noexcept {
// Count unique users with a default profile.
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
for (auto _ : state) {
set<string_view> default_users;
@ -155,7 +160,8 @@ BENCHMARK(iterator_twitter_default_profile);
static void error_code_twitter_image_sizes(State& state) noexcept {
// Count unique image sizes
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &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

@ -46,7 +46,8 @@ static void build_parsed_json(State& state) {
BENCHMARK(build_parsed_json);
static void document_parse_error_code(State& state) {
for (auto _ : state) {
auto [doc, error] = document::parse(EMPTY_ARRAY);
document::parser parser;
auto [doc, error] = parser.parse(EMPTY_ARRAY);
if (error) { return; }
}
}
@ -54,7 +55,8 @@ BENCHMARK(document_parse_error_code);
static void document_parse_exception(State& state) {
for (auto _ : state) {
try {
UNUSED document doc = document::parse(EMPTY_ARRAY);
document::parser parser;
UNUSED document &doc = parser.parse(EMPTY_ARRAY);
} catch(simdjson_error &j) {
return;
}

View File

@ -114,7 +114,8 @@ simdjson_compute_stats(const simdjson::padded_string &p) {
__attribute__((noinline)) bool
simdjson_just_parse(const simdjson::padded_string &p) {
return simdjson::document::parse(p).error() == simdjson::SUCCESS;
simdjson::document::parser parser;
return parser.parse(p).error() != simdjson::SUCCESS;
}
void sajson_traverse(std::vector<int64_t> &answer, const sajson::value &node) {
@ -368,7 +369,7 @@ int main(int argc, char *argv[]) {
volume, !just_data);
simdjson::document::parser parser;
simdjson::document &doc = parser.parse(p);
BEST_TIME("simdjson (just dom)", simdjson_just_dom(doc).size(), size,
BEST_TIME("simdjson (just dom) ", simdjson_just_dom(doc).size(), size,
, repeat, volume, !just_data);
char *buffer = (char *)malloc(p.size() + 1);
buffer[p.size()] = '\0';

View File

@ -59,7 +59,6 @@ public:
class parser;
class stream;
class doc_move_result;
class doc_result;
class element_result;
class array_result;
@ -108,85 +107,11 @@ public:
*/
bool dump_raw_tape(std::ostream &os) const noexcept;
/**
* Load a JSON document from a file and return it.
*
* document doc = document::load("jsonexamples/twitter.json");
*
* ### Parser Capacity
*
* If the parser's current capacity is less than the file length, it will allocate enough capacity
* to handle it (up to max_capacity).
*
* @param path The path to load.
* @return The document, or an error:
* - IO_ERROR if there was an error opening or reading the file.
* - MEMALLOC if the parser does not have enough capacity and memory allocation fails.
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
* - other json errors if parsing fails.
*/
inline static doc_move_result load(const std::string& path) noexcept;
/**
* Parse a JSON document and return a reference to it.
*
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
* those bytes are initialized to, as long as they are allocated. If realloc_if_needed is true,
* it is assumed that the buffer does *not* have enough padding, and it is reallocated, enlarged
* and copied before parsing.
*
* @param buf The JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes, unless
* realloc_if_needed is true.
* @param len The length of the JSON.
* @param realloc_if_needed Whether to reallocate and enlarge the JSON buffer to add padding.
* @return the document, or an error if the JSON is invalid.
*/
inline static doc_move_result parse(const uint8_t *buf, size_t len, bool realloc_if_needed = true) noexcept;
/**
* Parse a JSON document.
*
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
* those bytes are initialized to, as long as they are allocated. If realloc_if_needed is true,
* it is assumed that the buffer does *not* have enough padding, and it is reallocated, enlarged
* and copied before parsing.
*
* @param buf The JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes, unless
* realloc_if_needed is true.
* @param len The length of the JSON.
* @param realloc_if_needed Whether to reallocate and enlarge the JSON buffer to add padding.
* @return the document, or an error if the JSON is invalid.
*/
really_inline static doc_move_result parse(const char *buf, size_t len, bool realloc_if_needed = true) noexcept;
/**
* Parse a JSON document.
*
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
* those bytes are initialized to, as long as they are allocated. If `str.capacity() - str.size()
* < SIMDJSON_PADDING`, the string will be copied to a string with larger capacity before parsing.
*
* @param s The JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes, or
* a new string will be created with the extra padding.
* @return the document, or an error if the JSON is invalid.
*/
really_inline static doc_move_result parse(const std::string &s) noexcept;
/**
* Parse a JSON document.
*
* @param s The JSON to parse.
* @return the document, or an error if the JSON is invalid.
*/
really_inline static doc_move_result parse(const padded_string &s) noexcept;
// We do not want to allow implicit conversion from C string to std::string.
doc_result parse(const char *buf, bool realloc_if_needed = true) noexcept = delete;
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -202,7 +127,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -218,7 +144,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -244,8 +171,9 @@ public:
*
* The key will be matched against **unescaped** JSON:
*
* document::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* 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
@ -257,8 +185,9 @@ public:
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* 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
@ -277,140 +206,11 @@ private:
template<typename T>
class minify;
/**
* A parsed, *owned* document, or an error if the parse failed.
*
* document &doc = document::parse(json);
*
* Returns an owned `document`. When the doc_move_result (or the document retrieved from it) goes out of
* scope, the document's memory is deallocated.
*
* ## 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] = document::parse(json);
* if (error) { exit(1); }
*
* Use like this if you'd prefer to use exceptions:
*
* document doc = document::parse(json);
*
*/
class document::doc_move_result : public simdjson_move_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 value associated with the given JSON pointer.
*
* document doc = document::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 doc = document::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 doc = document::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::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::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::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::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_move_result() noexcept=default;
doc_move_result(document &&doc, error_code error) noexcept;
doc_move_result(document &&doc) noexcept;
doc_move_result(error_code error) noexcept;
friend class document;
}; // class document::doc_move_result
/**
* A parsed document reference, or an error if the parse failed.
*
* document &doc = document::parse(json);
* document::parser parser;
* document &doc = parser.parse(json);
*
* ## Document Ownership
*
@ -420,7 +220,7 @@ public:
* 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
* document &doc = parser.parse(); // take ownership
*
* If you do this, the parser will automatically allocate a new document on the next `parse()` call.
*
@ -435,7 +235,7 @@ public:
*
* Use like this if you'd prefer to use exceptions:
*
* document &doc = document::parse(json);
* document &doc = parser.parse(json);
*
*/
class document::doc_result : public simdjson_result<document&> {
@ -459,7 +259,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -475,7 +276,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -491,7 +293,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -517,8 +320,9 @@ public:
*
* The key will be matched against **unescaped** JSON:
*
* document::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* 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
@ -530,8 +334,9 @@ public:
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* 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
@ -763,7 +568,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -779,7 +585,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -795,7 +602,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document doc = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* 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
@ -821,8 +629,9 @@ public:
*
* The key will be matched against **unescaped** JSON:
*
* document::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* 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
@ -834,8 +643,9 @@ public:
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* 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
@ -897,9 +707,10 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document::array a = document::parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
* a.["0/foo/a/1"] == 20
* a.["0"]["foo"]["a"].at(1) == 20
* document::parser parser;
* document::array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
* a["0/foo/a/1"] == 20
* a["0"]["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
@ -912,9 +723,10 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document::array a = document::parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
* a.["0/foo/a/1"] == 20
* a.["0"]["foo"]["a"].at(1) == 20
* document::parser parser;
* document::array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
* a["0/foo/a/1"] == 20
* a["0"]["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
@ -927,7 +739,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document::array a = document::parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
* document::parser parser;
* document::array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
* a.at("0/foo/a/1") == 20
* a.at("0")["foo"]["a"].at(1) == 20
*
@ -1014,7 +827,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document::object obj = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* document::parser parser;
* document::object obj = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* obj["foo/a/1"] == 20
* obj["foo"]["a"].at(1) == 20
*
@ -1029,7 +843,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document::object obj = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* document::parser parser;
* document::object obj = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* obj["foo/a/1"] == 20
* obj["foo"]["a"].at(1) == 20
*
@ -1044,7 +859,8 @@ public:
/**
* Get the value associated with the given JSON pointer.
*
* document::object obj = document::parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* document::parser parser;
* document::object obj = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
* obj.at("foo/a/1") == 20
* obj.at("foo")["a"].at(1) == 20
*
@ -1061,8 +877,9 @@ public:
*
* The key will be matched against **unescaped** JSON:
*
* document::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* 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
@ -1074,8 +891,9 @@ public:
*
* Note: The key will be matched against **unescaped** JSON:
*
* document::parse(R"({ "a\n": 1 })")["a\n"].as_uint64_t().value == 1
* document::parse(R"({ "a\n": 1 })")["a\\n"].as_uint64_t().error == NO_SUCH_FIELD
* 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
@ -1898,7 +1716,8 @@ private:
/**
* Minifies a JSON element or document, printing the smallest possible valid JSON.
*
* document doc = document::parse(" [ 1 , 2 , 3 ] "_padded);
* document::parser parser;
* document &doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
* cout << minify(doc) << endl; // prints [1,2,3]
*
*/
@ -1988,18 +1807,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_move_result &value) noexcept(false) { return out << minify(value); }
/**
* Print JSON to an output stream.
*

View File

@ -43,7 +43,8 @@ enum error_code {
/**
* Get the error message for the given error code.
*
* auto [doc, error] = document::parse("foo");
* document::parser parser;
* auto [doc, error] = parser.parse("foo");
* if (error) { printf("Error: %s\n", error_message(error)); }
*
* @return The error message.

View File

@ -238,27 +238,6 @@ inline document::element_result document::operator[](const char *json_pointer) c
}
inline document::doc_move_result document::load(const std::string &path) noexcept {
document::parser parser;
auto [doc, error] = parser.load(path);
return doc_move_result((document &&)doc, error);
}
inline document::doc_move_result document::parse(const uint8_t *buf, size_t len, bool realloc_if_needed) noexcept {
document::parser parser;
auto [doc, error] = parser.parse(buf, len, realloc_if_needed);
return doc_move_result((document &&)doc, error);
}
really_inline document::doc_move_result document::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_move_result document::parse(const std::string &s) noexcept {
return parse(s.data(), s.length(), s.capacity() - s.length() < SIMDJSON_PADDING);
}
really_inline document::doc_move_result document::parse(const padded_string &s) noexcept {
return parse(s.data(), s.length(), false);
}
WARN_UNUSED
inline error_code document::set_capacity(size_t capacity) noexcept {
if (capacity == 0) {
@ -412,46 +391,6 @@ inline document::element_result document::doc_result::at_key(const char *key) co
return first.at_key(key);
}
//
// doc_move_result inline implementation
//
inline document::doc_move_result::doc_move_result(document &&doc, error_code error) noexcept : simdjson_move_result<document>(std::move(doc), error) { }
inline document::doc_move_result::doc_move_result(document &&doc) noexcept : simdjson_move_result<document>(std::move(doc)) { }
inline document::doc_move_result::doc_move_result(error_code error) noexcept : simdjson_move_result<document>(error) { }
inline document::array_result document::doc_move_result::as_array() const noexcept {
if (error()) { return error(); }
return first.root().as_array();
}
inline document::object_result document::doc_move_result::as_object() const noexcept {
if (error()) { return error(); }
return first.root().as_object();
}
inline document::element_result document::doc_move_result::operator[](std::string_view key) const noexcept {
if (error()) { return error(); }
return first[key];
}
inline document::element_result document::doc_move_result::operator[](const char *json_pointer) const noexcept {
return (*this)[std::string_view(json_pointer)];
}
inline document::element_result document::doc_move_result::at(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at(key);
}
inline document::element_result document::doc_move_result::at(size_t index) const noexcept {
if (error()) { return error(); }
return first.at(index);
}
inline document::element_result document::doc_move_result::at_key(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at_key(key);
}
inline document::element_result document::doc_move_result::at_key(const char *key) const noexcept {
if (error()) { return error(); }
return first.at_key(key);
}
//
// document::parser inline implementation
//
@ -1226,11 +1165,6 @@ inline std::ostream& minify<document::key_value_pair>::print(std::ostream& out)
#if SIMDJSON_EXCEPTIONS
template<>
inline std::ostream& minify<document::doc_move_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::doc_result>::print(std::ostream& out) {
if (value.error()) { throw simdjson_error(value.error()); }

View File

@ -385,7 +385,8 @@ namespace document_tests {
for(size_t i = 0; i < 200; i++) {
input += "]";
}
auto [doc, error] = simdjson::document::parse(input);
simdjson::document::parser parser;
auto [doc, error] = parser.parse(input);
if (error) { std::cerr << "Error: " << simdjson::error_message(error) << std::endl; return false; }
return true;
}
@ -550,13 +551,6 @@ namespace parse_api_tests {
const padded_string BASIC_NDJSON = string("[1,2,3]\n[4,5,6]");
// const padded_string EMPTY_NDJSON = string("");
bool document_parse() {
std::cout << "Running " << __func__ << std::endl;
auto [doc, error] = document::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; }
return true;
}
bool parser_parse() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
@ -589,13 +583,6 @@ namespace parse_api_tests {
// return true;
// }
bool document_load() {
std::cout << "Running " << __func__ << std::endl;
auto [doc, error] = document::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; }
return true;
}
bool parser_load() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
@ -619,12 +606,6 @@ namespace parse_api_tests {
#if SIMDJSON_EXCEPTIONS
bool document_parse_exception() {
std::cout << "Running " << __func__ << std::endl;
document doc = document::parse(BASIC_JSON);
if (!doc.root().is_array()) { cerr << "Document did not parse as an array" << endl; return false; }
return true;
}
bool parser_parse_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
@ -644,12 +625,6 @@ namespace parse_api_tests {
return true;
}
bool document_load_exception() {
std::cout << "Running " << __func__ << std::endl;
document doc = document::load(JSON_TEST_PATH);
if (!doc.root().is_object()) { cerr << "Document did not parse as an object" << endl; return false; }
return true;
}
bool parser_load_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
@ -671,18 +646,14 @@ namespace parse_api_tests {
#endif
bool run() {
return document_parse() &&
parser_parse() &&
return parser_parse() &&
parser_parse_many() &&
// parser_parse_many_empty() &&
document_load() &&
parser_load() &&
parser_load_many() &&
#if SIMDJSON_EXCEPTIONS
document_parse_exception() &&
parser_parse_exception() &&
parser_parse_many_exception() &&
document_load_exception() &&
parser_load_exception() &&
parser_load_many_exception() &&
#endif
@ -1055,7 +1026,8 @@ namespace dom_api_tests {
uint64_t expected_value[] = { 1, 2, 3 };
int i = 0;
document doc = document::parse(json);
document::parser parser;
document &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++;
@ -1070,7 +1042,8 @@ namespace dom_api_tests {
uint64_t expected_value[] = { 1, 10, 100 };
int i=0;
document doc = document::parse(json);
document::parser parser;
document &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++;
@ -1143,7 +1116,8 @@ namespace dom_api_tests {
bool document_object_index_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "a": 1, "b": 2, "c": 3})");
document doc = document::parse(json);
document::parser parser;
document &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;
}
@ -1160,7 +1134,8 @@ namespace dom_api_tests {
bool twitter_count_exception() {
std::cout << "Running " << __func__ << std::endl;
// Prints the number of results in twitter.json
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &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;
@ -1170,7 +1145,8 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
// Print users with a default profile.
set<string_view> default_users;
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
for (document::object tweet : doc["statuses"].as_array()) {
document::object user = tweet["user"];
if (user["default_profile"]) {
@ -1185,7 +1161,8 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
// Print image names and sizes
set<pair<uint64_t, uint64_t>> image_sizes;
document doc = document::load(JSON_TEST_PATH);
document::parser parser;
document &doc = parser.load(JSON_TEST_PATH);
for (document::object tweet : doc["statuses"].as_array()) {
auto [media, not_found] = tweet["entities"]["media"];
if (!not_found) {
@ -1248,23 +1225,6 @@ namespace format_tests {
return true;
}
bool print_document_parse() {
std::cout << "Running " << __func__ << std::endl;
auto [doc, error] = document::parse(DOCUMENT);
if (error) { cerr << error << endl; return false; }
ostringstream s;
s << doc;
return assert_minified(s);
}
bool print_minify_document_parse() {
std::cout << "Running " << __func__ << std::endl;
auto [doc, error] = document::parse(DOCUMENT);
if (error) { cerr << error << endl; return false; }
ostringstream s;
s << minify(doc);
return assert_minified(s);
}
bool print_parser_parse() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
@ -1337,19 +1297,6 @@ namespace format_tests {
#if SIMDJSON_EXCEPTIONS
bool print_document_parse_exception() {
std::cout << "Running " << __func__ << std::endl;
ostringstream s;
s << document::parse(DOCUMENT);
return assert_minified(s);
}
bool print_minify_document_parse_exception() {
std::cout << "Running " << __func__ << std::endl;
ostringstream s;
s << minify(document::parse(DOCUMENT));
return assert_minified(s);
}
bool print_parser_parse_exception() {
std::cout << "Running " << __func__ << std::endl;
document::parser parser;
@ -1369,14 +1316,16 @@ namespace format_tests {
bool print_element_result_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["foo"];
return assert_minified(s, "1");
}
bool print_minify_element_result_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["foo"]);
return assert_minified(s, "1");
@ -1384,7 +1333,8 @@ namespace format_tests {
bool print_element_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element value = doc["foo"];
ostringstream s;
s << value;
@ -1392,7 +1342,8 @@ namespace format_tests {
}
bool print_minify_element_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::element value = doc["foo"];
ostringstream s;
s << minify(value);
@ -1401,14 +1352,16 @@ namespace format_tests {
bool print_array_result_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["bar"].as_array();
return assert_minified(s, "[1,2,3]");
}
bool print_minify_array_result_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["bar"].as_array());
return assert_minified(s, "[1,2,3]");
@ -1416,14 +1369,16 @@ namespace format_tests {
bool print_object_result_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["baz"].as_object();
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
}
bool print_minify_object_result_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["baz"].as_object());
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
@ -1431,7 +1386,8 @@ namespace format_tests {
bool print_array_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::array value = doc["bar"];
ostringstream s;
s << value;
@ -1439,7 +1395,8 @@ namespace format_tests {
}
bool print_minify_array_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::array value = doc["bar"];
ostringstream s;
s << minify(value);
@ -1448,7 +1405,8 @@ namespace format_tests {
bool print_object_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::object value = doc["baz"];
ostringstream s;
s << value;
@ -1456,7 +1414,8 @@ namespace format_tests {
}
bool print_minify_object_exception() {
std::cout << "Running " << __func__ << std::endl;
const document &doc = document::parse(DOCUMENT);
document::parser parser;
document &doc = parser.parse(DOCUMENT);
document::object value = doc["baz"];
ostringstream s;
s << minify(value);
@ -1465,13 +1424,11 @@ namespace format_tests {
#endif // SIMDJSON_EXCEPTIONS
bool run() {
return print_document_parse() && print_minify_document_parse() &&
print_parser_parse() && print_minify_parser_parse() &&
return print_parser_parse() && print_minify_parser_parse() &&
print_element() && print_minify_element() &&
print_array() && print_minify_array() &&
print_object() && print_minify_object() &&
#if SIMDJSON_EXCEPTIONS
print_document_parse_exception() && print_minify_document_parse_exception() &&
print_parser_parse_exception() && print_minify_parser_parse_exception() &&
print_element_result_exception() && print_minify_element_result_exception() &&
print_array_result_exception() && print_minify_array_result_exception() &&

View File

@ -41,12 +41,6 @@ namespace parser_load {
TEST_FAIL("No documents returned");
}
bool document_load_nonexistent() {
TEST_START();
auto [doc, error] = document::load(NONEXISTENT_FILE);
ASSERT_ERROR(error, IO_ERROR);
TEST_SUCCEED();
}
bool parser_load_nonexistent() {
TEST_START();
document::parser parser;
@ -70,12 +64,6 @@ namespace parser_load {
TEST_SUCCEED();
}
bool document_load_chain() {
TEST_START();
auto [val, error] = document::load(NONEXISTENT_FILE)["foo"].as_uint64_t();
ASSERT_ERROR(error, IO_ERROR);
TEST_SUCCEED();
}
bool parser_load_chain() {
TEST_START();
document::parser parser;
@ -95,8 +83,8 @@ namespace parser_load {
}
bool run() {
return parser_load_capacity() && parser_load_many_capacity()
&& parser_load_nonexistent() && parser_load_many_nonexistent() && document_load_nonexistent() && padded_string_load_nonexistent()
&& document_load_chain() && parser_load_chain() && parser_load_many_chain();
&& parser_load_nonexistent() && parser_load_many_nonexistent() && padded_string_load_nonexistent()
&& parser_load_chain() && parser_load_many_chain();
}
}

View File

@ -34,8 +34,8 @@ const padded_string TEST_JSON = R"(
bool json_pointer_success_test(const char *json_pointer, std::string_view expected_value) {
std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl;
auto doc = document::parse(TEST_JSON);
auto [value, error] = doc[json_pointer].as_string();
document::parser parser;
auto [value, error] = parser.parse(TEST_JSON)[json_pointer].as_string();
if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; }
ASSERT(value == expected_value);
return true;
@ -43,8 +43,8 @@ bool json_pointer_success_test(const char *json_pointer, std::string_view expect
bool json_pointer_success_test(const char *json_pointer) {
std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl;
auto doc = document::parse(TEST_JSON);
auto [value, error] = doc[json_pointer];
document::parser parser;
auto [value, error] = parser.parse(TEST_JSON)[json_pointer];
if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; }
return true;
}
@ -52,8 +52,8 @@ bool json_pointer_success_test(const char *json_pointer) {
bool json_pointer_failure_test(const char *json_pointer, error_code expected_failure_test) {
std::cout << "Running invalid JSON pointer test '" << json_pointer << "' ..." << std::endl;
auto doc = document::parse(TEST_JSON);
auto [value, error] = doc[json_pointer];
document::parser parser;
auto [value, error] = parser.parse(TEST_JSON)[json_pointer];
ASSERT(error == expected_failure_test);
return true;
}

View File

@ -3,14 +3,6 @@
using namespace std;
using namespace simdjson;
void document_parse_error_code() {
cout << __func__ << endl;
auto [doc, error] = document::parse("[ 1, 2, 3 ]"_padded);
if (error) { cerr << "Error: " << error << endl; exit(1); }
cout << doc << endl;
}
void parser_parse_error_code() {
cout << __func__ << endl;
@ -71,30 +63,20 @@ void parser_parse_fixed_capacity() {
#if SIMDJSON_EXCEPTIONS
void document_parse_exception() {
cout << __func__ << endl;
cout << document::parse("[ 1, 2, 3 ]"_padded) << endl;
}
void document_parse_padded_string() {
void parser_parse_padded_string() {
cout << __func__ << endl;
auto json = "[ 1, 2, 3 ]"_padded;
cout << document::parse(json) << endl;
document::parser parser;
cout << parser.parse(json) << endl;
}
void document_parse_get_corpus() {
void parser_parse_get_corpus() {
cout << __func__ << endl;
auto json = get_corpus("jsonexamples/small/demo.json");
cout << document::parse(json) << endl;
}
void document_load() {
cout << __func__ << endl;
cout << document::load("jsonexamples/small/demo.json") << endl;
document::parser parser;
cout << parser.parse(json) << endl;
}
void parser_parse_exception() {
@ -126,18 +108,15 @@ void parser_parse_many_exception() {
int main() {
cout << "Running examples." << endl;
document_parse_error_code();
parser_parse_error_code();
parser_parse_many_error_code();
parser_parse_max_capacity();
parser_parse_fixed_capacity();
#if SIMDJSON_EXCEPTIONS
document_parse_exception();
parser_parse_exception();
parser_parse_many_exception();
document_parse_padded_string();
document_parse_get_corpus();
document_load();
parser_parse_padded_string();
parser_parse_get_corpus();
#endif // SIMDJSON_EXCEPTIONS
cout << "Ran to completion!" << endl;
return 0;

View File

@ -52,7 +52,8 @@ int main(int argc, char *argv[]) {
}
const char *filename = argv[1];
auto [doc, error] = simdjson::document::load(filename);
simdjson::document::parser parser;
auto [doc, error] = parser.load(filename);
if (error) { std::cerr << "Error parsing " << filename << ": " << error << std::endl; }
std::cout << "[" << std::endl;