diff --git a/benchmark/bench_dom_api.cpp b/benchmark/bench_dom_api.cpp index 1440942c7..ed6467bd9 100644 --- a/benchmark/bench_dom_api.cpp +++ b/benchmark/bench_dom_api.cpp @@ -407,7 +407,7 @@ static void iterator_twitter_default_profile(State& state) { set default_users; ParsedJson::Iterator iter(pj); - // for (dom::object tweet : doc["statuses"].get()) { + // for (dom::object tweet : doc["statuses"]) { if (!(iter.move_to_key("statuses") && iter.is_array())) { return; } if (iter.down()) { // first status do { @@ -480,23 +480,24 @@ static void iterator_twitter_image_sizes(State& state) { set> image_sizes; ParsedJson::Iterator iter(pj); - // for (dom::object tweet : doc["statuses"].get()) { + // for (dom::object tweet : doc["statuses"]) { if (!(iter.move_to_key("statuses") && iter.is_array())) { return; } if (iter.down()) { // first status do { - // auto [media, not_found] = tweet["entities"]["media"]; + // dom::object media; + // not_found = tweet["entities"]["media"].get(media); // if (!not_found) { if (iter.move_to_key("entities")) { if (!iter.is_object()) { return; } if (iter.move_to_key("media")) { if (!iter.is_array()) { return; } - // for (dom::object image : media.get()) { + // for (dom::object image : media) { if (iter.down()) { // first media do { - // for (auto [key, size] : image["sizes"].get()) { + // for (auto [key, size] : dom::object(image["sizes"])) { if (!(iter.move_to_key("sizes") && iter.is_object())) { return; } if (iter.down()) { // first size do { diff --git a/benchmark/distinctuseridcompetition.cpp b/benchmark/distinctuseridcompetition.cpp index 100c48f66..f2c4a6434 100644 --- a/benchmark/distinctuseridcompetition.cpp +++ b/benchmark/distinctuseridcompetition.cpp @@ -40,17 +40,18 @@ void print_vec(const std::vector &v) { // simdjson_recurse below come be implemented like so but it is slow: /*void simdjson_recurse(std::vector & v, simdjson::dom::element element) { - if (element.is()) { - auto [array, array_error] = element.get(); + error_code error; + if (element.is_array()) { + dom::array array; + error = element.get(array); for (auto child : array) { if (child.is() || child.is()) { simdjson_recurse(v, child); } } - } else if (element.is()) { - auto [object, error] = element.get(); + } else if (element.is_object()) { int64_t id; - error = object["user"]["id"].get(id); + error = element["user"]["id"].get(id); if(!error) { v.push_back(id); } @@ -330,7 +331,8 @@ int main(int argc, char *argv[]) { std::cerr << "warning: ignoring everything after " << argv[optind + 1] << std::endl; } - auto [p, error] = simdjson::padded_string::load(filename); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(filename).get(p); if (error) { std::cerr << "Could not load the file " << filename << std::endl; return EXIT_FAILURE; diff --git a/benchmark/minifiercompetition.cpp b/benchmark/minifiercompetition.cpp index 2a8c1611a..08c80f7aa 100644 --- a/benchmark/minifiercompetition.cpp +++ b/benchmark/minifiercompetition.cpp @@ -75,7 +75,8 @@ int main(int argc, char *argv[]) { exit(1); } const char *filename = argv[optind]; - auto [p, error] = simdjson::padded_string::load(filename); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(filename).get(p); if (error) { std::cerr << "Could not load the file " << filename << std::endl; return EXIT_FAILURE; diff --git a/benchmark/parseandstatcompetition.cpp b/benchmark/parseandstatcompetition.cpp index eb017ebd9..72972ca92 100644 --- a/benchmark/parseandstatcompetition.cpp +++ b/benchmark/parseandstatcompetition.cpp @@ -105,7 +105,8 @@ void simdjson_recurse(stat_t &s, simdjson::dom::element element) { never_inline stat_t simdjson_compute_stats(const simdjson::padded_string &p) { stat_t s{}; simdjson::dom::parser parser; - auto [doc, error] = parser.parse(p); + simdjson::dom::element doc; + auto error = parser.parse(p).get(doc); if (error) { s.valid = false; return s; @@ -154,11 +155,11 @@ static void GenStatPlus(Stat &stat, const dom::element &v) { break; case dom::element_type::STRING: { stat.stringCount++; - std::string_view sv = v.get(); + auto sv = std::string_view(v); stat.stringLength += sv.size(); } break; case dom::element_type::BOOL: - if (v.get()) { + if (bool(v)) { stat.trueCount++; } else { stat.falseCount++; @@ -409,7 +410,8 @@ int main(int argc, char *argv[]) { std::cerr << "warning: ignoring everything after " << argv[optind + 1] << std::endl; } - auto [p, error] = simdjson::padded_string::load(filename); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(filename).get(p); if (error) { std::cerr << "Could not load the file " << filename << std::endl; return EXIT_FAILURE; @@ -464,9 +466,10 @@ int main(int argc, char *argv[]) { printf("API traversal tests\n"); printf("Based on https://github.com/miloyip/nativejson-benchmark\n"); simdjson::dom::parser parser; - auto [doc, err] = parser.parse(p); - if (err) { - std::cerr << err << std::endl; + simdjson::dom::element doc; + auto error = parser.parse(p).get(doc); + if (error) { + std::cerr << error << std::endl; } size_t refval = simdjson_compute_stats_refplus(doc).objectCount; diff --git a/benchmark/parsingcompetition.cpp b/benchmark/parsingcompetition.cpp index 80a2a76d9..509e44087 100644 --- a/benchmark/parsingcompetition.cpp +++ b/benchmark/parsingcompetition.cpp @@ -82,9 +82,10 @@ inline void reset_stream(std::stringstream & is) { bool bench(const char *filename, bool verbose, bool just_data, double repeat_multiplier) { - auto [p, err] = simdjson::padded_string::load(filename); - if (err) { - std::cerr << "Could not load the file " << filename << std::endl; + simdjson::padded_string p; + auto error = simdjson::padded_string::load(filename).get(p); + if (error) { + std::cerr << "Could not load the file " << filename << ": " << error << std::endl; return false; } diff --git a/benchmark/statisticalmodel.cpp b/benchmark/statisticalmodel.cpp index 3838f5ef9..89efe82d6 100644 --- a/benchmark/statisticalmodel.cpp +++ b/benchmark/statisticalmodel.cpp @@ -96,7 +96,8 @@ void simdjson_recurse(stat_t &s, simdjson::dom::element element) { stat_t simdjson_compute_stats(const simdjson::padded_string &p) { stat_t answer{}; simdjson::dom::parser parser; - auto [doc, error] = parser.parse(p); + simdjson::dom::element doc; + auto error = parser.parse(p).get(doc); if (error) { answer.valid = false; return answer; @@ -136,7 +137,8 @@ int main(int argc, char *argv[]) { std::cerr << "warning: ignoring everything after " << argv[optind + 1] << std::endl; } - auto [p, error] = simdjson::padded_string::load(filename); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(filename).get(p); if (error) { std::cerr << "Could not load the file " << filename << std::endl; return EXIT_FAILURE; diff --git a/doc/basics.md b/doc/basics.md index db9aeb29c..2b578f241 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -164,7 +164,7 @@ And another one: auto abstract_json = R"( { "str" : { "123" : {"abc" : 3.14 } } } )"_padded; dom::parser parser; - double v = parser.parse(abstract_json)["str"]["123"]["abc"].get(); + double v = parser.parse(abstract_json)["str"]["123"]["abc"]; cout << "number: " << v << endl; ``` @@ -208,14 +208,13 @@ Your input string does not need any padding. Any string will do. The `validate_u C++17 Support ------------- -While the simdjson library can be used in any project using C++ 11 and above, it has special support -for C++ 17. The APIs for field iteration and error handling in particular are designed to work -nicely with C++17's destructuring syntax. For example: +While the simdjson library can be used in any project using C++ 11 and above, field iteration has special support C++ 17's destructuring syntax. For example: ```c++ -dom::parser parser; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; -auto [object, error] = parser.parse(json).get(); +dom::parser parser; +dom::object object; +auto error = parser.parse(json).get(object); if (error) { cerr << error << endl; return; } for (auto [key, value] : object) { cout << key << " = " << value << endl; @@ -226,11 +225,10 @@ For comparison, here is the C++ 11 version of the same code: ```c++ // C++ 11 version for comparison -dom::parser parser; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; -simdjson::error_code error; +dom::parser parser; dom::object object; -error = parser.parse(json).get(object); +auto error = parser.parse(json).get(object); if (!error) { cerr << error << endl; return; } for (dom::key_value_pair field : object) { cout << field.key << " = " << field.value << endl; @@ -258,29 +256,18 @@ Error Handling -------------- All simdjson APIs that can fail return `simdjson_result`, which is a <value, error_code> -pair. The error codes and values can be accessed directly, reading the error like so: +pair. You can retrieve the value with .get(), like so: ```c++ -auto [doc, error] = parser.parse(json); // doc is a dom::element +dom::element doc; +auto error = parser.parse(json).get(doc); if (error) { cerr << error << endl; exit(1); } -// Use document here now that we've checked for the error ``` When you use the code this way, it is your responsibility to check for error before using the result: if there is an error, the result value will not be valid and using it will caused undefined behavior. -> Note: because of the way `auto [x, y]` works in C++, you have to define new variables each time you -> use it. If your project treats aliased, this means you can't use the same names in `auto [x, error]` -> without triggering warnings or error (and particularly can't use the word "error" every time). To -> circumvent this, you can use this instead: -> -> ```c++ -> dom::element doc; -> auto error = parser.parse(json).get(doc); // <-- Assigns to doc and error just like "auto [doc, error]" -> ``` - - We can write a "quick start" example where we attempt to parse a file and access some data, without triggering exceptions: ```C++ @@ -288,11 +275,12 @@ We can write a "quick start" example where we attempt to parse a file and access int main(void) { simdjson::dom::parser parser; + simdjson::dom::element tweets; auto error = parser.load("twitter.json").get(tweets); if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; } - simdjson::dom::element res; + simdjson::dom::element res; if ((error = tweets["search_metadata"]["count"].get(res))) { std::cerr << "could not access keys" << std::endl; return EXIT_FAILURE; @@ -395,8 +383,7 @@ And another one: cout << "number: " << v << endl; ``` -Notice how we can string several operation (`parser.parse(abstract_json)["str"]["123"]["abc"].get()`) and only check for the error once, a strategy we call *error chaining*. - +Notice how we can string several operations (`parser.parse(abstract_json)["str"]["123"]["abc"].get(v)`) and only check for the error once, a strategy we call *error chaining*. The next two functions will take as input a JSON document containing an array with a single element, either a string or a number. They return true upon success. diff --git a/doc/performance.md b/doc/performance.md index bf022a4cd..1b65e995b 100644 --- a/doc/performance.md +++ b/doc/performance.md @@ -68,7 +68,8 @@ without bound: ```c++ dom::parser parser(1000*1000); // Never grow past documents > 1MB for (web_request request : listen()) { - auto [doc, error] = parser.parse(request.body); + dom::element doc; + auto error = parser.parse(request.body).get(doc); // If the document was above our limit, emit 413 = payload too large if (error == CAPACITY) { request.respond(413); continue; } // ... @@ -82,11 +83,12 @@ without bound: ```c++ dom::parser parser(0); // This parser will refuse to automatically grow capacity - simdjson::error_code allocate_error = parser.allocate(1000*1000); // This allocates enough capacity to handle documents <= 1MB - if (allocate_error) { cerr << allocate_error << endl; exit(1); } + auto error = parser.allocate(1000*1000); // This allocates enough capacity to handle documents <= 1MB + if (error) { cerr << error << endl; exit(1); } for (web_request request : listen()) { - auto [doc, error] = parser.parse(request.body); + dom::element doc; + error = parser.parse(request.body).get(doc); // If the document was above our limit, emit 413 = payload too large if (error == CAPACITY) { request.respond(413); continue; } // ... diff --git a/include/simdjson/dom/array.h b/include/simdjson/dom/array.h index 55d3ec8a8..a54383b41 100644 --- a/include/simdjson/dom/array.h +++ b/include/simdjson/dom/array.h @@ -68,7 +68,7 @@ public: * Get the value associated with the given JSON pointer. * * dom::parser parser; - * array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"); + * array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded); * a.at("0/foo/a/1") == 20 * a.at("0")["foo"]["a"].at(1) == 20 * diff --git a/include/simdjson/dom/element.h b/include/simdjson/dom/element.h index 6d9af51dd..c979ba661 100644 --- a/include/simdjson/dom/element.h +++ b/include/simdjson/dom/element.h @@ -336,8 +336,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object @@ -351,8 +351,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object @@ -364,7 +364,7 @@ public: * Get the value associated with the given JSON pointer. * * dom::parser parser; - * element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"); + * element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded); * doc.at("/foo/a/1") == 20 * doc.at("/")["foo"]["a"].at(1) == 20 * doc.at("")["foo"]["a"].at(1) == 20 @@ -391,8 +391,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object diff --git a/include/simdjson/dom/object.h b/include/simdjson/dom/object.h index 9316914d9..3be058eb4 100644 --- a/include/simdjson/dom/object.h +++ b/include/simdjson/dom/object.h @@ -101,8 +101,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * This function has linear-time complexity: the keys are checked one by one. * @@ -118,8 +118,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * This function has linear-time complexity: the keys are checked one by one. * @@ -133,7 +133,7 @@ public: * Get the value associated with the given JSON pointer. * * dom::parser parser; - * object obj = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"); + * object obj = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded); * obj.at("foo/a/1") == 20 * obj.at("foo")["a"].at(1) == 20 * @@ -151,8 +151,8 @@ public: * The key will be matched against **unescaped** JSON: * * dom::parser parser; - * parser.parse(R"({ "a\n": 1 })")["a\n"].get().value == 1 - * parser.parse(R"({ "a\n": 1 })")["a\\n"].get().error == NO_SUCH_FIELD + * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 + * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * This function has linear-time complexity: the keys are checked one by one. * diff --git a/include/simdjson/dom/parser.h b/include/simdjson/dom/parser.h index ba3d9b668..25eccf430 100644 --- a/include/simdjson/dom/parser.h +++ b/include/simdjson/dom/parser.h @@ -173,9 +173,13 @@ public: * the same interface, requiring you to check the error before using the document: * * dom::parser parser; - * for (auto [doc, error] : parser.load_many(path)) { - * if (error) { cerr << error << endl; exit(1); } - * cout << std::string(doc["title"]) << endl; + * dom::document_stream docs; + * auto error = parser.load_many(path).get(docs); + * if (error) { cerr << error << endl; exit(1); } + * for (auto doc : docs) { + * std::string_view title; + * if ((error = doc["title"].get(title)) { cerr << error << endl; exit(1); } + * cout << title << endl; * } * * ### Threads @@ -233,9 +237,13 @@ public: * the same interface, requiring you to check the error before using the document: * * dom::parser parser; - * for (auto [doc, error] : parser.parse_many(buf, len)) { - * if (error) { cerr << error << endl; exit(1); } - * cout << std::string(doc["title"]) << endl; + * dom::document_stream docs; + * auto error = parser.load_many(path).get(docs); + * if (error) { cerr << error << endl; exit(1); } + * for (auto doc : docs) { + * std::string_view title; + * if ((error = doc["title"].get(title)) { cerr << error << endl; exit(1); } + * cout << title << endl; * } * * ### REQUIRED: Buffer Padding diff --git a/include/simdjson/error.h b/include/simdjson/error.h index f272abd83..308bc1f0b 100644 --- a/include/simdjson/error.h +++ b/include/simdjson/error.h @@ -42,7 +42,8 @@ enum error_code { * Get the error message for the given error code. * * dom::parser parser; - * auto [doc, error] = parser.parse("foo"); + * dom::element doc; + * auto error = parser.parse("foo").get(doc); * if (error) { printf("Error: %s\n", error_message(error)); } * * @return The error message. diff --git a/tests/allparserscheckfile.cpp b/tests/allparserscheckfile.cpp index 6784a0603..959268e63 100644 --- a/tests/allparserscheckfile.cpp +++ b/tests/allparserscheckfile.cpp @@ -63,9 +63,10 @@ int main(int argc, char *argv[]) { exit(1); } const char *filename = argv[optind]; - auto [p, loaderr] = simdjson::padded_string::load(filename); - if (loaderr) { - std::cerr << "Could not load the file " << filename << ": " << loaderr << std::endl; + simdjson::padded_string p; + auto error = simdjson::padded_string::load(filename).get(p); + if (error) { + std::cerr << "Could not load the file " << filename << ": " << error << std::endl; return EXIT_FAILURE; } if (verbose) { @@ -79,7 +80,7 @@ int main(int argc, char *argv[]) { std::cout << std::endl; } simdjson::dom::parser parser; - auto err = parser.parse(p).error(); + error = parser.parse(p).error(); rapidjson::Document d; @@ -95,19 +96,19 @@ int main(int argc, char *argv[]) { .is_valid(); if (just_favorites) { printf("our parser : %s \n", - (err == simdjson::error_code::SUCCESS) ? "correct" : "invalid"); + (error == simdjson::error_code::SUCCESS) ? "correct" : "invalid"); printf("rapid (check encoding) : %s \n", rapid_correct_checkencoding ? "correct" : "invalid"); printf("sajson : %s \n", sajson_correct ? "correct" : "invalid"); - if (err == simdjson::DEPTH_ERROR) { + if (error == simdjson::DEPTH_ERROR) { printf("simdjson encountered a DEPTH_ERROR, it was parametrized to " "reject documents with depth exceeding %zu.\n", parser.max_depth()); } - if (((err == simdjson::error_code::SUCCESS) != rapid_correct_checkencoding) || + if (((error == simdjson::error_code::SUCCESS) != rapid_correct_checkencoding) || (rapid_correct_checkencoding != sajson_correct) || - ((err == simdjson::SUCCESS) != sajson_correct)) { + ((error == simdjson::SUCCESS) != sajson_correct)) { printf("WARNING: THEY DISAGREE\n\n"); return EXIT_FAILURE; } diff --git a/tests/basictests.cpp b/tests/basictests.cpp index d89eb5a9c..a59a88d02 100644 --- a/tests/basictests.cpp +++ b/tests/basictests.cpp @@ -17,6 +17,8 @@ #include "cast_tester.h" #include "test_macros.h" +const size_t AMAZON_CELLPHONES_NDJSON_DOC_COUNT = 793; + namespace number_tests { // ulp distance @@ -39,8 +41,8 @@ namespace number_tests { for (int m = 10; m < 20; m++) { for (int i = -1024; i < 1024; i++) { auto str = std::to_string(i); - auto [actual, error] = parser.parse(str).get(); - if (error) { std::cerr << error << std::endl; return false; } + int64_t actual; + ASSERT_SUCCESS(parser.parse(str).get(actual)); if (actual != i) { std::cerr << "JSON '" << str << "' parsed to " << actual << " instead of " << i << std::endl; return false; @@ -60,7 +62,8 @@ namespace number_tests { size_t n = snprintf(buf, sizeof(buf), "%.*e", std::numeric_limits::max_digits10 - 1, expected); if (n >= sizeof(buf)) { abort(); } fflush(NULL); - auto [actual, error] = parser.parse(buf, n).get(); + double actual; + auto error = parser.parse(buf, n).get(actual); if (error) { std::cerr << error << std::endl; return false; } uint64_t ulp = f64_ulp_dist(actual,expected); if(ulp > maxulp) maxulp = ulp; @@ -154,7 +157,8 @@ namespace number_tests { if (n >= sizeof(buf)) { abort(); } fflush(NULL); - auto [actual, error] = parser.parse(buf, n).get(); + double actual; + auto error = parser.parse(buf, n).get(actual); 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); @@ -174,17 +178,14 @@ namespace number_tests { } namespace document_tests { - int issue938() { + bool issue938() { std::vector json_strings{"[true,false]", "[1,2,3,null]", R"({"yay":"json!"})"}; simdjson::dom::parser parser1; for (simdjson::padded_string str : json_strings) { - auto [element, error] = parser1.parse(str); - if(error) { - std::cerr << error << std::endl; - } else { - std::cout << element << std::endl; - } + simdjson::dom::element element; + ASSERT_SUCCESS( parser1.parse(str).get(element) ); + std::cout << element << std::endl; } std::vector file_paths{ ADVERSARIAL_JSON, FLATADVERSARIAL_JSON, DEMO_JSON, @@ -192,23 +193,17 @@ namespace document_tests { TRUENULL_JSON}; for (auto path : file_paths) { simdjson::dom::parser parser2; + simdjson::dom::element element; std::cout << "file: " << path << std::endl; - auto [element, error] = parser2.load(path); - if(error) { - std::cerr << error << std::endl; - } else { - std::cout << element.type() << std::endl; - } + ASSERT_SUCCESS( parser2.load(path).get(element) ); + std::cout << element.type() << std::endl; } simdjson::dom::parser parser3; for (auto path : file_paths) { + simdjson::dom::element element; std::cout << "file: " << path << std::endl; - auto [element, error] = parser3.load(path); - if(error) { - std::cerr << error << std::endl; - } else { - std::cout << element.type() << std::endl; - } + ASSERT_SUCCESS( parser3.load(path).get(element) ); + std::cout << element.type() << std::endl; } return true; } @@ -218,52 +213,34 @@ namespace document_tests { std::cout << __func__ << std::endl; simdjson::padded_string badjson = "[7,7,7,7,6,7,7,7,6,7,7,6,[7,7,7,7,6,7,7,7,6,7,7,6,7,7,7,7,7,7,6"_padded; simdjson::dom::parser parser; - auto error = parser.parse(badjson).error(); - if (!error) { - printf("This json should not be valid %s.\n", badjson.data()); - return false; - } + ASSERT_ERROR( parser.parse(badjson), simdjson::TAPE_ERROR ); return true; } bool count_array_example() { std::cout << __func__ << std::endl; simdjson::padded_string smalljson = "[1,2,3]"_padded; simdjson::dom::parser parser; - auto [doc, error] = parser.parse(smalljson).get(); - if (error) { - printf("This json should be valid %s.\n", smalljson.data()); - return false; - } - if(doc.size() != 3) { - printf("This json should have size three but found %zu : %s.\n", doc.size(), smalljson.data()); - return false; - } + simdjson::dom::array array; + ASSERT_SUCCESS( parser.parse(smalljson).get(array) ); + ASSERT_EQUAL( array.size(), 3 ); return true; } bool count_object_example() { std::cout << __func__ << std::endl; simdjson::padded_string smalljson = "{\"1\":1,\"2\":1,\"3\":1}"_padded; simdjson::dom::parser parser; - auto [doc, error] = parser.parse(smalljson).get(); - if (error) { - printf("This json should be valid %s.\n", smalljson.data()); - return false; - } - if(doc.size() != 3) { - printf("This json should have size three but found %zu : %s.\n", doc.size(), smalljson.data()); - return false; - } + simdjson::dom::object object; + ASSERT_SUCCESS( parser.parse(smalljson).get(object) ); + ASSERT_EQUAL( object.size(), 3 ); return true; } bool padded_with_open_bracket() { std::cout << __func__ << std::endl; simdjson::dom::parser parser; // This is an invalid document padded with open braces. - auto error1 = parser.parse("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error(); - if (!error1) { std::cerr << "We expected an error but got: " << error1 << std::endl; return false; } + ASSERT_ERROR( parser.parse("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false), simdjson::TAPE_ERROR); // This is a valid document padded with open braces. - auto error2 = parser.parse("[][[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error(); - if (error2) { std::cerr << "Error: " << error2 << std::endl; return false; } + ASSERT_SUCCESS( parser.parse("[][[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false) ); return true; } // returns true if successful @@ -410,7 +387,7 @@ namespace document_stream_tests { size_t count = 0; for(; i != stream.end(); ++i) { auto doc = *i; - ASSERT_SUCCESS(doc.error()); + ASSERT_SUCCESS(doc); if( i.current_index() != count) { std::cout << "index:" << i.current_index() << std::endl; std::cout << "expected index:" << count << std::endl; @@ -518,22 +495,10 @@ namespace document_stream_tests { size_t count = 0; simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.parse_many(str, batch_size).get(stream) ); - for (auto [doc, error] : stream) { - if (error) { - printf("Error at on document %zd at batch size %zu: %s\n", count, batch_size, simdjson::error_message(error)); - return false; - } - - auto [keyid, error2] = doc["id"].get(); - if (error2) { - printf("Error getting id as int64 on document %zd at batch size %zu: %s\n", count, batch_size, simdjson::error_message(error2)); - return false; - } - - if (keyid != int64_t(count)) { - printf("key does not match %" PRId64 ", expected %zd on document %zd at batch size %zu\n", keyid, count, count, batch_size); - return false; - } + for (auto doc : stream) { + int64_t keyid; + ASSERT_SUCCESS( doc["id"].get(keyid) ); + ASSERT_EQUAL( keyid, int64_t(count) ); count++; } @@ -570,29 +535,14 @@ namespace document_stream_tests { size_t count = 0; simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.parse_many(str, batch_size).get(stream) ); - for (auto [doc, error] : stream) { - if (error) { - printf("Error at on document %zd at batch size %zu: %s\n", count, batch_size, simdjson::error_message(error)); - return false; - } - - auto [keyid, error2] = doc["id"].get(); - if (error2) { - printf("Error getting id as int64 on document %zd at batch size %zu: %s\n", count, batch_size, simdjson::error_message(error2)); - return false; - } - - if (keyid != int64_t(count)) { - printf("key does not match %" PRId64 ", expected %zd on document %zd at batch size %zu\n", keyid, count, count, batch_size); - return false; - } + for (auto doc : stream) { + int64_t keyid; + ASSERT_SUCCESS( doc["id"].get(keyid) ); + ASSERT_EQUAL( keyid, int64_t(count) ); count++; } - if(count != n_records) { - printf("Found wrong number of documents %zd, expected %zd at batch size %zu\n", count, n_records, batch_size); - return false; - } + ASSERT_EQUAL( count, n_records ) } printf("ok\n"); return true; @@ -620,9 +570,9 @@ namespace parse_api_tests { bool parser_parse() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [doc, error] = parser.parse(BASIC_JSON); - if (error) { cerr << error << endl; return false; } - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + dom::element doc; + ASSERT_SUCCESS( parser.parse(BASIC_JSON).get(doc) ); + ASSERT_EQUAL( doc.is(), true ); return true; } bool parser_parse_many() { @@ -631,12 +581,12 @@ namespace parse_api_tests { int count = 0; simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.parse_many(BASIC_NDJSON).get(stream) ); - for (auto [doc, error] : stream) { - if (error) { cerr << "Error in parse_many: " << endl; return false; } - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + for (auto doc : stream) { + UNUSED dom::array array; + ASSERT_SUCCESS( doc.get(array) ); count++; } - if (count != 2) { cerr << "parse_many returned " << count << " documents, expected 2" << endl; return false; } + ASSERT_EQUAL(count, 2); return true; } @@ -646,12 +596,12 @@ namespace parse_api_tests { std::cout << "Running " << __func__ << std::endl; dom::parser parser; int count = 0; - for (auto [doc, error] : parser.parse_many(BASIC_NDJSON)) { - if (error) { cerr << "Error in parse_many: " << endl; return false; } - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + for (auto doc : parser.parse_many(BASIC_NDJSON)) { + UNUSED dom::array array; + ASSERT_SUCCESS( doc.get(array) ); count++; } - if (count != 2) { cerr << "parse_many returned " << count << " documents, expected 2" << endl; return false; } + ASSERT_EQUAL(count, 2); return true; } SIMDJSON_POP_DISABLE_WARNINGS @@ -662,10 +612,10 @@ namespace parse_api_tests { simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.parse_many(EMPTY_NDJSON).get(stream) ); for (auto doc : stream) { - if (doc.error()) { cerr << "Error in parse_many: " << doc.error() << endl; return false; } + ASSERT_SUCCESS( doc ); count++; } - if (count != 0) { cerr << "parse_many returned " << count << " documents, expected 0" << endl; return false; } + ASSERT_EQUAL(count, 0); return true; } @@ -681,23 +631,21 @@ namespace parse_api_tests { memcpy(&empty_batches_ndjson[BATCH_SIZE*11+6], "3", 1); simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.parse_many(empty_batches_ndjson, BATCH_SIZE*16).get(stream) ); - for (auto [doc, error] : stream) { - if (error) { cerr << "Error in parse_many: " << error << endl; return false; } + for (auto doc : stream) { count++; - auto [val, val_error] = doc.get(); - if (val_error) { cerr << "Document is not an unsigned int: " << val_error << endl; return false; } - if (val != count) { cerr << "Expected document #" << count << " to equal " << count << ", but got " << val << " instead!" << endl; return false; } + uint64_t val; + ASSERT_SUCCESS( doc.get(val) ); + ASSERT_EQUAL( val, count ); } - if (count != 3) { cerr << "parse_many returned " << count << " documents, expected 0" << endl; return false; } + ASSERT_EQUAL(count, 3); return true; } bool parser_load() { std::cout << "Running " << __func__ << " on " << TWITTER_JSON << std::endl; dom::parser parser; - auto [doc, error] = parser.load(TWITTER_JSON); - if (error) { cerr << error << endl; return false; } - if (!doc.is()) { cerr << "Document did not parse as an object" << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.load(TWITTER_JSON).get(object) ); return true; } bool parser_load_many() { @@ -706,22 +654,18 @@ namespace parse_api_tests { int count = 0; simdjson::dom::document_stream stream; ASSERT_SUCCESS( parser.load_many(AMAZON_CELLPHONES_NDJSON).get(stream) ); - for (auto [doc, error] : stream) { - if (error) { cerr << error << endl; return false; } - + for (auto doc : stream) { dom::array arr; - error = doc.get(arr); // let us get the array - if (error) { cerr << error << endl; return false; } + ASSERT_SUCCESS( doc.get(arr) ); // let us get the array + ASSERT_EQUAL( arr.size(), 9 ); - if(arr.size() != 9) { cerr << "bad array size"<< endl; return false; } - - size_t c = 0; - for(auto v : arr) { c++; (void)v; } - if(c != 9) { cerr << "mismatched array size"<< endl; return false; } + size_t arr_count = 0; + for (auto v : arr) { arr_count++; (void)v; } + ASSERT_EQUAL( arr_count, 9 ); count++; } - if (count != 793) { cerr << "Expected 793 documents, but load_many loaded " << count << " documents." << endl; return false; } + ASSERT_EQUAL(count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT); return true; } @@ -731,22 +675,18 @@ namespace parse_api_tests { std::cout << "Running " << __func__ << " on " << AMAZON_CELLPHONES_NDJSON << std::endl; dom::parser parser; int count = 0; - for (auto [doc, error] : parser.load_many(AMAZON_CELLPHONES_NDJSON)) { - if (error) { cerr << error << endl; return false; } - + for (auto doc : parser.load_many(AMAZON_CELLPHONES_NDJSON)) { dom::array arr; - error = doc.get(arr); // let us get the array - if (error) { cerr << error << endl; return false; } + ASSERT_SUCCESS( doc.get(arr) ); + ASSERT_EQUAL( arr.size(), 9 ); - if(arr.size() != 9) { cerr << "bad array size"<< endl; return false; } - - size_t c = 0; - for(auto v : arr) { c++; (void)v; } - if(c != 9) { cerr << "mismatched array size"<< endl; return false; } + size_t arr_count = 0; + for (auto v : arr) { arr_count++; (void)v; } + ASSERT_EQUAL( arr_count, 9 ); count++; } - if (count != 793) { cerr << "Expected 793 documents, but load_many loaded " << count << " documents." << endl; return false; } + ASSERT_EQUAL( count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT ); return true; } SIMDJSON_POP_DISABLE_WARNINGS @@ -756,45 +696,39 @@ namespace parse_api_tests { bool parser_parse_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(BASIC_JSON); - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + UNUSED dom::array array = parser.parse(BASIC_JSON); return true; } bool parser_parse_many_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; int count = 0; - for (const element doc : parser.parse_many(BASIC_NDJSON)) { - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + for (UNUSED dom::array doc : parser.parse_many(BASIC_NDJSON)) { count++; } - if (count != 2) { cerr << "parse_many returned " << count << " documents, expected 2" << endl; return false; } + ASSERT_EQUAL(count, 2); return true; } bool parser_load_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - const element doc = parser.load(TWITTER_JSON); - if (!doc.is()) { cerr << "Document did not parse as an object" << endl; return false; } - size_t c = 0; - dom::object obj = doc.get().value(); // let us get the object - for (auto x : obj) { - c++; - (void) x; + size_t count = 0; + dom::object object = parser.load(TWITTER_JSON); + for (UNUSED auto field : object) { + count++; } - if(c != obj.size()) { cerr << "Mismatched size" << endl; return false; } + ASSERT_EQUAL( count, object.size() ); return true; } bool parser_load_many_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; int count = 0; - for (const element doc : parser.load_many(AMAZON_CELLPHONES_NDJSON)) { - if (!doc.is()) { cerr << "Document did not parse as an array" << endl; return false; } + for (UNUSED dom::array doc : parser.load_many(AMAZON_CELLPHONES_NDJSON)) { count++; } - if (count != 793) { cerr << "Expected 1 document, but load_many loaded " << count << " documents." << endl; return false; } + ASSERT_EQUAL( count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT ); return true; } #endif @@ -933,16 +867,17 @@ namespace dom_api_tests { string json(R"({ "a": 1, "b": 2, "c": 3 })"); const char* expected_key[] = { "a", "b", "c" }; uint64_t expected_value[] = { 1, 2, 3 }; - int i = 0; dom::parser parser; - auto [object, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.parse(json).get(object) ); + int i = 0; for (auto [key, value] : object) { - if (key != expected_key[i] || value.get().first != expected_value[i]) { cerr << "Expected " << expected_key[i] << " = " << expected_value[i] << ", got " << key << "=" << value << endl; return false; } + ASSERT_EQUAL( key, expected_key[i] ); + ASSERT_EQUAL( value.get().first, expected_value[i] ); i++; } - if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; } + ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) ); return true; } @@ -950,16 +885,18 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ 1, 10, 100 ])"); uint64_t expected_value[] = { 1, 10, 100 }; - int i=0; dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + int i=0; for (auto value : array) { - if (value.get().first != expected_value[i]) { cerr << "Expected " << expected_value[i] << ", got " << value << endl; return false; } + uint64_t v; + ASSERT_SUCCESS( value.get(v) ); + ASSERT_EQUAL( v, expected_value[i] ); i++; } - if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; } + ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) ); return true; } @@ -969,13 +906,13 @@ namespace dom_api_tests { int i = 0; dom::parser parser; - auto [object, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - for (auto [key, value] : object) { - cout << "Unexpected " << key << " = " << value << endl; + dom::object object; + ASSERT_SUCCESS( parser.parse(json).get(object) ); + for (UNUSED auto field : object) { + TEST_FAIL("Unexpected field"); i++; } - if (i > 0) { cout << "Expected 0 values, got " << i << endl; return false; } + ASSERT_EQUAL(i, 0); return true; } @@ -985,13 +922,13 @@ namespace dom_api_tests { int i=0; dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - for (auto value : array) { - cout << "Unexpected value " << value << endl; + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + for (UNUSED auto value : array) { + TEST_FAIL("Unexpected value"); i++; } - if (i > 0) { cout << "Expected 0 values, got " << i << endl; return false; } + ASSERT_EQUAL(i, 0); return true; } @@ -999,13 +936,18 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ "hi", "has backslash\\" ])"); dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - auto val = array.begin(); + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + + auto iter = array.begin(); + std::string_view val; + ASSERT_SUCCESS( (*iter).get(val) ); + ASSERT_EQUAL( val, "hi" ); + + ++iter; + ASSERT_SUCCESS( (*iter).get(val) ); + ASSERT_EQUAL( val, "has backslash\\" ); - if ((*val).get().first != "hi") { cerr << "Expected value to be \"hi\", was " << (*val).get().first << endl; return false; } - ++val; - if ((*val).get().first != "has backslash\\") { cerr << "Expected string_view(\"has backslash\\\\\") to be \"has backslash\\\", was " << (*val).get().first << endl; return false; } return true; } @@ -1013,22 +955,22 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ 0, 1, -1, 1.1 ])"); dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - auto val = array.begin(); + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); - if ((*val).get().first != 0) { cerr << "Expected uint64_t(0) to be 0, was " << (*val) << endl; return false; } - if ((*val).get().first != 0) { cerr << "Expected int64_t(0) to be 0, was " << (*val).get().first << endl; return false; } - if ((*val).get().first != 0) { cerr << "Expected double(0) to be 0, was " << (*val).get().first << endl; return false; } - ++val; - if ((*val).get().first != 1) { cerr << "Expected uint64_t(1) to be 1, was " << (*val) << endl; return false; } - if ((*val).get().first != 1) { cerr << "Expected int64_t(1) to be 1, was " << (*val).get().first << endl; return false; } - if ((*val).get().first != 1) { cerr << "Expected double(1) to be 1, was " << (*val).get().first << endl; return false; } - ++val; - if ((*val).get().first != -1) { cerr << "Expected int64_t(-1) to be -1, was " << (*val).get().first << endl; return false; } - if ((*val).get().first != -1) { cerr << "Expected double(-1) to be -1, was " << (*val).get().first << endl; return false; } - ++val; - if ((*val).get().first != 1.1) { cerr << "Expected double(1.1) to be 1.1, was " << (*val).get().first << endl; return false; } + auto iter = array.begin(); + ASSERT_EQUAL( (*iter).get().first, 0 ); + ASSERT_EQUAL( (*iter).get().first, 0 ); + ASSERT_EQUAL( (*iter).get().first, 0 ); + ++iter; + ASSERT_EQUAL( (*iter).get().first, 1 ); + ASSERT_EQUAL( (*iter).get().first, 1 ); + ASSERT_EQUAL( (*iter).get().first, 1 ); + ++iter; + ASSERT_EQUAL( (*iter).get().first, -1 ); + ASSERT_EQUAL( (*iter).get().first, -1 ); + ++iter; + ASSERT_EQUAL( (*iter).get().first, 1.1 ); return true; } @@ -1036,13 +978,13 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ true, false ])"); dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } - auto val = array.begin(); + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); - if ((*val).get().first != true) { cerr << "Expected bool(true) to be true, was " << (*val) << endl; return false; } + auto val = array.begin(); + ASSERT_EQUAL( (*val).get().first, true ); ++val; - if ((*val).get().first != false) { cerr << "Expected bool(false) to be false, was " << (*val) << endl; return false; } + ASSERT_EQUAL( (*val).get().first, false ); return true; } @@ -1050,10 +992,11 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"([ null ])"); dom::parser parser; - auto [array, error] = parser.parse(json).get(); - if (error) { cerr << "Error: " << error << endl; return false; } + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + auto val = array.begin(); - if (!(*val).is_null()) { cerr << "Expected null to be null!" << endl; return false; } + ASSERT_EQUAL( !(*val).is_null(), 0 ); return true; } @@ -1061,27 +1004,29 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"({ "a": 1, "b": 2, "c/d": 3})"); dom::parser parser; - auto [doc, error] = parser.parse(json); - if (doc["a"].get().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; } - if (doc["b"].get().first != 2) { cerr << "Expected uint64_t(doc[\"b\"]) to be 2, was " << doc["b"].first << endl; return false; } - if (doc["c/d"].get().first != 3) { cerr << "Expected uint64_t(doc[\"c/d\"]) to be 3, was " << doc["c"].first << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.parse(json).get(object) ); + ASSERT_EQUAL( object["a"].get().first, 1 ); + ASSERT_EQUAL( object["b"].get().first, 2 ); + ASSERT_EQUAL( object["c/d"].get().first, 3 ); // Check all three again in backwards order, to ensure we can go backwards - if (doc["c/d"].get().first != 3) { cerr << "Expected uint64_t(doc[\"c/d\"]) to be 3, was " << doc["c"].first << endl; return false; } - if (doc["b"].get().first != 2) { cerr << "Expected uint64_t(doc[\"b\"]) to be 2, was " << doc["b"].first << endl; return false; } - if (doc["a"].get().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; } + ASSERT_EQUAL( object["c/d"].get().first, 3 ); + ASSERT_EQUAL( object["b"].get().first, 2 ); + ASSERT_EQUAL( object["a"].get().first, 1 ); + simdjson::error_code error; UNUSED element val; #ifndef _LIBCPP_VERSION // should work everywhere but with libc++, must include the header. - std::tie(val,error) = doc["d"]; - if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } - std::tie(std::ignore,error) = doc["d"]; - if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } + std::tie(val,error) = object["d"]; + ASSERT_ERROR( error, NO_SUCH_FIELD ); + std::tie(std::ignore,error) = object["d"]; + ASSERT_ERROR( error, NO_SUCH_FIELD ); #endif - // tie(val, error) = doc["d"]; fails with "no viable overloaded '='" on Apple clang version 11.0.0 tie(val, error) = doc["d"]; - doc["d"].tie(val, error); - if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } - if (doc["d"].get(val) != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } - if (doc["d"].error() != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; } + // tie(val, error) = object["d"]; fails with "no viable overloaded '='" on Apple clang version 11.0.0 tie(val, error) = doc["d"]; + object["d"].tie(val, error); + ASSERT_ERROR( error, NO_SUCH_FIELD ); + ASSERT_ERROR( object["d"].get(val), NO_SUCH_FIELD ); + ASSERT_ERROR( object["d"], NO_SUCH_FIELD ); return true; } @@ -1089,26 +1034,25 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"({ "obj": { "a": 1, "b": 2, "c/d": 3 } })"); dom::parser parser; - auto [doc, error] = parser.parse(json); - if (error) { cerr << "Error: " << error << endl; return false; } - if (doc["obj"]["a"].get().first != 1) { cerr << "Expected uint64_t(doc[\"obj\"][\"a\"]) to be 1, was " << doc["obj"]["a"].first << endl; return false; } + dom::element doc; + ASSERT_SUCCESS( parser.parse(json).get(doc) ); + ASSERT_EQUAL( doc["obj"]["a"].get().first, 1); object obj; - error = doc.get(obj); - if (error) { cerr << "Error: " << error << endl; return false; } - if (obj["obj"]["a"].get().first != 1) { cerr << "Expected uint64_t(doc[\"obj\"][\"a\"]) to be 1, was " << doc["obj"]["a"].first << endl; return false; } + ASSERT_SUCCESS( doc.get(obj) ); + ASSERT_EQUAL( obj["obj"]["a"].get().first, 1); - error = obj["obj"].get(obj); - if (obj["a"].get().first != 1) { cerr << "Expected uint64_t(obj[\"a\"]) to be 1, was " << obj["a"].first << endl; return false; } - if (obj["b"].get().first != 2) { cerr << "Expected uint64_t(obj[\"b\"]) to be 2, was " << obj["b"].first << endl; return false; } - if (obj["c/d"].get().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; } + ASSERT_SUCCESS( obj["obj"].get(obj) ); + ASSERT_EQUAL( obj["a"].get().first, 1 ); + ASSERT_EQUAL( obj["b"].get().first, 2 ); + ASSERT_EQUAL( obj["c/d"].get().first, 3 ); // Check all three again in backwards order, to ensure we can go backwards - if (obj["c/d"].get().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; } - if (obj["b"].get().first != 2) { cerr << "Expected uint64_t(obj[\"b\"]) to be 2, was " << obj["b"].first << endl; return false; } - if (obj["a"].get().first != 1) { cerr << "Expected uint64_t(obj[\"a\"]) to be 1, was " << obj["a"].first << endl; return false; } + ASSERT_EQUAL( obj["c/d"].get().first, 3 ); + ASSERT_EQUAL( obj["b"].get().first, 2 ); + ASSERT_EQUAL( obj["a"].get().first, 1 ); UNUSED element val; - if (doc["d"].get(val) != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(obj[\"d\"]), got " << error << endl; return false; } + ASSERT_ERROR( doc["d"].get(val), NO_SUCH_FIELD); return true; } @@ -1116,9 +1060,9 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; // Prints the number of results in twitter.json dom::parser parser; - auto [result_count, error] = parser.load(TWITTER_JSON)["search_metadata"]["count"].get(); - if (error) { cerr << "Error: " << error << endl; return false; } - if (result_count != 100) { cerr << "Expected twitter.json[metadata_count][count] = 100, got " << result_count << endl; return false; } + uint64_t result_count; + ASSERT_SUCCESS( parser.load(TWITTER_JSON)["search_metadata"]["count"].get(result_count) ); + ASSERT_EQUAL( result_count, 100 ); return true; } @@ -1128,20 +1072,19 @@ namespace dom_api_tests { set default_users; dom::parser parser; dom::array tweets; - auto error = parser.load(TWITTER_JSON)["statuses"].get(tweets); - if (error) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( parser.load(TWITTER_JSON)["statuses"].get(tweets) ); for (auto tweet : tweets) { object user; - if ((error = tweet["user"].get(user))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( tweet["user"].get(user) ); bool default_profile; - if ((error = user["default_profile"].get(default_profile))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( user["default_profile"].get(default_profile) ); if (default_profile) { std::string_view screen_name; - if ((error = user["screen_name"].get(screen_name))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( user["screen_name"].get(screen_name) ); default_users.insert(screen_name); } } - if (default_users.size() != 86) { cerr << "Expected twitter.json[statuses][user] to contain 86 default_profile users, got " << default_users.size() << endl; return false; } + ASSERT_EQUAL( default_users.size(), 86 ); return true; } @@ -1149,26 +1092,26 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; // Print image names and sizes set> image_sizes; + simdjson::error_code error; dom::parser parser; dom::array tweets; - auto error = parser.load(TWITTER_JSON)["statuses"].get(tweets); - if (error) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( parser.load(TWITTER_JSON)["statuses"].get(tweets) ); for (auto tweet : tweets) { dom::array media; if (not (error = tweet["entities"]["media"].get(media))) { for (auto image : media) { object sizes; - if ((error = image["sizes"].get(sizes))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( image["sizes"].get(sizes) ); for (auto size : sizes) { uint64_t width, height; - if ((error = size.value["w"].get(width))) { cerr << "Error: " << error << endl; return false; } - if ((error = size.value["h"].get(height))) { cerr << "Error: " << error << endl; return false; } + ASSERT_SUCCESS( size.value["w"].get(width) ); + ASSERT_SUCCESS( size.value["h"].get(height) ); image_sizes.insert(make_pair(width, height)); } } } } - if (image_sizes.size() != 15) { cerr << "Expected twitter.json[statuses][entities][media][sizes] to contain 15 different sizes, got " << image_sizes.size() << endl; return false; } + ASSERT_EQUAL( image_sizes.size(), 15 ); return true; } @@ -1182,12 +1125,12 @@ namespace dom_api_tests { int i = 0; dom::parser parser; - element doc = parser.parse(json); - for (auto [key, value] : doc.get()) { - 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; } + for (auto [key, value] : dom::object(parser.parse(json))) { + ASSERT_EQUAL( key, expected_key[i]); + ASSERT_EQUAL( uint64_t(value), expected_value[i] ); i++; } - if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; } + ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) ); return true; } @@ -1198,69 +1141,61 @@ namespace dom_api_tests { int i=0; dom::parser parser; - element doc = parser.parse(json); - for (uint64_t value : doc.get()) { - if (value != expected_value[i]) { cerr << "Expected " << expected_value[i] << ", got " << value << endl; return false; } + for (uint64_t value : parser.parse(json)) { + ASSERT_EQUAL( value, expected_value[i] ); i++; } - if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; } + ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) ); return true; } bool string_value_exception() { std::cout << "Running " << __func__ << std::endl; - string json(R"([ "hi", "has backslash\\" ])"); dom::parser parser; - auto val = parser.parse(json).get().begin(); - - if (strcmp((const char*)*val, "hi")) { cerr << "Expected const char*(\"hi\") to be \"hi\", was " << (const char*)*val << endl; return false; } - if (string_view(*val) != "hi") { cerr << "Expected string_view(\"hi\") to be \"hi\", was " << string_view(*val) << endl; return false; } - ++val; - if (strcmp((const char*)*val, "has backslash\\")) { cerr << "Expected const char*(\"has backslash\\\\\") to be \"has backslash\\\", was " << (const char*)*val << endl; return false; } - if (string_view(*val) != "has backslash\\") { cerr << "Expected string_view(\"has backslash\\\\\") to be \"has backslash\\\", was " << string_view(*val) << endl; return false; } + ASSERT_EQUAL( (const char *)parser.parse(R"("hi")"_padded), "hi" ); + ASSERT_EQUAL( string_view(parser.parse(R"("hi")"_padded)), "hi" ); + ASSERT_EQUAL( (const char *)parser.parse(R"("has backslash\\")"_padded), "has backslash\\"); + ASSERT_EQUAL( string_view(parser.parse(R"("has backslash\\")"_padded)), "has backslash\\" ); return true; } bool numeric_values_exception() { std::cout << "Running " << __func__ << std::endl; - string json(R"([ 0, 1, -1, 1.1 ])"); dom::parser parser; - auto val = parser.parse(json).get().begin(); - if (uint64_t(*val) != 0) { cerr << "Expected uint64_t(0) to be 0, was " << uint64_t(*val) << endl; return false; } - if (int64_t(*val) != 0) { cerr << "Expected int64_t(0) to be 0, was " << int64_t(*val) << endl; return false; } - if (double(*val) != 0) { cerr << "Expected double(0) to be 0, was " << double(*val) << endl; return false; } - ++val; - if (uint64_t(*val) != 1) { cerr << "Expected uint64_t(1) to be 1, was " << uint64_t(*val) << endl; return false; } - if (int64_t(*val) != 1) { cerr << "Expected int64_t(1) to be 1, was " << int64_t(*val) << endl; return false; } - if (double(*val) != 1) { cerr << "Expected double(1) to be 1, was " << double(*val) << endl; return false; } - ++val; - if (int64_t(*val) != -1) { cerr << "Expected int64_t(-1) to be -1, was " << int64_t(*val) << endl; return false; } - if (double(*val) != -1) { cerr << "Expected double(-1) to be -1, was " << double(*val) << endl; return false; } - ++val; - if (double(*val) != 1.1) { cerr << "Expected double(1.1) to be 1.1, was " << double(*val) << endl; return false; } + ASSERT_EQUAL( uint64_t(parser.parse("0"_padded)), 0); + ASSERT_EQUAL( int64_t(parser.parse("0"_padded)), 0); + ASSERT_EQUAL( double(parser.parse("0"_padded)), 0); + + ASSERT_EQUAL( uint64_t(parser.parse("1"_padded)), 1); + ASSERT_EQUAL( int64_t(parser.parse("1"_padded)), 1); + ASSERT_EQUAL( double(parser.parse("1"_padded)), 1); + + ASSERT_EQUAL( int64_t(parser.parse("-1"_padded)), -1); + ASSERT_EQUAL( double(parser.parse("-1"_padded)), -1); + + ASSERT_EQUAL( double(parser.parse("1.1"_padded)), 1.1); + return true; } bool boolean_values_exception() { std::cout << "Running " << __func__ << std::endl; - string json(R"([ true, false ])"); dom::parser parser; - auto val = parser.parse(json).get().begin(); - if (bool(*val) != true) { cerr << "Expected bool(true) to be true, was " << bool(*val) << endl; return false; } - ++val; - if (bool(*val) != false) { cerr << "Expected bool(false) to be false, was " << bool(*val) << endl; return false; } + ASSERT_EQUAL( bool(parser.parse("true"_padded)), true); + + ASSERT_EQUAL( bool(parser.parse("false"_padded)), false); + return true; } bool null_value_exception() { std::cout << "Running " << __func__ << std::endl; - string json(R"([ null ])"); dom::parser parser; - auto val = parser.parse(json).get().begin(); - if (!(*val).is_null()) { cerr << "Expected null to be null!" << endl; return false; } + ASSERT_EQUAL( bool(parser.parse("null"_padded).is_null()), true ); + return true; } @@ -1268,8 +1203,10 @@ namespace dom_api_tests { std::cout << "Running " << __func__ << std::endl; string json(R"({ "a": 1, "b": 2, "c": 3})"); dom::parser parser; - 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; } + auto obj = parser.parse(json); + + ASSERT_EQUAL(uint64_t(obj["a"]), 1); + return true; } @@ -1278,7 +1215,9 @@ namespace dom_api_tests { string json(R"({ "obj": { "a": 1, "b": 2, "c": 3 } })"); dom::parser parser; object obj = parser.parse(json)["obj"]; - if (uint64_t(obj["a"]) != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << uint64_t(obj["a"]) << endl; return false; } + + ASSERT_EQUAL( uint64_t(obj["a"]), 1); + return true; } @@ -1313,18 +1252,17 @@ namespace dom_api_tests { // Print image names and sizes set> image_sizes; dom::parser parser; - element doc = parser.load(TWITTER_JSON); - for (object tweet : doc["statuses"].get()) { - auto [media, not_found] = tweet["entities"]["media"]; - if (!not_found) { - for (object image : media.get()) { - for (auto size : image["sizes"].get()) { + for (object tweet : parser.load(TWITTER_JSON)["statuses"]) { + auto media = tweet["entities"]["media"]; + if (!media.error()) { + for (object image : media) { + for (auto size : object(image["sizes"])) { image_sizes.insert(make_pair(size.value["w"], size.value["h"])); } } } } - if (image_sizes.size() != 15) { cerr << "Expected twitter.json[statuses][entities][media][sizes] to contain 15 different sizes, got " << image_sizes.size() << endl; return false; } + ASSERT_EQUAL( image_sizes.size(), 15 ); return true; } @@ -1746,21 +1684,10 @@ namespace minify_tests { return false; } size_t newlength{}; - auto error = simdjson::minify(input, length, buffer.get(), newlength); - if(error != simdjson::SUCCESS) { - std::cerr << "error " << error << std::endl; - return false; - } - // memcmp - if(newlength != expected_length) { - std::cerr << "lengths do not match " << std::endl; - return false; - } + ASSERT_SUCCESS( simdjson::minify(input, length, buffer.get(), newlength) ); + ASSERT_EQUAL( newlength, expected_length); for(size_t i = 0; i < newlength; i++) { - if(buffer.get()[i] != expected[i]) { - std::cerr << "Inputs do not match (but same length) " << std::endl; - return false; - } + ASSERT_EQUAL( buffer.get()[i], expected[i]); } return true; } @@ -1810,8 +1737,8 @@ namespace format_tests { bool print_parser_parse() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [doc, error] = parser.parse(DOCUMENT); - if (error) { cerr << error << endl; return false; } + dom::element doc; + ASSERT_SUCCESS( parser.parse(DOCUMENT).get(doc) ); ostringstream s; s << doc; return assert_minified(s); @@ -1819,8 +1746,8 @@ namespace format_tests { bool print_minify_parser_parse() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [doc, error] = parser.parse(DOCUMENT); - if (error) { cerr << error << endl; return false; } + dom::element doc; + ASSERT_SUCCESS( parser.parse(DOCUMENT).get(doc) ); ostringstream s; s << minify(doc); return assert_minified(s); @@ -1829,8 +1756,8 @@ namespace format_tests { bool print_element() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["foo"]; - if (error) { cerr << error << endl; return false; } + dom::element value; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["foo"].get(value) ); ostringstream s; s << value; return assert_minified(s, "1"); @@ -1838,8 +1765,8 @@ namespace format_tests { bool print_minify_element() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["foo"]; - if (error) { cerr << error << endl; return false; } + dom::element value; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["foo"].get(value) ); ostringstream s; s << minify(value); return assert_minified(s, "1"); @@ -1848,38 +1775,38 @@ namespace format_tests { bool print_array() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["bar"].get(); - if (error) { cerr << error << endl; return false; } + dom::array array; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["bar"].get(array) ); ostringstream s; - s << value; + s << array; return assert_minified(s, "[1,2,3]"); } bool print_minify_array() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["bar"].get(); - if (error) { cerr << error << endl; return false; } + dom::array array; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["bar"].get(array) ); ostringstream s; - s << minify(value); + s << minify(array); return assert_minified(s, "[1,2,3]"); } bool print_object() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["baz"].get(); - if (error) { cerr << error << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["baz"].get(object) ); ostringstream s; - s << value; + s << object; return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } bool print_minify_object() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - auto [value, error] = parser.parse(DOCUMENT)["baz"].get(); - if (error) { cerr << error << endl; return false; } + dom::object object; + ASSERT_SUCCESS( parser.parse(DOCUMENT)["baz"].get(object) ); ostringstream s; - s << minify(value); + s << minify(object); return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } @@ -1903,25 +1830,22 @@ namespace format_tests { bool print_element_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << doc["foo"]; + s << parser.parse(DOCUMENT)["foo"]; return assert_minified(s, "1"); } bool print_minify_element_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << minify(doc["foo"]); + s << minify(parser.parse(DOCUMENT)["foo"]); return assert_minified(s, "1"); } bool print_element_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); - element value = doc["foo"]; + element value = parser.parse(DOCUMENT)["foo"]; ostringstream s; s << value; return assert_minified(s, "1"); @@ -1929,8 +1853,7 @@ namespace format_tests { bool print_minify_element_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); - element value = doc["foo"]; + element value = parser.parse(DOCUMENT)["foo"]; ostringstream s; s << minify(value); return assert_minified(s, "1"); @@ -1939,66 +1862,64 @@ namespace format_tests { bool print_array_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << doc["bar"].get(); + s << parser.parse(DOCUMENT)["bar"].get(); return assert_minified(s, "[1,2,3]"); } bool print_minify_array_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << minify(doc["bar"].get()); + s << minify(parser.parse(DOCUMENT)["bar"].get()); return assert_minified(s, "[1,2,3]"); } bool print_object_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << doc["baz"].get(); + s << parser.parse(DOCUMENT)["baz"].get(); return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } bool print_minify_object_result_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); ostringstream s; - s << minify(doc["baz"].get()); + s << minify(parser.parse(DOCUMENT)["baz"].get()); return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } bool print_array_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; + dom::array array = parser.parse(DOCUMENT)["bar"]; ostringstream s; - s << parser.parse(DOCUMENT)["bar"]; + s << array; return assert_minified(s, "[1,2,3]"); } bool print_minify_array_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; + dom::array array = parser.parse(DOCUMENT)["bar"]; ostringstream s; - s << minify(parser.parse(DOCUMENT)["bar"]); + s << minify(array); return assert_minified(s, "[1,2,3]"); } bool print_object_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; + dom::object object = parser.parse(DOCUMENT)["baz"]; ostringstream s; - s << parser.parse(DOCUMENT)["baz"]; + s << object; return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } bool print_minify_object_exception() { std::cout << "Running " << __func__ << std::endl; dom::parser parser; - element doc = parser.parse(DOCUMENT); - object value = doc["baz"]; + dom::object object = parser.parse(DOCUMENT)["baz"]; ostringstream s; - s << minify(value); + s << minify(object); return assert_minified(s, R"({"a":1,"b":2,"c":3})"); } #endif // SIMDJSON_EXCEPTIONS diff --git a/tests/errortests.cpp b/tests/errortests.cpp index 3be94fcd0..f2050d5af 100644 --- a/tests/errortests.cpp +++ b/tests/errortests.cpp @@ -46,15 +46,16 @@ namespace parser_load { ASSERT_SUCCESS(parser.parse_many(DOC).get(docs)); for (auto doc : docs) { count++; - auto [val, error] = doc.get(); + uint64_t val; + auto error = doc.get(val); if (count == 3) { ASSERT_ERROR(error, TAPE_ERROR); } else { - if (error) { TEST_FAIL(error); } - if (val != count) { cerr << "FAIL: expected " << count << ", got " << val << endl; return false; } + ASSERT_SUCCESS(error); + ASSERT_EQUAL(val, count); } } - if (count != 3) { cerr << "FAIL: expected 2 documents and 1 error, got " << count << " total things" << endl; return false; } + ASSERT_EQUAL(count, 3); TEST_SUCCEED(); } @@ -69,7 +70,7 @@ namespace parser_load { count++; ASSERT_ERROR(doc.error(), TAPE_ERROR); } - if (count != 1) { cerr << "FAIL: expected no documents and 1 error, got " << count << " total things" << endl; return false; } + ASSERT_EQUAL(count, 1); TEST_SUCCEED(); } @@ -82,36 +83,34 @@ namespace parser_load { ASSERT_SUCCESS(parser.parse_many(DOC).get(docs)); for (auto doc : docs) { count++; - auto [val, error] = doc.get(); + uint64_t val; + auto error = doc.get(val); if (count == 3) { ASSERT_ERROR(error, TAPE_ERROR); } else { - if (error) { TEST_FAIL(error); } - if (val != count) { cerr << "FAIL: expected " << count << ", got " << val << endl; return false; } + ASSERT_SUCCESS(error); + ASSERT_EQUAL(val, count); } } - if (count != 3) { cerr << "FAIL: expected 2 documents and 1 error, got " << count << " total things" << endl; return false; } + ASSERT_EQUAL(count, 3); TEST_SUCCEED(); } bool parser_load_nonexistent() { TEST_START(); dom::parser parser; - auto error = parser.load(NONEXISTENT_FILE).error(); - ASSERT_ERROR(error, IO_ERROR); + ASSERT_ERROR( parser.load(NONEXISTENT_FILE).error(), IO_ERROR ); TEST_SUCCEED(); } bool parser_load_many_nonexistent() { TEST_START(); dom::parser parser; - dom::document_stream stream; - ASSERT_ERROR(parser.load_many(NONEXISTENT_FILE).get(stream), IO_ERROR); + ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).error(), IO_ERROR ); TEST_SUCCEED(); } bool padded_string_load_nonexistent() { TEST_START(); - auto error = padded_string::load(NONEXISTENT_FILE).error(); - ASSERT_ERROR(error, IO_ERROR); + ASSERT_ERROR(padded_string::load(NONEXISTENT_FILE).error(), IO_ERROR); TEST_SUCCEED(); } @@ -119,16 +118,17 @@ namespace parser_load { TEST_START(); dom::parser parser; UNUSED uint64_t foo; - ASSERT_ERROR( parser.load(NONEXISTENT_FILE)["foo"].get(foo) , IO_ERROR); + ASSERT_ERROR( parser.load(NONEXISTENT_FILE)["foo"].get(foo), IO_ERROR); TEST_SUCCEED(); } bool parser_load_many_chain() { TEST_START(); dom::parser parser; - dom::document_stream stream; - ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).get(stream) , IO_ERROR ); + UNUSED dom::document_stream stream; + ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).get(stream), IO_ERROR ); TEST_SUCCEED(); } + bool run() { return true && parser_load_capacity() diff --git a/tests/integer_tests.cpp b/tests/integer_tests.cpp index c072ac05f..c35d717c8 100644 --- a/tests/integer_tests.cpp +++ b/tests/integer_tests.cpp @@ -3,6 +3,7 @@ #include #include "simdjson.h" +#include "test_macros.h" // we define our own asserts to get around NDEBUG #ifndef ASSERT @@ -29,44 +30,43 @@ template static const std::string make_json(T value) { } template -static void parse_and_validate(const std::string src, T expected) { +static bool parse_and_validate(const std::string src, T expected) { std::cout << "src: " << src << ", "; const padded_string pstr{src}; simdjson::dom::parser parser; - bool result; if constexpr (std::is_same::value) { - auto [actual, error] = parser.parse(pstr).get()["key"].get(); - if (error) { std::cerr << error << std::endl; abort(); } - result = (expected == actual); + int64_t actual; + ASSERT_SUCCESS( parser.parse(pstr)["key"].get(actual) ); + std::cout << std::boolalpha << "test: " << (expected == actual) << std::endl; + ASSERT_EQUAL( expected, actual ); } else { - auto [actual, error] = parser.parse(pstr).get()["key"].get(); - if (error) { std::cerr << error << std::endl; abort(); } - result = (expected == actual); - } - std::cout << std::boolalpha << "test: " << result << std::endl; - if(!result) { - std::cerr << "bug detected" << std::endl; - exit(EXIT_FAILURE); + uint64_t actual; + ASSERT_SUCCESS( parser.parse(pstr)["key"].get(actual) ); + std::cout << std::boolalpha << "test: " << (expected == actual) << std::endl; + ASSERT_EQUAL( expected, actual ); } + return true; } static bool parse_and_check_signed(const std::string src) { std::cout << "src: " << src << ", expecting signed" << std::endl; const padded_string pstr{src}; simdjson::dom::parser parser; - auto [value, error] = parser.parse(pstr).get()["key"]; - if (error) { std::cerr << error << std::endl; abort(); } - return value.is(); + simdjson::dom::element value; + ASSERT_SUCCESS( parser.parse(pstr).get()["key"].get(value) ); + ASSERT_EQUAL( value.is(), true ); + return true; } static bool parse_and_check_unsigned(const std::string src) { std::cout << "src: " << src << ", expecting signed" << std::endl; const padded_string pstr{src}; simdjson::dom::parser parser; - auto [value, error] = parser.parse(pstr).get()["key"]; - if (error) { std::cerr << error << std::endl; abort(); } - return value.is(); + simdjson::dom::element value; + ASSERT_SUCCESS( parser.parse(pstr).get()["key"].get(value) ); + ASSERT_EQUAL( value.is(), true ); + return true; } int main() { @@ -75,21 +75,21 @@ int main() { constexpr auto int64_min = numeric_limits::lowest(); constexpr auto uint64_max = numeric_limits::max(); constexpr auto uint64_min = numeric_limits::lowest(); - parse_and_validate(make_json(int64_max), int64_max); - parse_and_validate(make_json(int64_min), int64_min); - parse_and_validate(make_json(uint64_max), uint64_max); - parse_and_validate(make_json(uint64_min), uint64_min); constexpr auto int64_max_plus1 = static_cast(int64_max) + 1; - parse_and_validate(make_json(int64_max_plus1), int64_max_plus1); - if(!parse_and_check_signed(make_json(int64_max))) { - std::cerr << "bug: large signed integers should be represented as signed integers" << std::endl; - return EXIT_FAILURE; + if (true + && parse_and_validate(make_json(int64_max), int64_max) + && parse_and_validate(make_json(uint64_max), uint64_max) + && parse_and_validate(make_json(uint64_min), uint64_min) + && parse_and_validate(make_json(int64_min), int64_min) + && parse_and_validate(make_json(uint64_max), uint64_max) + && parse_and_validate(make_json(uint64_min), uint64_min) + && parse_and_validate(make_json(int64_max_plus1), int64_max_plus1) + && parse_and_check_signed(make_json(int64_max)) + && parse_and_check_unsigned(make_json(uint64_max)) + ) { + std::cout << "All ok." << std::endl; + return EXIT_SUCCESS; } - if(!parse_and_check_unsigned(make_json(uint64_max))) { - std::cerr << "bug: a large unsigned integers is not represented as an unsigned integer" << std::endl; - return EXIT_FAILURE; - } - std::cout << "All ok." << std::endl; - return EXIT_SUCCESS; + return EXIT_FAILURE; } diff --git a/tests/jsoncheck.cpp b/tests/jsoncheck.cpp index 55c734e69..35001c7ce 100644 --- a/tests/jsoncheck.cpp +++ b/tests/jsoncheck.cpp @@ -60,7 +60,8 @@ bool validate(const char *dirname) { char *fullpath = static_cast(malloc(fullpathlen)); snprintf(fullpath, fullpathlen, "%s%s%s", dirname, needsep ? "/" : "", name); - auto [p, error] = simdjson::padded_string::load(fullpath); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(fullpath).get(p); if (error) { std::cerr << "Could not load the file " << fullpath << std::endl; return EXIT_FAILURE; diff --git a/tests/numberparsingcheck.cpp b/tests/numberparsingcheck.cpp index 92ab25f37..dbcc30477 100644 --- a/tests/numberparsingcheck.cpp +++ b/tests/numberparsingcheck.cpp @@ -172,7 +172,8 @@ bool validate(const char *dirname) { } else { strcpy(fullpath + dirlen, name); } - auto [p, error] = simdjson::padded_string::load(fullpath); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(fullpath).get(p); if (error) { std::cerr << "Could not load the file " << fullpath << std::endl; return EXIT_FAILURE; diff --git a/tests/pointercheck.cpp b/tests/pointercheck.cpp index 58e67ce3e..e0517edb5 100644 --- a/tests/pointercheck.cpp +++ b/tests/pointercheck.cpp @@ -1,6 +1,7 @@ #include #include "simdjson.h" +#include "test_macros.h" // we define our own asserts to get around NDEBUG #ifndef ASSERT @@ -35,49 +36,46 @@ 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; dom::parser parser; - auto [value, error] = parser.parse(TEST_JSON).at(json_pointer).get(); - if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; } - ASSERT(value == expected_value); + std::string_view value; + ASSERT_SUCCESS( parser.parse(TEST_JSON).at(json_pointer).get(value) ); + ASSERT_EQUAL(value, expected_value); return true; } bool json_pointer_success_test(const char *json_pointer) { std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl; dom::parser parser; - auto error = parser.parse(TEST_JSON).at(json_pointer).error(); - if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; } + ASSERT_SUCCESS( parser.parse(TEST_JSON).at(json_pointer).error() ); return true; } -bool json_pointer_failure_test(const char *json_pointer, error_code expected_failure_test) { +bool json_pointer_failure_test(const char *json_pointer, error_code expected_error) { std::cout << "Running invalid JSON pointer test '" << json_pointer << "' ..." << std::endl; dom::parser parser; - auto error = parser.parse(TEST_JSON).at(json_pointer).error(); - ASSERT(error == expected_failure_test); + ASSERT_ERROR(parser.parse(TEST_JSON).at(json_pointer).error(), expected_error); return true; } int main() { - if ( - 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 + if (true + && 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 ) { std::cout << "Success!" << std::endl; return 0; diff --git a/tests/readme_examples.cpp b/tests/readme_examples.cpp index 692b9492a..1469d3d2c 100644 --- a/tests/readme_examples.cpp +++ b/tests/readme_examples.cpp @@ -88,7 +88,7 @@ void basics_dom_4() { auto abstract_json = R"( { "str" : { "123" : {"abc" : 3.14 } } } )"_padded; dom::parser parser; - double v = parser.parse(abstract_json)["str"]["123"]["abc"].get(); + double v = parser.parse(abstract_json)["str"]["123"]["abc"]; cout << "number: " << v << endl; } @@ -141,9 +141,10 @@ namespace treewalk_1 { #ifdef SIMDJSON_CPLUSPLUS17 void basics_cpp17_1() { - dom::parser parser; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; - auto [object, error] = parser.parse(json).get(); + dom::parser parser; + dom::object object; + auto error = parser.parse(json).get(object); if (error) { cerr << error << endl; return; } for (auto [key, value] : object) { cout << key << " = " << value << endl; @@ -153,11 +154,10 @@ void basics_cpp17_1() { void basics_cpp17_2() { // C++ 11 version for comparison - dom::parser parser; padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded; - simdjson::error_code error; + dom::parser parser; dom::object object; - error = parser.parse(json).get(object); + auto error = parser.parse(json).get(object); if (!error) { cerr << error << endl; return; } for (dom::key_value_pair field : object) { cout << field.key << " = " << field.value << endl; @@ -216,26 +216,28 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS // The web_request part of this is aspirational, so we compile as much as we can here void performance_2() { dom::parser parser(1000*1000); // Never grow past documents > 1MB -// for (web_request request : listen()) { - auto [doc, error] = parser.parse("1"_padded/*request.body*/); -// // If the document was above our limit, emit 413 = payload too large + /* for (web_request request : listen()) */ { + dom::element doc; + auto error = parser.parse("1"_padded/*request.body*/).get(doc); + // If the document was above our limit, emit 413 = payload too large if (error == CAPACITY) { /* request.respond(413); continue; */ } -// // ... -// } + // ... + } } // The web_request part of this is aspirational, so we compile as much as we can here void performance_3() { dom::parser parser(0); // This parser will refuse to automatically grow capacity - simdjson::error_code allocate_error = parser.allocate(1000*1000); // This allocates enough capacity to handle documents <= 1MB - if (allocate_error) { cerr << allocate_error << endl; exit(1); } + auto error = parser.allocate(1000*1000); // This allocates enough capacity to handle documents <= 1MB + if (error) { cerr << error << endl; exit(1); } - // for (web_request request : listen()) { - auto [doc, error] = parser.parse("1"_padded/*request.body*/); + /* for (web_request request : listen()) */ { + dom::element doc; + auto error = parser.parse("1"_padded/*request.body*/).get(doc); // If the document was above our limit, emit 413 = payload too large if (error == CAPACITY) { /* request.respond(413); continue; */ } // ... - // } + } } SIMDJSON_POP_DISABLE_WARNINGS #endif diff --git a/tests/readme_examples_noexceptions.cpp b/tests/readme_examples_noexceptions.cpp index 36bf89ced..e668a0f40 100644 --- a/tests/readme_examples_noexceptions.cpp +++ b/tests/readme_examples_noexceptions.cpp @@ -10,7 +10,8 @@ void basics_error_1() { dom::parser parser; auto json = "1"_padded; - auto [doc, error] = parser.parse(json); // doc is a dom::element + dom::element doc; + auto error = parser.parse(json).get(doc); if (error) { cerr << error << endl; exit(1); } // Use document here now that we've checked for the error } @@ -18,14 +19,6 @@ SIMDJSON_POP_DISABLE_WARNINGS #endif void basics_error_2() { - dom::parser parser; - auto json = "1"_padded; - - dom::element doc; - UNUSED auto error = parser.parse(json).get(doc); // <-- Assigns to doc and error just like "auto [doc, error]"} -} - -void basics_error_3() { auto cars_json = R"( [ { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] }, { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] }, @@ -70,8 +63,7 @@ void basics_error_3() { } } - -void basics_error_4() { +void basics_error_3() { auto abstract_json = R"( [ { "12345" : {"a":12.34, "b":56.78, "c": 9998877} }, { "12545" : {"a":11.44, "b":12.78, "c": 11111111} } @@ -102,7 +94,7 @@ void basics_error_4() { } } -void basics_error_5() { +void basics_error_4() { auto abstract_json = R"( { "str" : { "123" : {"abc" : 3.14 } } } )"_padded; dom::parser parser; @@ -116,7 +108,7 @@ void basics_error_5() { #ifdef SIMDJSON_CPLUSPLUS17 -void basics_error_3_cpp17() { +void basics_error_2_cpp17() { auto cars_json = R"( [ { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] }, { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] }, @@ -201,6 +193,5 @@ int main() { basics_error_2(); basics_error_3(); basics_error_4(); - basics_error_5(); return EXIT_SUCCESS; } diff --git a/tests/singleheadertest.cpp b/tests/singleheadertest.cpp index b2d0051d8..46a0e3cb0 100644 --- a/tests/singleheadertest.cpp +++ b/tests/singleheadertest.cpp @@ -6,12 +6,13 @@ using namespace simdjson; int main() { const char *filename = SIMDJSON_BENCHMARK_DATA_DIR "/twitter.json"; - padded_string p = get_corpus(filename); dom::parser parser; - auto [doc, error] = parser.parse(p); - if(error) { + dom::element doc; + auto error = parser.load(filename).get(doc); + if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; } + std::cout << doc << std::endl; return EXIT_SUCCESS; } diff --git a/tests/stringparsingcheck.cpp b/tests/stringparsingcheck.cpp index eeec5900b..cefaa637b 100644 --- a/tests/stringparsingcheck.cpp +++ b/tests/stringparsingcheck.cpp @@ -337,7 +337,8 @@ bool validate(const char *dirname) { } else { strcpy(fullpath + dirlen, name); } - auto [p, error] = simdjson::padded_string::load(fullpath); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(fullpath).get(p); if (error) { std::cerr << "Could not load the file " << fullpath << std::endl; return EXIT_FAILURE; diff --git a/tests/test_macros.h b/tests/test_macros.h index 35228ca24..5c46c0765 100644 --- a/tests/test_macros.h +++ b/tests/test_macros.h @@ -18,21 +18,37 @@ const char *SMALLDEMO_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "smalldemo.json"; const char *TRUENULL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "truenull.json"; // For the ASSERT_EQUAL macro -template -bool equals_expected(T actual, T expected) { - return actual == expected; +template +really_inline bool equals_expected(T actual, S expected) { + return actual == T(expected); } template<> -bool equals_expected(const char *actual, const char *expected) { +really_inline bool equals_expected(const char *actual, const char *expected) { return !strcmp(actual, expected); } +really_inline simdjson::error_code to_error_code(simdjson::error_code error) { + return error; +} +template +really_inline simdjson::error_code to_error_code(const simdjson::simdjson_result &result) { + return result.error(); +} + #define TEST_START() { cout << "Running " << __func__ << " ..." << endl; } -#define ASSERT_EQUAL(ACTUAL, EXPECTED) do { auto _actual = (ACTUAL); auto _expected = (EXPECTED); if (!equals_expected(_actual, _expected)) { std::cerr << "Expected " << #ACTUAL << " to be " << _expected << ", got " << _actual << " instead!" << std::endl; return false; } } while(0); -#define ASSERT_ERROR(ACTUAL, EXPECTED) do { auto _actual = (ACTUAL); auto _expected = (EXPECTED); if (_actual != _expected) { std::cerr << "FAIL: Unexpected error \"" << _actual << "\" (expected \"" << _expected << "\")" << std::endl; return false; } } while (0); +#define ASSERT_EQUAL(ACTUAL, EXPECTED) \ +do { \ + auto _actual = (ACTUAL); \ + auto _expected = (EXPECTED); \ + if (!equals_expected(_actual, _expected)) { \ + std::cerr << "Expected " << (#ACTUAL) << " to be " << _expected << ", got " << _actual << " instead!" << std::endl; \ + return false; \ + } \ +} while(0); +#define ASSERT_ERROR(ACTUAL, EXPECTED) do { auto _actual = to_error_code(ACTUAL); auto _expected = to_error_code(EXPECTED); if (_actual != _expected) { std::cerr << "FAIL: Unexpected error \"" << _actual << "\" (expected \"" << _expected << "\")" << std::endl; return false; } } while (0); #define ASSERT(RESULT, MESSAGE) if (!(RESULT)) { std::cerr << MESSAGE << std::endl; return false; } #define RUN_TEST(RESULT) if (!RESULT) { return false; } -#define ASSERT_SUCCESS(ERROR) do { auto _error = (ERROR); if (_error) { std::cerr << _error << std::endl; return false; } } while(0); +#define ASSERT_SUCCESS(ERROR) do { auto _error = to_error_code(ERROR); if (_error) { std::cerr << _error << std::endl; return false; } } while(0); #define TEST_FAIL(MESSAGE) { std::cerr << "FAIL: " << (MESSAGE) << std::endl; return false; } #define TEST_SUCCEED() { return true; } diff --git a/tools/json2json.cpp b/tools/json2json.cpp index d02ba74c5..084ad3ca2 100644 --- a/tools/json2json.cpp +++ b/tools/json2json.cpp @@ -49,10 +49,10 @@ int main(int argc, char *argv[]) { const char *filename = result["file"].as().c_str(); simdjson::dom::parser parser; - auto [doc, error] = parser.load(filename); // do the parsing, return false on error - if (error != simdjson::SUCCESS) { - std::cerr << " Parsing failed. Error is '" << simdjson::error_message(error) - << "'." << std::endl; + simdjson::dom::element doc; + auto error = parser.load(filename).get(doc); // do the parsing, return false on error + if (error) { + std::cerr << " Parsing failed. Error is '" << error << "'." << std::endl; return EXIT_FAILURE; } if(rawdump) { diff --git a/tools/jsonpointer.cpp b/tools/jsonpointer.cpp index c5f0c6f55..ca6311a1b 100644 --- a/tools/jsonpointer.cpp +++ b/tools/jsonpointer.cpp @@ -20,16 +20,17 @@ int main(int argc, char *argv[]) { const char *filename = argv[1]; simdjson::dom::parser parser; - auto [doc, error] = parser.load(filename); + simdjson::dom::element doc; + auto error = parser.load(filename).get(doc); if (error) { std::cerr << "Error parsing " << filename << ": " << error << std::endl; } std::cout << "[" << std::endl; for (int idx = 2; idx < argc; idx++) { const char *json_pointer = argv[idx]; - auto [value, pointer_error] = doc[json_pointer]; + simdjson::dom::element value; std::cout << "{\"jsonpath\": \"" << json_pointer << "\""; - if (pointer_error) { - std::cout << ",\"error\":\"" << pointer_error << "\""; + if ((error = doc[json_pointer].get(value))) { + std::cout << ",\"error\":\"" << error << "\""; } else { std::cout << ",\"value\":" << value; } diff --git a/tools/jsonstats.cpp b/tools/jsonstats.cpp index 4f2aa4208..977d6a480 100644 --- a/tools/jsonstats.cpp +++ b/tools/jsonstats.cpp @@ -166,7 +166,8 @@ void recurse(simdjson::dom::element element, stat_t &s, size_t depth) { stat_t simdjson_compute_stats(const simdjson::padded_string &p) { stat_t s{}; simdjson::dom::parser parser; - auto [doc, error] = parser.parse(p); + simdjson::dom::element doc; + auto error = parser.parse(p).get(doc); if (error) { s.valid = false; std::cerr << error << std::endl; @@ -217,7 +218,8 @@ int main(int argc, char *argv[]) { const char *filename = result["file"].as().c_str(); - auto [p, error] = simdjson::padded_string::load(filename); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(filename).get(p); if (error) { std::cerr << "Could not load the file " << filename << std::endl; return EXIT_FAILURE; diff --git a/tools/minify.cpp b/tools/minify.cpp index f9f264c42..2e2acebd2 100644 --- a/tools/minify.cpp +++ b/tools/minify.cpp @@ -56,7 +56,8 @@ int main(int argc, char *argv[]) { std::string filename = result["file"].as(); - auto [p, error] = simdjson::padded_string::load(filename); + simdjson::padded_string p; + auto error = simdjson::padded_string::load(filename).get(p); if (error) { std::cerr << "Could not load the file " << filename << std::endl; return EXIT_FAILURE;