diff --git a/.github/workflows/macos-11.yml b/.github/workflows/macos-11.yml deleted file mode 100644 index 579bdd0db..000000000 --- a/.github/workflows/macos-11.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Macos (Xcode 11) - -on: [push, pull_request] - -jobs: - macos-build: - if: >- - ! contains(toJSON(github.event.commits.*.message), '[skip ci]') && - ! contains(toJSON(github.event.commits.*.message), '[skip github]') - runs-on: macos-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 - with: - path: dependencies/.cache - key: ${{ hashFiles('dependencies/CMakeLists.txt') }} - - name: Use cmake - run: | - xcversion select 11.7 - mkdir builddebug && - cd builddebug && - cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && - cmake --build . && - ctest -j --output-on-failure -LE explicitonly && - cd .. && - mkdir build && - cd build && - cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && - cmake --build . && - ctest -j --output-on-failure -LE explicitonly && - cmake --install . && - echo -e '#include \nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json && - cd ../tests/installation_tests/find && - mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build . diff --git a/benchmark/json2msgpack/simdjson_ondemand.h b/benchmark/json2msgpack/simdjson_ondemand.h index e1d7b2abc..3c4daa4cf 100644 --- a/benchmark/json2msgpack/simdjson_ondemand.h +++ b/benchmark/json2msgpack/simdjson_ondemand.h @@ -74,10 +74,11 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json, write_byte(0xc2 + doc.get_bool()); break; case simdjson::ondemand::json_type::null: - write_byte(0xc0); - // As a side effect, the is_null call advances the document's iterator - // so that the current_location check would work in all cases. - doc.is_null(); + // We check that the value is indeed null + // otherwise: an error is thrown. + if(doc.is_null()) { + write_byte(0xc0); + } break; case simdjson::ondemand::json_type::array: case simdjson::ondemand::json_type::object: @@ -163,7 +164,11 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) { write_byte(0xc2 + element.get_bool()); break; case simdjson::ondemand::json_type::null: - write_byte(0xc0); + // We check that the value is indeed null + // otherwise: an error is thrown. + if(element.is_null()) { + write_byte(0xc0); + } break; default: SIMDJSON_UNREACHABLE(); diff --git a/doc/basics.md b/doc/basics.md index 6a9ef33cd..419383375 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -482,8 +482,20 @@ support for users who avoid exceptions. See [the simdjson error handling documen std::cout << "Number of fields: " << count << std::endl; // Prints "Number of fields: 2" ``` * **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document - with a known type, and are trying to generically inspect or walk over JSON elements. To do that, you can use iterators and the `type()` method. You can also represent arbitrary JSON values with - `ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You may also access [raw strings](#raw-strings). + with a known type, and are trying to generically inspect or walk over JSON elements. + You can also represent arbitrary JSON values with + `ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. + You can query the type of a document or a value with the `type()` method. + The `type()` method does not consume or validate documents and values, but it tells you whether they are + - arrays (`json_type::array`), + - objects (`json_type::object`) + - numbers (`json_type::number`), + - strings (`json_type::string`), + - Booleans (`json_type::boolean`), + - null (`json_type::null`). + + You must still validate and consume the values (e.g., call `is_null()`) after calling `type()`. + You may also access [raw strings](#raw-strings). For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`. ```c++ void recursive_print_json(ondemand::value element) { @@ -532,7 +544,11 @@ support for users who avoid exceptions. See [the simdjson error handling documen cout << element.get_bool(); break; case ondemand::json_type::null: - cout << "null"; + // We check that the value is indeed null + // otherwise: an error is thrown. + if(element.is_null()) { + cout << "null"; + } break; } } @@ -1110,7 +1126,7 @@ for (auto val : doc) { std::cout << doc.current_location() << std::endl; // Throws OUT_OF_BOUNDS ``` -Conversely, if `doc.current_location().error() == simdjson::SUCCESS`, +Conversely, if `doc.current_location().error() == simdjson::SUCCESS`, then the document has more content. Finally, the `current_location()` method may also be used even when no exceptions/errors diff --git a/include/simdjson/generic/ondemand/document-inl.h b/include/simdjson/generic/ondemand/document-inl.h index 90117b3c1..596bad0f4 100644 --- a/include/simdjson/generic/ondemand/document-inl.h +++ b/include/simdjson/generic/ondemand/document-inl.h @@ -94,7 +94,7 @@ simdjson_inline simdjson_result document::get_raw_json_string() simdjson_inline simdjson_result document::get_bool() noexcept { return get_root_value_iterator().get_root_bool(); } -simdjson_inline bool document::is_null() noexcept { +simdjson_inline simdjson_result document::is_null() noexcept { return get_root_value_iterator().is_root_null(); } @@ -354,7 +354,7 @@ simdjson_inline simdjson_result simdjs if (error()) { return error(); } return first.get_value(); } -simdjson_inline bool simdjson_result::is_null() noexcept { +simdjson_inline simdjson_result simdjson_result::is_null() noexcept { if (error()) { return error(); } return first.is_null(); } @@ -504,7 +504,7 @@ simdjson_inline simdjson_result document_reference::get_string simdjson_inline simdjson_result document_reference::get_raw_json_string() noexcept { return doc->get_raw_json_string(); } simdjson_inline simdjson_result document_reference::get_bool() noexcept { return doc->get_bool(); } simdjson_inline simdjson_result document_reference::get_value() noexcept { return doc->get_value(); } -simdjson_inline bool document_reference::is_null() noexcept { return doc->is_null(); } +simdjson_inline simdjson_result document_reference::is_null() noexcept { return doc->is_null(); } #if SIMDJSON_EXCEPTIONS simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); } @@ -636,7 +636,7 @@ simdjson_inline simdjson_result simdjs if (error()) { return error(); } return first.get_value(); } -simdjson_inline bool simdjson_result::is_null() noexcept { +simdjson_inline simdjson_result simdjson_result::is_null() noexcept { if (error()) { return error(); } return first.is_null(); } @@ -648,7 +648,7 @@ simdjson_inline simdjson_result simdjson_result::is_negative() noexcept { +simdjson_inline simdjson_result simdjson_result::is_negative() noexcept { if (error()) { return error(); } return first.is_negative(); } diff --git a/include/simdjson/generic/ondemand/document.h b/include/simdjson/generic/ondemand/document.h index 6a926aae5..eb401dbaa 100644 --- a/include/simdjson/generic/ondemand/document.h +++ b/include/simdjson/generic/ondemand/document.h @@ -126,11 +126,14 @@ public: simdjson_inline simdjson_result get_value() noexcept; /** - * Checks if this JSON value is null. + * Checks if this JSON value is null. If and only if the value is + * null, then it is consumed (we advance). If we find a token that + * begins with 'n' but is not 'null', then an error is returned. * * @returns Whether the value is null. + * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'. */ - simdjson_inline bool is_null() noexcept; + simdjson_inline simdjson_result is_null() noexcept; /** * Get this value as the given type. @@ -363,7 +366,9 @@ public: simdjson_inline simdjson_result operator[](const char *key) & noexcept; /** - * Get the type of this JSON value. + * Get the type of this JSON value. It does not validate or consume the value. + * E.g., you must still call "is_null()" to check that a value is null even if + * "type()" returns json_type::null. * * NOTE: If you're only expecting a value to be one type (a typical case), it's generally * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just @@ -595,7 +600,7 @@ public: simdjson_inline simdjson_result get_bool() noexcept; simdjson_inline simdjson_result get_value() noexcept; - simdjson_inline bool is_null() noexcept; + simdjson_inline simdjson_result is_null() noexcept; simdjson_inline simdjson_result raw_json() noexcept; simdjson_inline operator document&() const noexcept; @@ -660,7 +665,7 @@ public: simdjson_inline simdjson_result get_raw_json_string() noexcept; simdjson_inline simdjson_result get_bool() noexcept; simdjson_inline simdjson_result get_value() noexcept; - simdjson_inline bool is_null() noexcept; + simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & noexcept; template simdjson_inline simdjson_result get() && noexcept; @@ -727,7 +732,7 @@ public: simdjson_inline simdjson_result get_raw_json_string() noexcept; simdjson_inline simdjson_result get_bool() noexcept; simdjson_inline simdjson_result get_value() noexcept; - simdjson_inline bool is_null() noexcept; + simdjson_inline simdjson_result is_null() noexcept; #if SIMDJSON_EXCEPTIONS simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false); @@ -754,8 +759,8 @@ public: simdjson_inline simdjson_result type() noexcept; simdjson_inline simdjson_result is_scalar() noexcept; simdjson_inline simdjson_result current_location() noexcept; - simdjson_inline int32_t current_depth() const noexcept; - simdjson_inline bool is_negative() noexcept; + simdjson_inline simdjson_result current_depth() const noexcept; + simdjson_inline simdjson_result is_negative() noexcept; simdjson_inline simdjson_result is_integer() noexcept; simdjson_inline simdjson_result get_number_type() noexcept; simdjson_inline simdjson_result get_number() noexcept; diff --git a/include/simdjson/generic/ondemand/serialization.h b/include/simdjson/generic/ondemand/serialization.h index 0d2eca69f..64f16a2d4 100644 --- a/include/simdjson/generic/ondemand/serialization.h +++ b/include/simdjson/generic/ondemand/serialization.h @@ -4,23 +4,27 @@ namespace simdjson { /** * Create a string-view instance out of a document instance. The string-view instance - * contains JSON text that is suitable to be parsed as JSON again. + * contains JSON text that is suitable to be parsed as JSON again. It does not + * validate the content. */ inline simdjson_result to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document& x) noexcept; /** * Create a string-view instance out of a value instance. The string-view instance * contains JSON text that is suitable to be parsed as JSON again. The value must - * not have been accessed previously. + * not have been accessed previously. It does not + * validate the content. */ inline simdjson_result to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::value& x) noexcept; /** * Create a string-view instance out of an object instance. The string-view instance - * contains JSON text that is suitable to be parsed as JSON again. + * contains JSON text that is suitable to be parsed as JSON again. It does not + * validate the content. */ inline simdjson_result to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::object& x) noexcept; /** * Create a string-view instance out of an array instance. The string-view instance - * contains JSON text that is suitable to be parsed as JSON again. + * contains JSON text that is suitable to be parsed as JSON again. It does not + * validate the content. */ inline simdjson_result to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::array& x) noexcept; inline simdjson_result to_json_string(simdjson_result x); @@ -39,7 +43,8 @@ inline simdjson_result to_json_string(simdjson_result x); #endif /** - * Print JSON to an output stream. + * Print JSON to an output stream. It does not + * validate the content. * * @param out The output stream. * @param value The array. @@ -61,7 +67,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x); #endif /** - * Print JSON to an output stream. + * Print JSON to an output stream. It does not + * validate the content. * * @param out The output stream. * @param value The array. @@ -76,7 +83,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result&& x); #endif /** - * Print JSON to an output stream. + * Print JSON to an output stream. It does not + * validate the content. * * @param out The output stream. * @param value The object. diff --git a/include/simdjson/generic/ondemand/value-inl.h b/include/simdjson/generic/ondemand/value-inl.h index 813fcb69d..801bbcd7f 100644 --- a/include/simdjson/generic/ondemand/value-inl.h +++ b/include/simdjson/generic/ondemand/value-inl.h @@ -54,10 +54,9 @@ simdjson_inline simdjson_result value::get_int64_in_string() noexcept { simdjson_inline simdjson_result value::get_bool() noexcept { return iter.get_bool(); } -simdjson_inline bool value::is_null() noexcept { +simdjson_inline simdjson_result value::is_null() noexcept { return iter.is_null(); } - template<> simdjson_inline simdjson_result value::get() noexcept { return get_array(); } template<> simdjson_inline simdjson_result value::get() noexcept { return get_object(); } template<> simdjson_inline simdjson_result value::get() noexcept { return get_raw_json_string(); } @@ -311,8 +310,8 @@ simdjson_inline simdjson_result simdjson_result::is_null() noexcept { - if (error()) { return false; } +simdjson_inline simdjson_result simdjson_result::is_null() noexcept { + if (error()) { return error(); } return first.is_null(); } @@ -404,7 +403,7 @@ simdjson_inline simdjson_result simdjson_result::current_depth() const noexcept { +simdjson_inline simdjson_result simdjson_result::current_depth() const noexcept { if (error()) { return error(); } return first.current_depth(); } diff --git a/include/simdjson/generic/ondemand/value.h b/include/simdjson/generic/ondemand/value.h index 0a9486565..a3d5d6638 100644 --- a/include/simdjson/generic/ondemand/value.h +++ b/include/simdjson/generic/ondemand/value.h @@ -150,11 +150,14 @@ public: simdjson_inline simdjson_result get_bool() noexcept; /** - * Checks if this JSON value is null. + * Checks if this JSON value is null. If and only if the value is + * null, then it is consumed (we advance). If we find a token that + * begins with 'n' but is not 'null', then an error is returned. * * @returns Whether the value is null. + * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'. */ - simdjson_inline bool is_null() noexcept; + simdjson_inline simdjson_result is_null() noexcept; #if SIMDJSON_EXCEPTIONS /** @@ -334,7 +337,9 @@ public: simdjson_inline simdjson_result operator[](const char *key) noexcept; /** - * Get the type of this JSON value. + * Get the type of this JSON value. It does not validate or consume the value. + * E.g., you must still call "is_null()" to check that a value is null even if + * "type()" returns json_type::null. * * NOTE: If you're only expecting a value to be one type (a typical case), it's generally * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just @@ -583,7 +588,7 @@ public: simdjson_inline simdjson_result get_string() noexcept; simdjson_inline simdjson_result get_raw_json_string() noexcept; simdjson_inline simdjson_result get_bool() noexcept; - simdjson_inline bool is_null() noexcept; + simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() noexcept; @@ -676,7 +681,7 @@ public: /** @copydoc simdjson_inline simdjson_result current_location() noexcept */ simdjson_inline simdjson_result current_location() noexcept; /** @copydoc simdjson_inline int32_t current_depth() const noexcept */ - simdjson_inline int32_t current_depth() const noexcept; + simdjson_inline simdjson_result current_depth() const noexcept; simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; }; diff --git a/include/simdjson/generic/ondemand/value_iterator-inl.h b/include/simdjson/generic/ondemand/value_iterator-inl.h index c099c99db..98c4529dd 100644 --- a/include/simdjson/generic/ondemand/value_iterator-inl.h +++ b/include/simdjson/generic/ondemand/value_iterator-inl.h @@ -468,8 +468,11 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::parse if (error) { return incorrect_type_error("Not a boolean"); } return simdjson_result(!not_true); } -simdjson_inline bool value_iterator::parse_null(const uint8_t *json) const noexcept { - return !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]); +simdjson_warn_unused simdjson_inline simdjson_result value_iterator::parse_null(const uint8_t *json) const noexcept { + bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]); + // if we start with 'n', we must be a null + if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); } + return is_null_string; } simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_string() noexcept { @@ -516,10 +519,11 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::get_b if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); } return result; } -simdjson_inline bool value_iterator::is_null() noexcept { - auto result = parse_null(peek_non_root_scalar("null")); - if(result) { advance_non_root_scalar("null"); } - return result; +simdjson_inline simdjson_result value_iterator::is_null() noexcept { + bool is_null_value; + SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value)); + if(is_null_value) { advance_non_root_scalar("null"); } + return is_null_value; } simdjson_inline bool value_iterator::is_negative() noexcept { return numberparsing::is_negative(peek_non_root_scalar("numbersign")); diff --git a/include/simdjson/generic/ondemand/value_iterator.h b/include/simdjson/generic/ondemand/value_iterator.h index 1b1e012c9..7cd7a25ea 100644 --- a/include/simdjson/generic/ondemand/value_iterator.h +++ b/include/simdjson/generic/ondemand/value_iterator.h @@ -289,7 +289,7 @@ public: simdjson_warn_unused simdjson_inline simdjson_result get_double() noexcept; simdjson_warn_unused simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_warn_unused simdjson_inline simdjson_result get_bool() noexcept; - simdjson_inline bool is_null() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result is_null() noexcept; simdjson_warn_unused simdjson_inline bool is_negative() noexcept; simdjson_warn_unused simdjson_inline simdjson_result is_integer() noexcept; simdjson_warn_unused simdjson_inline simdjson_result get_number_type() noexcept; @@ -350,7 +350,7 @@ protected: inline std::string to_string() const noexcept; simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept; - simdjson_inline bool parse_null(const uint8_t *json) const noexcept; + simdjson_inline simdjson_result parse_null(const uint8_t *json) const noexcept; simdjson_inline simdjson_result parse_bool(const uint8_t *json) const noexcept; simdjson_inline const uint8_t *peek_start() const noexcept; simdjson_inline uint32_t peek_start_length() const noexcept; diff --git a/tests/dom/readme_examples.cpp b/tests/dom/readme_examples.cpp index 5a8761999..4abefd97c 100644 --- a/tests/dom/readme_examples.cpp +++ b/tests/dom/readme_examples.cpp @@ -160,7 +160,11 @@ namespace ondemand_treewalk { cout << element.get_bool(); break; case ondemand::json_type::null: - cout << "null"; + // We check that the value is indeed null + // otherwise: an error is thrown. + if(element.is_null()) { + cout << "null"; + } break; } } diff --git a/tests/ondemand/ondemand_error_tests.cpp b/tests/ondemand/ondemand_error_tests.cpp index 6234ffa1c..5f3af0e4a 100644 --- a/tests/ondemand/ondemand_error_tests.cpp +++ b/tests/ondemand/ondemand_error_tests.cpp @@ -119,7 +119,9 @@ namespace error_tests { SUBTEST("simdjson_result", test_ondemand_doc(json, [&](auto doc) { simdjson_result val = doc["val"]; // Get everything that can fail in both forward and backwards order - ASSERT_EQUAL( val.is_null(), false ); + bool is_null_value; + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, false ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); @@ -131,15 +133,18 @@ namespace error_tests { ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); - ASSERT_EQUAL( val.is_null(), false ); ASSERT_SUCCESS( val.get_bool() ); + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, false ); TEST_SUCCEED(); })); SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) { ondemand::value val; ASSERT_SUCCESS( doc["val"].get(val) ); // Get everything that can fail in both forward and backwards order - ASSERT_EQUAL( val.is_null(), false ); + bool is_null_value; + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, false ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); @@ -151,14 +156,17 @@ namespace error_tests { ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); - ASSERT_EQUAL( val.is_null(), false ); ASSERT_SUCCESS( val.get_bool() ); + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, false ); TEST_SUCCEED(); })); json = R"(true)"_padded; SUBTEST("simdjson_result", test_ondemand_doc(json, [&](simdjson_result val) { // Get everything that can fail in both forward and backwards order - ASSERT_EQUAL( val.is_null(), false ); + bool is_null_value; + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, false ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); @@ -170,14 +178,17 @@ namespace error_tests { ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); - ASSERT_EQUAL( val.is_null(), false ); ASSERT_SUCCESS( val.get_bool()); + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, false ); TEST_SUCCEED(); })); SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) { ondemand::document val; ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order - ASSERT_EQUAL( val.is_null(), false ); + bool is_null_value; + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, false ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); @@ -189,8 +200,9 @@ namespace error_tests { ASSERT_ERROR( val.get_double(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); - ASSERT_EQUAL( val.is_null(), false ); ASSERT_SUCCESS( val.get_bool() ); + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, false ); TEST_SUCCEED(); })); @@ -216,13 +228,16 @@ namespace error_tests { ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); - ASSERT_EQUAL( val.is_null(), true ); + bool is_null_value; + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, true ); TEST_SUCCEED(); })); SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) { ondemand::value val; ASSERT_SUCCESS( doc["val"].get(val) ); // Get everything that can fail in both forward and backwards order + ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); @@ -236,7 +251,9 @@ namespace error_tests { ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); - ASSERT_EQUAL( val.is_null(), true ); + bool is_null_value; + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, true ); TEST_SUCCEED(); })); json = R"(null)"_padded; @@ -255,7 +272,9 @@ namespace error_tests { ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); - ASSERT_EQUAL( val.is_null(), true ); + bool is_null_value; + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, true ); TEST_SUCCEED(); })); SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) { @@ -274,7 +293,9 @@ namespace error_tests { ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); - ASSERT_EQUAL( val.is_null(), true ); + bool is_null_value; + ASSERT_SUCCESS( val.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, true ); TEST_SUCCEED(); })); TEST_SUCCEED(); diff --git a/tests/ondemand/ondemand_json_pointer_tests.cpp b/tests/ondemand/ondemand_json_pointer_tests.cpp index 179479ded..bf0b93d32 100644 --- a/tests/ondemand/ondemand_json_pointer_tests.cpp +++ b/tests/ondemand/ondemand_json_pointer_tests.cpp @@ -71,7 +71,7 @@ namespace json_pointer_tests { ASSERT_SUCCESS(val.get_bool().error()); break; case ondemand::json_type::null: - ASSERT_TRUE(val.is_null()); + ASSERT_SUCCESS(val.is_null().error()); break; default: TEST_FAIL("unexpected type"); diff --git a/tests/ondemand/ondemand_misc_tests.cpp b/tests/ondemand/ondemand_misc_tests.cpp index 1a422f534..2cb88d346 100644 --- a/tests/ondemand/ondemand_misc_tests.cpp +++ b/tests/ondemand/ondemand_misc_tests.cpp @@ -271,7 +271,9 @@ namespace misc_tests { ASSERT_SUCCESS(global.get(global_object)); ondemand::value shadowable; ASSERT_SUCCESS(global_object["shadowable"].get(shadowable)); - ASSERT_TRUE(!shadowable.is_null()); + bool is_null_value; + ASSERT_SUCCESS(shadowable.is_null().get(is_null_value)); + ASSERT_TRUE(!is_null_value); ondemand::value badvalue; auto error = global_object["writable"].get(badvalue); if(error == SUCCESS) { diff --git a/tests/ondemand/ondemand_readme_examples.cpp b/tests/ondemand/ondemand_readme_examples.cpp index ae582c669..1ee9377a6 100644 --- a/tests/ondemand/ondemand_readme_examples.cpp +++ b/tests/ondemand/ondemand_readme_examples.cpp @@ -87,7 +87,11 @@ void recursive_print_json(ondemand::value element) { cout << element.get_bool(); break; case ondemand::json_type::null: - cout << "null"; + // we check that the value is indeed null + // otherwise: an error is thrown. + if(element.is_null()) { + cout << "null"; + } break; } } @@ -166,7 +170,11 @@ void recursive_print_json_breakline(ondemand::value element) { cout << element.get_bool(); break; case ondemand::json_type::null: - cout << "null"; + // We check that the value is indeed null + // otherwise: an error is thrown. + if(element.is_null()) { + cout << "null"; + } break; } } diff --git a/tests/ondemand/ondemand_scalar_tests.cpp b/tests/ondemand/ondemand_scalar_tests.cpp index 8bc188e27..082369ee9 100644 --- a/tests/ondemand/ondemand_scalar_tests.cpp +++ b/tests/ondemand/ondemand_scalar_tests.cpp @@ -206,11 +206,15 @@ namespace scalar_tests { SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) { ondemand::document doc; ASSERT_SUCCESS( std::move(doc_result).get(doc) ); - ASSERT_EQUAL( doc.is_null(), true ); + bool is_null_value; + ASSERT_SUCCESS( doc.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, true ); return true; })); SUBTEST("simdjson_result", test_ondemand_doc(json, [&](auto doc_result) { - ASSERT_EQUAL( doc_result.is_null(), true ); + bool is_null_value; + ASSERT_SUCCESS( doc_result.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, true ); return true; })); json = "[null]"_padded; @@ -219,7 +223,9 @@ namespace scalar_tests { for (auto value_result : doc_result) { ondemand::value value; ASSERT_SUCCESS( value_result.get(value) ); - ASSERT_EQUAL( value.is_null(), true ); + bool is_null_value; + ASSERT_SUCCESS( value.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, true ); count++; } ASSERT_EQUAL( count, 1 ); @@ -228,7 +234,9 @@ namespace scalar_tests { SUBTEST("simdjson_result", test_ondemand_doc(json, [&](auto doc_result) { int count = 0; for (auto value_result : doc_result) { - ASSERT_EQUAL( value_result.is_null(), true ); + bool is_null_value; + ASSERT_SUCCESS( value_result.is_null().get(is_null_value) ); + ASSERT_EQUAL( is_null_value, true ); count++; } ASSERT_EQUAL( count, 1 ); diff --git a/tools/json2json.cpp b/tools/json2json.cpp index 949aeb8d9..0b776dc0f 100644 --- a/tools/json2json.cpp +++ b/tools/json2json.cpp @@ -63,6 +63,8 @@ int main(int argc, const char *argv[]) { simdjson::ondemand::document doc; error = parser.iterate(docdata).get(doc); if(error != simdjson::SUCCESS) { std::cout << error << std::endl; return EXIT_FAILURE; } + // This locates the document and captures a string_view instance, it does + // not validate the document: std::cout << doc; // check if there is more content const char * endofstream;