diff --git a/benchmark/bench_dom_api.cpp b/benchmark/bench_dom_api.cpp index 8f84e415..718d55fd 100644 --- a/benchmark/bench_dom_api.cpp +++ b/benchmark/bench_dom_api.cpp @@ -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 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> 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 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> image_sizes; auto [statuses, error] = doc["statuses"].as_array(); diff --git a/benchmark/bench_parse_call.cpp b/benchmark/bench_parse_call.cpp index 6a6cff90..5695cce7 100644 --- a/benchmark/bench_parse_call.cpp +++ b/benchmark/bench_parse_call.cpp @@ -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; } diff --git a/benchmark/distinctuseridcompetition.cpp b/benchmark/distinctuseridcompetition.cpp index f3adb356..194f2d6c 100644 --- a/benchmark/distinctuseridcompetition.cpp +++ b/benchmark/distinctuseridcompetition.cpp @@ -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 &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'; diff --git a/include/simdjson/document.h b/include/simdjson/document.h index 26ff923d..23575ce5 100644 --- a/include/simdjson/document.h +++ b/include/simdjson/document.h @@ -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 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 { -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 { @@ -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. * diff --git a/include/simdjson/error.h b/include/simdjson/error.h index 56a3cb80..3f9f9ac7 100644 --- a/include/simdjson/error.h +++ b/include/simdjson/error.h @@ -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. diff --git a/include/simdjson/inline/document.h b/include/simdjson/inline/document.h index ff8fc309..bd1b0fc4 100644 --- a/include/simdjson/inline/document.h +++ b/include/simdjson/inline/document.h @@ -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(std::move(doc), error) { } -inline document::doc_move_result::doc_move_result(document &&doc) noexcept : simdjson_move_result(std::move(doc)) { } -inline document::doc_move_result::doc_move_result(error_code error) noexcept : simdjson_move_result(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::print(std::ostream& out) #if SIMDJSON_EXCEPTIONS -template<> -inline std::ostream& minify::print(std::ostream& out) { - if (value.error()) { throw simdjson_error(value.error()); } - return out << minify(value.first); -} template<> inline std::ostream& minify::print(std::ostream& out) { if (value.error()) { throw simdjson_error(value.error()); } diff --git a/tests/basictests.cpp b/tests/basictests.cpp index 7b69f458..cd1b7ab5 100644 --- a/tests/basictests.cpp +++ b/tests/basictests.cpp @@ -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 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> 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() && diff --git a/tests/errortests.cpp b/tests/errortests.cpp index 88eb49dd..94ca673f 100644 --- a/tests/errortests.cpp +++ b/tests/errortests.cpp @@ -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(); } } diff --git a/tests/pointercheck.cpp b/tests/pointercheck.cpp index 9b91ae88..c274084b 100644 --- a/tests/pointercheck.cpp +++ b/tests/pointercheck.cpp @@ -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; } diff --git a/tests/readme_examples.cpp b/tests/readme_examples.cpp index a7cf8ab3..cc2aa0f2 100644 --- a/tests/readme_examples.cpp +++ b/tests/readme_examples.cpp @@ -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; diff --git a/tools/jsonpointer.cpp b/tools/jsonpointer.cpp index 93cfa44a..021d9f5c 100644 --- a/tools/jsonpointer.cpp +++ b/tools/jsonpointer.cpp @@ -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;