diff --git a/doc/basics.md b/doc/basics.md index 16162b8e..7c69053b 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -871,6 +871,30 @@ bool parse() { ``` +The following examples illustrates how to iterate through the content of an object without +having to handle exceptions. +```c++ + auto json = R"({"k\u0065y": 1})"_padded; + ondemand::parser parser; + ondemand::document doc; + auto error = parser.iterate(json).get(doc); + if(error) { return false; } + ondemand::object object; + error = doc.get_object().get(object); + if(error) { return false; } + for(auto field : object) { + ondemand::raw_json_string keyv; + error = field.key().get(keyv); + if(error) { return false; } + if(keyv == "key") { + uint64_t intvalue; + error = field.value().get(intvalue); + if(error) { return false; } + std::cout << intvalue; + } + } +``` + ### Disabling Exceptions The simdjson can be build with exceptions entirely disabled. It checks the `__cpp_exceptions` macro at compile time. Even if exceptions are enabled in your compiler, you may still disable exceptions specifically for simdjson, by setting `SIMDJSON_EXCEPTIONS` to `0` (false) at compile-time when building the simdjson library. If you are building with CMake, to ensure you don't write any code that uses exceptions, you compile with `SIMDJSON_EXCEPTIONS=OFF`. For example, if including the project via cmake: diff --git a/include/simdjson/generic/implementation_simdjson_result_base.h b/include/simdjson/generic/implementation_simdjson_result_base.h index d4b6c87f..e14ae461 100644 --- a/include/simdjson/generic/implementation_simdjson_result_base.h +++ b/include/simdjson/generic/implementation_simdjson_result_base.h @@ -115,9 +115,10 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_really_inline T&& value_unsafe() && noexcept; - - T first{}; - error_code second{UNINITIALIZED}; +protected: + /** users should never directly access first and second. **/ + T first{}; /** Users should never directly access 'first'. **/ + error_code second{UNINITIALIZED}; /** Users should never directly access 'second'. **/ }; // struct implementation_simdjson_result_base } // namespace SIMDJSON_IMPLEMENTATION diff --git a/tests/ondemand/compilation_failure_tests/CMakeLists.txt b/tests/ondemand/compilation_failure_tests/CMakeLists.txt index c766be0a..9ee474bd 100644 --- a/tests/ondemand/compilation_failure_tests/CMakeLists.txt +++ b/tests/ondemand/compilation_failure_tests/CMakeLists.txt @@ -17,3 +17,4 @@ endfunction(add_dual_compile_test) add_dual_compile_test(iterate_char_star) add_dual_compile_test(iterate_string_view) add_dual_compile_test(iterate_temporary_buffer) +add_dual_compile_test(first_second_access) diff --git a/tests/ondemand/compilation_failure_tests/first_second_access.cpp b/tests/ondemand/compilation_failure_tests/first_second_access.cpp new file mode 100644 index 00000000..b5cde477 --- /dev/null +++ b/tests/ondemand/compilation_failure_tests/first_second_access.cpp @@ -0,0 +1,28 @@ + +#include +#include "simdjson.h" + +using namespace simdjson; + +int main() { + auto json = "1"_padded; + ondemand::parser parser; + ondemand::document doc; + auto error = parser.iterate(json).get(doc); + if(error) { return EXIT_FAILURE; } + simdjson_result query = doc.at_pointer("/"); +#if COMPILATION_TEST_USE_FAILING_CODE + if(query.second == simdjson::SUCCESS) { + std::cout << "success" << std::endl; + std::cout << query.first << std::endl; + } +#else + ondemand::value val; + error = query.get(val); + if(error == simdjson::SUCCESS) { + std::cout << "success" << std::endl; + std::cout << val << std::endl; + } +#endif + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/tests/ondemand/ondemand_array_tests.cpp b/tests/ondemand/ondemand_array_tests.cpp index e4c4bedc..698d76cb 100644 --- a/tests/ondemand/ondemand_array_tests.cpp +++ b/tests/ondemand/ondemand_array_tests.cpp @@ -416,9 +416,10 @@ namespace array_tests { } // Break after using first value in child object case 3: { - for (auto [ child_field, error ] : value.get_object()) { - ASSERT_SUCCESS(error); - ASSERT_EQUAL(child_field.key(), "x"); + for (auto child_field : value.get_object()) { + ondemand::raw_json_string k; + ASSERT_SUCCESS( child_field.key().get(k) ); + ASSERT_EQUAL(k, "x"); uint64_t x; ASSERT_SUCCESS( child_field.value().get(x) ); ASSERT_EQUAL(x, 3); @@ -430,9 +431,10 @@ namespace array_tests { // Break without using first value in child object case 4: { - for (auto [ child_field, error ] : value.get_object()) { - ASSERT_SUCCESS(error); - ASSERT_EQUAL(child_field.key(), "x"); + for (auto child_field : value.get_object()) { + ondemand::raw_json_string k; + ASSERT_SUCCESS( child_field.key().get(k) ); + ASSERT_EQUAL(k, "x"); break; } std::cout << " - After reaching (but not using) first value in child object ..." << std::endl; @@ -457,8 +459,7 @@ namespace array_tests { // Break after first value in child array case 7: { - for (auto [ child_value, error ] : value) { - ASSERT_SUCCESS(error); + for (auto child_value : value) { uint64_t x; ASSERT_SUCCESS( child_value.get(x) ); ASSERT_EQUAL( x, 7 ); diff --git a/tests/ondemand/ondemand_object_error_tests.cpp b/tests/ondemand/ondemand_object_error_tests.cpp index 1059e035..0b2c3cb6 100644 --- a/tests/ondemand/ondemand_object_error_tests.cpp +++ b/tests/ondemand/ondemand_object_error_tests.cpp @@ -17,7 +17,7 @@ namespace object_error_tests { ASSERT_ERROR(actual_error, expected_error[count - N]); } else { ASSERT_SUCCESS(actual_error); - ASSERT_EQUAL(field.key().first, expected_key[count]); + ASSERT_EQUAL(field.key().value_unsafe(), expected_key[count]); ASSERT_EQUAL(actual, expected[count]); } count++; diff --git a/tests/ondemand/ondemand_object_tests.cpp b/tests/ondemand/ondemand_object_tests.cpp index c8e87a0b..25bb98f4 100644 --- a/tests/ondemand/ondemand_object_tests.cpp +++ b/tests/ondemand/ondemand_object_tests.cpp @@ -203,9 +203,9 @@ namespace object_tests { ASSERT_RESULT( doc_result.type(), json_type::object ); ASSERT_SUCCESS( doc_result.get(object) ); size_t i = 0; - for (auto [ field, error ] : object) { - ASSERT_SUCCESS(error); - ASSERT_EQUAL( field.key(), expected_key[i]); + for (auto field : object) { + ASSERT_SUCCESS( field.key().error() ); + ASSERT_EQUAL( field.key().value_unsafe(), expected_key[i]); ASSERT_EQUAL( field.value().get_uint64().value_unsafe(), expected_value[i] ); i++; } @@ -217,9 +217,9 @@ namespace object_tests { ASSERT_RESULT( doc_result.type(), json_type::object ); ASSERT_SUCCESS( doc_result.get(object) ); size_t i = 0; - for (auto [ field, error ] : object) { - ASSERT_SUCCESS(error); - ASSERT_EQUAL( field.key(), expected_key[i]); + for (auto field : object) { + ASSERT_SUCCESS( field.error() ); + ASSERT_EQUAL( field.key().value_unsafe(), expected_key[i]); ASSERT_EQUAL( field.value().get_uint64().value_unsafe(), expected_value[i] ); i++; } @@ -228,9 +228,9 @@ namespace object_tests { ASSERT_RESULT( doc_result.type(), json_type::object ); ASSERT_SUCCESS( doc_result.get(object) ); i = 0; - for (auto [ field, error ] : object) { - ASSERT_SUCCESS(error); - ASSERT_EQUAL( field.key(), expected_key[i]); + for (auto field : object) { + ASSERT_SUCCESS( field.error() ); + ASSERT_EQUAL( field.key().value_unsafe(), expected_key[i]); ASSERT_EQUAL( field.value().get_uint64().value_unsafe(), expected_value[i] ); i++; } @@ -240,9 +240,9 @@ namespace object_tests { SUBTEST("simdjson_result", test_ondemand_doc(json, [&](auto doc_result) { simdjson_result object_result = doc_result.get_object(); size_t i = 0; - for (auto [ field, error ] : object_result) { - ASSERT_SUCCESS(error); - ASSERT_EQUAL( field.key(), expected_key[i] ); + for (auto field : object_result) { + ASSERT_SUCCESS( field.error() ); + ASSERT_EQUAL( field.key().value_unsafe(), expected_key[i]); ASSERT_EQUAL( field.value().get_uint64().value_unsafe(), expected_value[i] ); i++; } @@ -297,9 +297,9 @@ namespace object_tests { case 3: { ASSERT_EQUAL(key, "object_break"); - for (auto [ child_field, error ] : field.value().get_object()) { - ASSERT_SUCCESS(error); - ASSERT_EQUAL(child_field.key(), "x"); + for (auto child_field : field.value().get_object()) { + ASSERT_SUCCESS( child_field.error() ); + ASSERT_EQUAL(child_field.key().value_unsafe(), "x"); uint64_t x; ASSERT_SUCCESS( child_field.value().get(x) ); ASSERT_EQUAL(x, 3); @@ -313,9 +313,9 @@ namespace object_tests { case 4: { ASSERT_EQUAL(key, "object_break_unused"); - for (auto [ child_field, error ] : field.value().get_object()) { - ASSERT_SUCCESS(error); - ASSERT_EQUAL(child_field.key(), "x"); + for (auto child_field : field.value().get_object()) { + ASSERT_SUCCESS(child_field.error()); + ASSERT_EQUAL(child_field.key().value_unsafe(), "x"); break; } std::cout << " - After reaching (but not using) first value in child object ..." << std::endl; @@ -576,17 +576,15 @@ namespace object_tests { ASSERT_RESULT( doc_result.type(), json_type::object ); ASSERT_SUCCESS( doc_result.get(object) ); size_t i = 0; - for (auto [ field, error ] : object) { + for (auto field : object) { (void)field; - (void)error; i++; } ASSERT_EQUAL( i, 0 ); doc_result.rewind(); i = 0; - for (auto [ field, error ] : object) { + for (auto field : object) { (void)field; - (void)error; i++; } ASSERT_EQUAL( i, 0 ); diff --git a/tests/ondemand/ondemand_readme_examples.cpp b/tests/ondemand/ondemand_readme_examples.cpp index c99a741c..52cac5e3 100644 --- a/tests/ondemand/ondemand_readme_examples.cpp +++ b/tests/ondemand/ondemand_readme_examples.cpp @@ -345,6 +345,59 @@ int using_the_parsed_json_6_process() { return EXIT_SUCCESS; } + +bool exception_free_object_loop() { + auto json = R"({"k\u0065y": 1})"_padded; + ondemand::parser parser; + ondemand::document doc; + auto error = parser.iterate(json).get(doc); + if(error) { return false; } + ondemand::object object; + error = doc.get_object().get(object); + if(error) { return false; } + for(auto field : object) { + std::string_view keyv; + error = field.unescaped_key().get(keyv); + if(error) { return false; } + if(keyv == "key") { + uint64_t intvalue; + error = field.value().get(intvalue); + if(error) { return false; } + std::cout << intvalue; + } + } + return true; +} + + +bool exception_free_object_loop_no_escape() { + auto json = R"({"k\u0065y": 1})"_padded; + ondemand::parser parser; + ondemand::document doc; + auto error = parser.iterate(json).get(doc); + if(error) { return false; } + ondemand::object object; + error = doc.get_object().get(object); + if(error) { return false; } + for(auto field : object) { + ondemand::raw_json_string keyv; + error = field.key().get(keyv); + /** + * If you need to escape the keys, you can do + * std::string_view keyv; + * error = field.unescaped_key().get(keyv); + */ + if(error) { return false; } + if(keyv == "key") { + uint64_t intvalue; + error = field.value().get(intvalue); + if(error) { return false; } + std::cout << intvalue; + } + } + return true; +} + bool using_the_parsed_json_6() { TEST_START(); ASSERT_EQUAL(using_the_parsed_json_6_process(), EXIT_SUCCESS);