Guarding first/second access. (#1688)

* Guarding first/second access.

* Correcting our own usage.

* Adding more documentation.
This commit is contained in:
Daniel Lemire 2021-08-06 20:25:05 -04:00 committed by GitHub
parent 06643fc9f5
commit 19902abaf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 140 additions and 34 deletions

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1,28 @@
#include <iostream>
#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<ondemand::value> 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;
}

View File

@ -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 );

View File

@ -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++;

View File

@ -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<ondemand::object>", test_ondemand_doc(json, [&](auto doc_result) {
simdjson_result<ondemand::object> 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 );

View File

@ -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);