diff --git a/.gitignore b/.gitignore index f2d59df08..e40c0647c 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,7 @@ objs /perfdiff /pointercheck /readme_examples +/readme_examples_noexceptions /statisticalmodel /stringparsingcheck /submodules @@ -119,6 +120,7 @@ objs /tests/integer_tests /tests/parse_many_test /tests/readme_examples +/tests/readme_examples_noexceptions /tools/json2json /tools/jsonstats /tools/minify diff --git a/Makefile b/Makefile index 3284347b8..ce8ae8c7b 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,7 @@ JSON_INCLUDE:=dependencies/json/single_include/nlohmann/json.hpp EXTRAOBJECTS=ujdecode.o MAINEXECUTABLES=parse minify json2json jsonstats statisticalmodel jsonpointer get_corpus_benchmark -TESTEXECUTABLES=jsoncheck jsoncheck_westmere jsoncheck_fallback integer_tests numberparsingcheck stringparsingcheck pointercheck parse_many_test basictests errortests readme_examples +TESTEXECUTABLES=jsoncheck jsoncheck_westmere jsoncheck_fallback integer_tests numberparsingcheck stringparsingcheck pointercheck parse_many_test basictests errortests readme_examples readme_examples_noexceptions COMPARISONEXECUTABLES=minifiercompetition parsingcompetition parseandstatcompetition distinctuseridcompetition allparserscheckfile allparsingcompetition SUPPLEMENTARYEXECUTABLES=parse_noutf8validation parse_nonumberparsing parse_nostringparsing @@ -111,9 +111,6 @@ run_basictests: basictests run_errortests: errortests ./errortests -run_readme_examples: readme_examples - ./readme_examples - run_numberparsingcheck: numberparsingcheck ./numberparsingcheck @@ -161,7 +158,7 @@ test: quicktests slowtests quiettest: quicktests slowtests -quicktests: run_basictests run_quickstart run_readme_examples run_jsoncheck run_numberparsingcheck run_integer_tests run_stringparsingcheck run_jsoncheck run_parse_many_test run_pointercheck run_jsoncheck_westmere run_jsoncheck_fallback +quicktests: run_basictests run_quickstart readme_examples readme_examples_noexceptions run_jsoncheck run_numberparsingcheck run_integer_tests run_stringparsingcheck run_jsoncheck run_parse_many_test run_pointercheck run_jsoncheck_westmere run_jsoncheck_fallback slowtests: run_testjson2json_sh run_issue150_sh @@ -234,6 +231,8 @@ errortests:tests/errortests.cpp $(HEADERS) $(LIBFILES) readme_examples: tests/readme_examples.cpp $(HEADERS) $(LIBFILES) $(CXX) $(CXXFLAGS) -o readme_examples tests/readme_examples.cpp -I. $(LIBFILES) $(LIBFLAGS) +readme_examples_noexceptions: tests/readme_examples_noexceptions.cpp $(HEADERS) $(LIBFILES) + $(CXX) $(CXXFLAGS) -o readme_examples_noexceptions tests/readme_examples_noexceptions.cpp -I. $(LIBFILES) $(LIBFLAGS) -fno-exceptions numberparsingcheck: tests/numberparsingcheck.cpp $(HEADERS) src/simdjson.cpp $(CXX) $(CXXFLAGS) -o numberparsingcheck tests/numberparsingcheck.cpp -I. $(LIBFLAGS) -DJSON_TEST_NUMBERS diff --git a/doc/basics.md b/doc/basics.md index b37f3f9e5..69ae2ae0e 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -102,8 +102,6 @@ for (dom::object car : cars) { } ``` - - JSON Pointer ------------ @@ -144,7 +142,7 @@ behavior. > > ```c++ > dom::element doc; -> error_code error; +> simdjson::error_code error; > parser.parse(json).tie(doc, error); // <-- Assigns to doc and error just like "auto [doc, error]" > ``` @@ -154,48 +152,50 @@ This is how the example in "Using the Parsed JSON" could be written using only e ```c++ 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 ] }, - { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] } +{ "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 ] }, +{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] } ] )"_padded; dom::parser parser; -auto [doc, error] = parser.parse(cars_json); +auto [cars, error] = parser.parse(cars_json).get(); if (error) { cerr << error << endl; exit(1); } // Iterating through an array of objects for (dom::element car_element : cars) { - dom::object car; - car_element.get().tie(car, error); - if (error) { cerr << error << endl; exit(1); } +dom::object car; +car_element.get().tie(car, error); +if (error) { cerr << error << endl; exit(1); } - // Accessing a field by name - dom::element make, model; - car["make"].tie(make, error); - if (error) { cerr << error << endl; exit(1); } - car["model"].tie(model, error); - if (error) { cerr << error << endl; exit(1); } - cout << "Make/Model: " << make << "/" << model << endl; +// Accessing a field by name +dom::element make, model; +car["make"].tie(make, error); +if (error) { cerr << error << endl; exit(1); } +car["model"].tie(model, error); +if (error) { cerr << error << endl; exit(1); } +cout << "Make/Model: " << make << "/" << model << endl; - // Casting a JSON element to an integer - uint64_t year; - car["year"].get().tie(year, error); - if (error) { cerr << error << endl; exit(1); } - cout << "- This car is " << 2020 - year << "years old." << endl; +// Casting a JSON element to an integer +uint64_t year; +car["year"].get().tie(year, error); +if (error) { cerr << error << endl; exit(1); } +cout << "- This car is " << 2020 - year << "years old." << endl; - // Iterating through an array of floats - double total_tire_pressure = 0; - for (dom::element tire_pressure_element : car["tire_pressure"]) { +// Iterating through an array of floats +double total_tire_pressure = 0; +dom::array tire_pressure_array; +car["tire_pressure"].get().tie(tire_pressure_array, error); +if (error) { cerr << error << endl; exit(1); } +for (dom::element tire_pressure_element : tire_pressure_array) { double tire_pressure; - tire_pressure_element.get().tie(tire_pressure, error); + tire_pressure_element.get().tie(tire_pressure, error); if (error) { cerr << error << endl; exit(1); } total_tire_pressure += tire_pressure; - } - cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl; +} +cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl; - // Writing out all the information about the car - for (auto [key, value] : car) { +// Writing out all the information about the car +for (auto [key, value] : car) { cout << "- " << key << ": " << value << endl; - } } ``` @@ -215,14 +215,15 @@ Newline-Delimited JSON (ndjson) and JSON lines The simdjson library also support multithreaded JSON streaming through a large file containing many smaller JSON documents in either [ndjson](http://ndjson.org) or [JSON lines](http://jsonlines.org) format. If your JSON documents all contain arrays or objects, we even support direct file concatenation without whitespace. The concatenated file has no size restrictions (including larger than 4GB), though each individual document must be less than 4GB. -Here is a simple example: +Here is a simple example, given "x.json" with this content: -```cpp -auto ndjson = R"( +```json { "foo": 1 } { "foo": 2 } { "foo": 3 } -)"_padded; +``` + +```c++ dom::parser parser; for (dom::element doc : parser.load_many(filename)) { cout << doc["foo"] << endl; diff --git a/include/simdjson/document.h b/include/simdjson/document.h index 66967a2f6..204bcf906 100644 --- a/include/simdjson/document.h +++ b/include/simdjson/document.h @@ -85,263 +85,6 @@ class tape_ref; namespace simdjson::dom { -/** - * A parsed JSON document. - * - * This class cannot be copied, only moved, to avoid unintended allocations. - */ -class document { -public: - /** - * Create a document container with zero capacity. - * - * The parser will allocate capacity as needed. - */ - document() noexcept=default; - ~document() noexcept=default; - - /** - * Take another document's buffers. - * - * @param other The document to take. Its capacity is zeroed and it is invalidated. - */ - document(document &&other) noexcept = default; - document(const document &) = delete; // Disallow copying - /** - * Take another document's buffers. - * - * @param other The document to take. Its capacity is zeroed. - */ - document &operator=(document &&other) noexcept = default; - document &operator=(const document &) = delete; // Disallow copying - - /** - * Get the root element of this document as a JSON array. - */ - element root() const noexcept; - - /** - * Dump the raw tape for debugging. - * - * @param os the stream to output to. - * @return false if the tape is likely wrong (e.g., you did not parse a valid JSON). - */ - bool dump_raw_tape(std::ostream &os) const noexcept; - - std::unique_ptr tape; - std::unique_ptr string_buf;// should be at least byte_capacity - -private: - inline error_code set_capacity(size_t len) noexcept; - template - friend class simdjson::minify; - friend class parser; -}; // class document - -/** - * A JSON element. - * - * References an element in a JSON document, representing a JSON null, boolean, string, number, - * array or object. - */ -class element : protected internal::tape_ref { -public: - /** Create a new, invalid element. */ - really_inline element() noexcept; - - /** Whether this element is a json `null`. */ - really_inline bool is_null() const noexcept; - - /** - * Tell whether the value can be cast to the given primitive type. - * - * Supported types: - * - Boolean: bool - * - Number: double, uint64_t, int64_t - * - String: std::string_view, const char * - * - Array: array - */ - template - really_inline bool is() const noexcept; - - /** - * Get the value as the given primitive type. - * - * Supported types: - * - Boolean: bool - * - Number: double, uint64_t, int64_t - * - String: std::string_view, const char * - * - Array: array - * - * @returns The value cast to the given type, or: - * INCORRECT_TYPE if the value cannot be cast to the given type. - */ - template - really_inline simdjson_result get() const noexcept; - -#if SIMDJSON_EXCEPTIONS - /** - * Read this element as a boolean. - * - * @return The boolean value - * @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not a boolean. - */ - inline operator bool() const noexcept(false); - - /** - * Read this element as a null-terminated string. - * - * Does *not* convert other types to a string; requires that the JSON type of the element was - * an actual string. - * - * @return The string value. - * @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not a string. - */ - inline explicit operator const char*() const noexcept(false); - - /** - * Read this element as a null-terminated string. - * - * Does *not* convert other types to a string; requires that the JSON type of the element was - * an actual string. - * - * @return The string value. - * @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not a string. - */ - inline operator std::string_view() const noexcept(false); - - /** - * Read this element as an unsigned integer. - * - * @return The integer value. - * @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not an integer - * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits or is negative - */ - inline operator uint64_t() const noexcept(false); - /** - * Read this element as an signed integer. - * - * @return The integer value. - * @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not an integer - * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits - */ - inline operator int64_t() const noexcept(false); - /** - * Read this element as an double. - * - * @return The double value. - * @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not a number - * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits or is negative - */ - inline operator double() const noexcept(false); - /** - * Read this element as a JSON array. - * - * @return The JSON array. - * @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not an array - */ - inline operator array() const noexcept(false); - /** - * Read this element as a JSON object (key/value pairs). - * - * @return The JSON object. - * @exception simdjson_error(UNEXPECTED_TYPE) if the JSON element is not an object - */ - inline operator object() const noexcept(false); -#endif // SIMDJSON_EXCEPTIONS - - /** - * Get the value associated with the given key. - * - * 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 - * - * @return The value associated with this field, or: - * - NO_SUCH_FIELD if the field does not exist in the object - * - INCORRECT_TYPE if this is not an object - */ - inline simdjson_result operator[](const std::string_view &key) const noexcept; - - /** - * Get the value associated with the given key. - * - * 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 - * - * @return The value associated with this field, or: - * - NO_SUCH_FIELD if the field does not exist in the object - * - INCORRECT_TYPE if this is not an object - */ - inline simdjson_result operator[](const char *key) const noexcept; - - /** - * Get the value associated with the given JSON pointer. - * - * dom::parser parser; - * element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"); - * doc.at("/foo/a/1") == 20 - * doc.at("/")["foo"]["a"].at(1) == 20 - * doc.at("")["foo"]["a"].at(1) == 20 - * - * @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 simdjson_result at(const 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 simdjson_result at(size_t index) const noexcept; - - /** - * Get the value associated with the given key. - * - * 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 - * - * @return The value associated with this field, or: - * - NO_SUCH_FIELD if the field does not exist in the object - */ - inline simdjson_result at_key(const std::string_view &key) const noexcept; - - /** - * Get the value associated with the given key in a case-insensitive manner. - * - * Note: The key will be matched against **unescaped** JSON. - * - * @return The value associated with this field, or: - * - NO_SUCH_FIELD if the field does not exist in the object - */ - inline simdjson_result at_key_case_insensitive(const std::string_view &key) const noexcept; - - /** @private for debugging. Prints out the root element. */ - inline bool dump_raw_tape(std::ostream &out) const noexcept; - -private: - really_inline element(const document *doc, size_t json_index) noexcept; - friend class document; - friend class object; - friend class array; - friend struct simdjson_result; - template - friend class simdjson::minify; -}; - /** * Represents a JSON array. */ @@ -552,6 +295,279 @@ private: friend class simdjson::minify; }; +/** + * A parsed JSON document. + * + * This class cannot be copied, only moved, to avoid unintended allocations. + */ +class document { +public: + /** + * Create a document container with zero capacity. + * + * The parser will allocate capacity as needed. + */ + document() noexcept=default; + ~document() noexcept=default; + + /** + * Take another document's buffers. + * + * @param other The document to take. Its capacity is zeroed and it is invalidated. + */ + document(document &&other) noexcept = default; + document(const document &) = delete; // Disallow copying + /** + * Take another document's buffers. + * + * @param other The document to take. Its capacity is zeroed. + */ + document &operator=(document &&other) noexcept = default; + document &operator=(const document &) = delete; // Disallow copying + + /** + * Get the root element of this document as a JSON array. + */ + element root() const noexcept; + + /** + * Dump the raw tape for debugging. + * + * @param os the stream to output to. + * @return false if the tape is likely wrong (e.g., you did not parse a valid JSON). + */ + bool dump_raw_tape(std::ostream &os) const noexcept; + + std::unique_ptr tape; + std::unique_ptr string_buf;// should be at least byte_capacity + +private: + inline error_code set_capacity(size_t len) noexcept; + template + friend class simdjson::minify; + friend class parser; +}; // class document + +/** + * A JSON element. + * + * References an element in a JSON document, representing a JSON null, boolean, string, number, + * array or object. + */ +class element : protected internal::tape_ref { +public: + /** Create a new, invalid element. */ + really_inline element() noexcept; + + /** Whether this element is a json `null`. */ + really_inline bool is_null() const noexcept; + + /** + * Tell whether the value can be cast to the given primitive type. + * + * Supported types: + * - Boolean: bool + * - Number: double, uint64_t, int64_t + * - String: std::string_view, const char * + * - Array: array + */ + template + really_inline bool is() const noexcept; + + /** + * Get the value as the given primitive type. + * + * Supported types: + * - Boolean: bool + * - Number: double, uint64_t, int64_t + * - String: std::string_view, const char * + * - Array: array + * + * @returns The value cast to the given type, or: + * INCORRECT_TYPE if the value cannot be cast to the given type. + */ + template + really_inline simdjson_result get() const noexcept; + +#if SIMDJSON_EXCEPTIONS + /** + * Read this element as a boolean. + * + * @return The boolean value + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a boolean. + */ + inline operator bool() const noexcept(false); + + /** + * Read this element as a null-terminated string. + * + * Does *not* convert other types to a string; requires that the JSON type of the element was + * an actual string. + * + * @return The string value. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a string. + */ + inline explicit operator const char*() const noexcept(false); + + /** + * Read this element as a null-terminated string. + * + * Does *not* convert other types to a string; requires that the JSON type of the element was + * an actual string. + * + * @return The string value. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a string. + */ + inline operator std::string_view() const noexcept(false); + + /** + * Read this element as an unsigned integer. + * + * @return The integer value. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an integer + * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits or is negative + */ + inline operator uint64_t() const noexcept(false); + /** + * Read this element as an signed integer. + * + * @return The integer value. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an integer + * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits + */ + inline operator int64_t() const noexcept(false); + /** + * Read this element as an double. + * + * @return The double value. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a number + * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits or is negative + */ + inline operator double() const noexcept(false); + /** + * Read this element as a JSON array. + * + * @return The JSON array. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array + */ + inline operator array() const noexcept(false); + /** + * Read this element as a JSON object (key/value pairs). + * + * @return The JSON object. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an object + */ + inline operator object() const noexcept(false); + + /** + * Iterate over each element in this array. + * + * @return The beginning of the iteration. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array + */ + inline dom::array::iterator begin() const noexcept(false); + + /** + * Iterate over each element in this array. + * + * @return The end of the iteration. + * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array + */ + inline dom::array::iterator end() const noexcept(false); +#endif // SIMDJSON_EXCEPTIONS + + /** + * Get the value associated with the given key. + * + * 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 + * + * @return The value associated with this field, or: + * - NO_SUCH_FIELD if the field does not exist in the object + * - INCORRECT_TYPE if this is not an object + */ + inline simdjson_result operator[](const std::string_view &key) const noexcept; + + /** + * Get the value associated with the given key. + * + * 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 + * + * @return The value associated with this field, or: + * - NO_SUCH_FIELD if the field does not exist in the object + * - INCORRECT_TYPE if this is not an object + */ + inline simdjson_result operator[](const char *key) const noexcept; + + /** + * Get the value associated with the given JSON pointer. + * + * dom::parser parser; + * element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"); + * doc.at("/foo/a/1") == 20 + * doc.at("/")["foo"]["a"].at(1) == 20 + * doc.at("")["foo"]["a"].at(1) == 20 + * + * @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 simdjson_result at(const 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 simdjson_result at(size_t index) const noexcept; + + /** + * Get the value associated with the given key. + * + * 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 + * + * @return The value associated with this field, or: + * - NO_SUCH_FIELD if the field does not exist in the object + */ + inline simdjson_result at_key(const std::string_view &key) const noexcept; + + /** + * Get the value associated with the given key in a case-insensitive manner. + * + * Note: The key will be matched against **unescaped** JSON. + * + * @return The value associated with this field, or: + * - NO_SUCH_FIELD if the field does not exist in the object + */ + inline simdjson_result at_key_case_insensitive(const std::string_view &key) const noexcept; + + /** @private for debugging. Prints out the root element. */ + inline bool dump_raw_tape(std::ostream &out) const noexcept; + +private: + really_inline element(const document *doc, size_t json_index) noexcept; + friend class document; + friend class object; + friend class array; + friend struct simdjson_result; + template + friend class simdjson::minify; +}; + /** * Key/value pair in an object. */ @@ -1445,6 +1461,9 @@ public: inline operator double() const noexcept(false); inline operator dom::array() const noexcept(false); inline operator dom::object() const noexcept(false); + + inline dom::array::iterator begin() const noexcept(false); + inline dom::array::iterator end() const noexcept(false); #endif // SIMDJSON_EXCEPTIONS }; diff --git a/include/simdjson/inline/document.h b/include/simdjson/inline/document.h index c54576c8f..c65ff1802 100644 --- a/include/simdjson/inline/document.h +++ b/include/simdjson/inline/document.h @@ -90,6 +90,15 @@ inline simdjson_result::operator dom::object() const noexcept(fals return get(); } +inline dom::array::iterator simdjson_result::begin() const noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first.begin(); +} +inline dom::array::iterator simdjson_result::end() const noexcept(false) { + if (error()) { throw simdjson_error(error()); } + return first.end(); +} + #endif // @@ -830,6 +839,13 @@ inline element::operator double() const noexcept(false) { return get(); inline element::operator array() const noexcept(false) { return get(); } inline element::operator object() const noexcept(false) { return get(); } +inline dom::array::iterator dom::element::begin() const noexcept(false) { + return get().begin(); +} +inline dom::array::iterator dom::element::end() const noexcept(false) { + return get().end(); +} + #endif inline simdjson_result element::operator[](const std::string_view &key) const noexcept { diff --git a/include/simdjson/inline/parsedjson_iterator.h b/include/simdjson/inline/parsedjson_iterator.h index b45b016f2..11c06b26f 100644 --- a/include/simdjson/inline/parsedjson_iterator.h +++ b/include/simdjson/inline/parsedjson_iterator.h @@ -211,7 +211,11 @@ bool ParsedJson::Iterator::next() { ParsedJson::Iterator::Iterator(const ParsedJson &pj) noexcept(false) : doc(pj.doc), depth(0), location(0), tape_length(0) { +#if SIMDJSON_EXCEPTIONS if (!pj.valid) { throw simdjson_error(pj.error); } +#else + if (!pj.valid) { abort(); } +#endif max_depth = pj.max_depth(); depth_index = new scopeindex_t[max_depth + 1]; diff --git a/tests/readme_examples.cpp b/tests/readme_examples.cpp index 52143f9c7..c3273f532 100644 --- a/tests/readme_examples.cpp +++ b/tests/readme_examples.cpp @@ -1,123 +1,81 @@ #include #include "simdjson.h" + +namespace compile_tests { + using namespace std; using namespace simdjson; +using error_code=simdjson::error_code; -void parser_parse_error_code() { - cout << __func__ << endl; +void basics_1() { + const char *filename = "x.txt"; - // Allocate a parser big enough for all files dom::parser parser; + dom::element doc = parser.load(filename); // load and parse a file - // Read files with the parser, one by one - for (padded_string json : { string("[1, 2, 3]"), string("true"), string("[ true, false ]") }) { - cout << "Parsing " << json.data() << " ..." << endl; - auto [doc, error] = parser.parse(json); - if (error) { cerr << "Error: " << error << endl; exit(1); } - cout << doc << endl; + cout << doc; +} + +void basics_2() { + dom::parser parser; + dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string + + cout << doc; +} + +void basics_dom_1() { + 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 ] }, + { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] } + ] )"_padded; + dom::parser parser; + dom::array cars = parser.parse(cars_json).get(); + + // Iterating through an array of objects + for (dom::object car : cars) { + // Accessing a field by name + cout << "Make/Model: " << car["make"] << "/" << car["model"] << endl; + + // Casting a JSON element to an integer + uint64_t year = car["year"]; + cout << "- This car is " << 2020 - year << "years old." << endl; + + // Iterating through an array of floats + double total_tire_pressure = 0; + for (double tire_pressure : car["tire_pressure"]) { + total_tire_pressure += tire_pressure; + } + cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl; + + // Writing out all the information about the car + for (auto [key, value] : car) { + cout << "- " << key << ": " << value << endl; + } } } -void parser_parse_many_error_code() { - cout << __func__ << endl; - - // Read files with the parser - auto json = "[1, 2, 3] true [ true, false ]"_padded; - cout << "Parsing " << json.data() << " ..." << endl; +void basics_dom_2() { + 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 ] }, + { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] } + ] )"_padded; dom::parser parser; - for (auto [doc, error] : parser.parse_many(json)) { - if (error) { cerr << "Error: " << error << endl; exit(1); } - cout << doc << endl; - } + dom::element cars = parser.parse(cars_json); + cout << cars.at("0/tire_pressure/1") << endl; // Prints 39.9} } -void parser_parse_max_capacity() { - cout << __func__ << endl; - - int argc = 2; - padded_string argv[] { string("[1,2,3]"), string("true") }; - dom::parser parser(1024*1024); // Set max capacity to 1MB - for (int i=0;i +#include "simdjson.h" + +using namespace std; +using namespace simdjson; + +void basics_error_1() { + dom::parser parser; + auto json = "1"_padded; + + auto [doc, error] = parser.parse(json); // doc is a dom::element + if (error) { cerr << error << endl; exit(1); } + // Use document here now that we've checked for the error +} + +void basics_error_2() { + dom::parser parser; + auto json = "1"_padded; + + dom::element doc; + simdjson::error_code error; + parser.parse(json).tie(doc, error); // <-- 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 ] }, + { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] } + ] )"_padded; + dom::parser parser; + auto [cars, error] = parser.parse(cars_json).get(); + if (error) { cerr << error << endl; exit(1); } + + // Iterating through an array of objects + for (dom::element car_element : cars) { + dom::object car; + car_element.get().tie(car, error); + if (error) { cerr << error << endl; exit(1); } + + // Accessing a field by name + dom::element make, model; + car["make"].tie(make, error); + if (error) { cerr << error << endl; exit(1); } + car["model"].tie(model, error); + if (error) { cerr << error << endl; exit(1); } + cout << "Make/Model: " << make << "/" << model << endl; + + // Casting a JSON element to an integer + uint64_t year; + car["year"].get().tie(year, error); + if (error) { cerr << error << endl; exit(1); } + cout << "- This car is " << 2020 - year << "years old." << endl; + + // Iterating through an array of floats + double total_tire_pressure = 0; + dom::array tire_pressure_array; + car["tire_pressure"].get().tie(tire_pressure_array, error); + if (error) { cerr << error << endl; exit(1); } + for (dom::element tire_pressure_element : tire_pressure_array) { + double tire_pressure; + tire_pressure_element.get().tie(tire_pressure, error); + if (error) { cerr << error << endl; exit(1); } + total_tire_pressure += tire_pressure; + } + cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl; + + // Writing out all the information about the car + for (auto [key, value] : car) { + cout << "- " << key << ": " << value << endl; + } + } +} + +int main() { + return 0; +}