From 0f515785c6c24b544d1e23af8eef473031e9c8a7 Mon Sep 17 00:00:00 2001 From: John Keiser Date: Thu, 7 Jan 2021 15:20:31 -0800 Subject: [PATCH] Support reading scalars out of order --- .../simdjson/generic/ondemand/json_iterator.h | 1 + .../simdjson/generic/ondemand/logger-inl.h | 22 +- include/simdjson/generic/ondemand/logger.h | 3 + .../generic/ondemand/token_iterator.h | 1 + .../generic/ondemand/value_iterator-inl.h | 227 ++++++++---------- .../generic/ondemand/value_iterator.h | 9 + tests/ondemand/ondemand_dom_api_tests.cpp | 29 ++- tests/ondemand/ondemand_ordering_tests.cpp | 31 ++- 8 files changed, 187 insertions(+), 136 deletions(-) diff --git a/include/simdjson/generic/ondemand/json_iterator.h b/include/simdjson/generic/ondemand/json_iterator.h index 98907ae7..bd528140 100644 --- a/include/simdjson/generic/ondemand/json_iterator.h +++ b/include/simdjson/generic/ondemand/json_iterator.h @@ -177,6 +177,7 @@ protected: friend class parser; friend class value_iterator; friend simdjson_really_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta) noexcept; + friend simdjson_really_inline void logger::log_line(const json_iterator &iter, const uint32_t *index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail) noexcept; }; // json_iterator } // namespace ondemand diff --git a/include/simdjson/generic/ondemand/logger-inl.h b/include/simdjson/generic/ondemand/logger-inl.h index a8f0b20f..d45f2180 100644 --- a/include/simdjson/generic/ondemand/logger-inl.h +++ b/include/simdjson/generic/ondemand/logger-inl.h @@ -24,6 +24,9 @@ simdjson_really_inline void log_event(const json_iterator &iter, const char *typ simdjson_really_inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept { log_line(iter, "", type, detail, delta, depth_delta); } +simdjson_really_inline void log_value(const json_iterator &iter, const uint32_t *index, depth_t depth, const char *type, std::string_view detail) noexcept { + log_line(iter, index, depth, "", type, detail); +} simdjson_really_inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept { log_line(iter, "+", type, "", delta, depth_delta); log_depth++; @@ -35,6 +38,9 @@ simdjson_really_inline void log_end_value(const json_iterator &iter, const char simdjson_really_inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept { log_line(iter, "ERROR: ", error, detail, delta, depth_delta); } +simdjson_really_inline void log_error(const json_iterator &iter, const uint32_t *index, depth_t depth, const char *error, const char *detail) noexcept { + log_line(iter, index, depth, "ERROR: ", error, detail); +} simdjson_really_inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept { log_event(iter.json_iter(), type, detail, delta, depth_delta); @@ -76,8 +82,12 @@ simdjson_really_inline void log_headers() noexcept { } simdjson_really_inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta) noexcept { + log_line(iter, iter.token.index+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail); +} +simdjson_really_inline void log_line(const json_iterator &iter, const uint32_t *index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail) noexcept { if (LOG_ENABLED) { - const int indent = (log_depth+depth_delta)*2; + const int indent = depth*2; + const auto buf = iter.token.buf; printf("| %*s%s%-*s ", indent, "", title_prefix, @@ -86,21 +96,23 @@ simdjson_really_inline void log_line(const json_iterator &iter, const char *titl { // Print the current structural. printf("| "); + auto current_structural = &buf[*index]; for (int i=0;i va return require_raw_json_string().unescape(_json_iter->string_buf_loc()); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_raw_json_string() noexcept { - assert_at_start(); - - logger::log_value(*_json_iter, "string", "", 0); - auto json = _json_iter->peek(); - if (*json != '"') { logger::log_error(*_json_iter, "Not a string"); return INCORRECT_TYPE; } - _json_iter->advance(); - _json_iter->ascend_to(depth()-1); + auto json = peek_scalar(); + if (*json != '"') { return incorrect_type_error("Not a string"); } + advance_scalar("string"); return raw_json_string(json+1); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_raw_json_string() noexcept { - assert_at_start(); - - logger::log_value(*_json_iter, "string", "", 0); - auto json = _json_iter->advance(); - if (*json != '"') { logger::log_error(*_json_iter, "Not a string"); return INCORRECT_TYPE; } - _json_iter->ascend_to(depth()-1); + auto json = advance_scalar("string"); + if (*json != '"') { return incorrect_type_error("Not a string"); } return raw_json_string(json+1); } -simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_uint64() noexcept { - assert_at_non_root_start(); - logger::log_value(*_json_iter, "uint64", "", 0); +simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_uint64() noexcept { uint64_t result; - SIMDJSON_TRY( numberparsing::parse_unsigned(_json_iter->peek()).get(result) ); - _json_iter->advance(); - _json_iter->ascend_to(depth()-1); + SIMDJSON_TRY( numberparsing::parse_unsigned(peek_scalar()).get(result) ); + advance_non_root_scalar("uint64"); return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_uint64() noexcept { - assert_at_non_root_start(); - - logger::log_value(*_json_iter, "uint64", "", 0); - _json_iter->ascend_to(depth()-1); - return numberparsing::parse_unsigned(_json_iter->advance()); + return numberparsing::parse_unsigned(advance_non_root_scalar("uint64")); } -simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_int64() noexcept { - assert_at_non_root_start(); - logger::log_value(*_json_iter, "int64", "", 0); +simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_int64() noexcept { int64_t result; - SIMDJSON_TRY( numberparsing::parse_integer(_json_iter->peek()).get(result) ); - _json_iter->advance(); - _json_iter->ascend_to(depth()-1); + SIMDJSON_TRY( numberparsing::parse_integer(peek_scalar()).get(result) ); + advance_non_root_scalar("int64"); return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_int64() noexcept { - assert_at_non_root_start(); - - logger::log_value(*_json_iter, "int64", "", 0); - _json_iter->ascend_to(depth()-1); - return numberparsing::parse_integer(_json_iter->advance()); + return numberparsing::parse_integer(advance_non_root_scalar("int64")); } -simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_double() noexcept { - assert_at_non_root_start(); - logger::log_value(*_json_iter, "double", "", 0); +simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_double() noexcept { double result; - SIMDJSON_TRY( numberparsing::parse_double(_json_iter->peek()).get(result) ); - _json_iter->advance(); - _json_iter->ascend_to(depth()-1); + SIMDJSON_TRY( numberparsing::parse_double(peek_scalar()).get(result) ); + advance_non_root_scalar("double"); return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_double() noexcept { - assert_at_non_root_start(); - - logger::log_value(*_json_iter, "double", "", 0); - _json_iter->ascend_to(depth()-1); - return numberparsing::parse_double(_json_iter->advance()); + return numberparsing::parse_double(advance_non_root_scalar("double")); } + simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::parse_bool(const uint8_t *json) const noexcept { - logger::log_value(*_json_iter, "bool", ""); auto not_true = atomparsing::str4ncmp(json, "true"); auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e'); bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]); - if (error) { logger::log_error(*_json_iter, "Not a boolean"); return INCORRECT_TYPE; } + if (error) { return incorrect_type_error("Not a boolean"); } return simdjson_result(!not_true); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_bool() noexcept { - assert_at_non_root_start(); - bool result; - SIMDJSON_TRY( parse_bool(_json_iter->peek()).get(result) ); - _json_iter->advance(); - _json_iter->ascend_to(depth()-1); + SIMDJSON_TRY( parse_bool(peek_scalar()).get(result) ); + advance_non_root_scalar("bool"); return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_bool() noexcept { - assert_at_non_root_start(); - - _json_iter->ascend_to(depth()-1); - return parse_bool(_json_iter->advance()); + return parse_bool(advance_non_root_scalar("bool")); } simdjson_really_inline bool value_iterator::is_null(const uint8_t *json) const noexcept { - if (!atomparsing::str4ncmp(json, "null")) { - logger::log_value(*_json_iter, "null", ""); - return true; - } - return false; + return !atomparsing::str4ncmp(json, "null"); } simdjson_really_inline bool value_iterator::is_null() noexcept { - assert_at_non_root_start(); - - if (is_null(_json_iter->peek())) { - _json_iter->advance(); - _json_iter->ascend_to(depth()-1); + if (is_null(peek_scalar())) { + advance_non_root_scalar("null"); return true; } return false; } simdjson_really_inline bool value_iterator::require_null() noexcept { - assert_at_non_root_start(); - - _json_iter->ascend_to(depth()-1); - return is_null(_json_iter->advance()); + return is_null(advance_non_root_scalar("null")); } constexpr const uint32_t MAX_INT_LENGTH = 1024; simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::parse_root_uint64(const uint8_t *json, uint32_t max_len) const noexcept { uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Root number more than 20 characters"); return NUMBER_ERROR; } - logger::log_value(*_json_iter, "uint64", "", 0); - auto result = numberparsing::parse_unsigned(tmpbuf); - if (result.error()) { logger::log_error(*_json_iter, "Error parsing unsigned integer"); } - return result; + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, _start_index, depth(), "Root number more than 20 characters"); return NUMBER_ERROR; } + return numberparsing::parse_unsigned(tmpbuf); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_root_uint64() noexcept { - assert_at_root(); - uint64_t result; - SIMDJSON_TRY( parse_root_uint64(_json_iter->peek(), _json_iter->peek_length()).get(result) ); - _json_iter->advance(); + SIMDJSON_TRY( parse_root_uint64(peek_scalar(), peek_scalar_length()).get(result) ); + advance_root_scalar("uint64"); return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_root_uint64() noexcept { - assert_at_root(); - - auto max_len = _json_iter->peek_length(); - return parse_root_uint64(_json_iter->advance(), max_len); + auto max_len = peek_scalar_length(); + return parse_root_uint64(advance_root_scalar("uint64"), max_len); } + simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::parse_root_int64(const uint8_t *json, uint32_t max_len) const noexcept { uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Root number more than 20 characters"); return NUMBER_ERROR; } - logger::log_value(*_json_iter, "int64", "", 0); - auto result = numberparsing::parse_integer(tmpbuf); - if (result.error()) { logger::log_error(*_json_iter, "Error parsing integer"); } - return result; + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, _start_index, depth(), "Root number more than 20 characters"); return NUMBER_ERROR; } + return numberparsing::parse_integer(tmpbuf); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_root_int64() noexcept { - assert_at_root(); - int64_t result; - SIMDJSON_TRY( parse_root_int64(_json_iter->peek(), _json_iter->peek_length()).get(result) ); - _json_iter->advance(); + SIMDJSON_TRY( parse_root_int64(peek_scalar(), peek_scalar_length()).get(result) ); + advance_root_scalar("int64"); return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_root_int64() noexcept { - assert_at_root(); - - auto max_len = _json_iter->peek_length(); - return parse_root_int64(_json_iter->advance(), max_len); + auto max_len = peek_scalar_length(); + return parse_root_int64(advance_root_scalar("int64"), max_len); } + simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::parse_root_double(const uint8_t *json, uint32_t max_len) const noexcept { // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/, 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest number: -0.e-308. uint8_t tmpbuf[1074+8+1]; - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Root number more than 1082 characters"); return NUMBER_ERROR; } - logger::log_value(*_json_iter, "double", "", 0); - auto result = numberparsing::parse_double(tmpbuf); - if (result.error()) { logger::log_error(*_json_iter, "Error parsing double"); } - return result; + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, _start_index, depth(), "Root number more than 1082 characters"); return NUMBER_ERROR; } + return numberparsing::parse_double(tmpbuf); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_root_double() noexcept { - assert_at_root(); - double result; - SIMDJSON_TRY( parse_root_double(_json_iter->peek(), _json_iter->peek_length()).get(result) ); - _json_iter->advance(); + SIMDJSON_TRY( parse_root_double(peek_scalar(), peek_scalar_length()).get(result) ); + advance_root_scalar("double"); return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_root_double() noexcept { - assert_at_root(); - - auto max_len = _json_iter->peek_length(); - return parse_root_double(_json_iter->advance(), max_len); + auto max_len = peek_scalar_length(); + return parse_root_double(advance_root_scalar("double"), max_len); } + simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::parse_root_bool(const uint8_t *json, uint32_t max_len) const noexcept { uint8_t tmpbuf[5+1]; - if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, "Not a boolean"); return INCORRECT_TYPE; } + if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return incorrect_type_error("Not a boolean"); } return parse_bool(tmpbuf); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_root_bool() noexcept { - assert_at_root(); - bool result; - SIMDJSON_TRY( parse_root_bool(_json_iter->peek(), _json_iter->peek_length()).get(result) ); - _json_iter->advance(); + SIMDJSON_TRY( parse_root_bool(peek_scalar(), peek_scalar_length()).get(result) ); + advance_root_scalar("bool"); return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_root_bool() noexcept { - assert_at_root(); - - auto max_len = _json_iter->peek_length(); - return parse_root_bool(_json_iter->advance(), max_len); + auto max_len = peek_scalar_length(); + return parse_root_bool(advance_root_scalar("bool"), max_len); } simdjson_really_inline bool value_iterator::is_root_null(const uint8_t *json, uint32_t max_len) const noexcept { uint8_t tmpbuf[4+1]; @@ -515,17 +448,13 @@ simdjson_really_inline bool value_iterator::is_root_null(const uint8_t *json, ui return is_null(tmpbuf); } simdjson_really_inline bool value_iterator::is_root_null() noexcept { - assert_at_root(); - - if (!is_root_null(_json_iter->peek(), _json_iter->peek_length())) { return false; } - _json_iter->advance(); + if (!is_root_null(peek_scalar(), peek_scalar_length())) { return false; } + advance_root_scalar("null"); return true; } simdjson_really_inline bool value_iterator::require_root_null() noexcept { - assert_at_root(); - - auto max_len = _json_iter->peek_length(); - return is_root_null(_json_iter->advance(), max_len); + auto max_len = peek_scalar_length(); + return is_root_null(advance_root_scalar("null"), max_len); } simdjson_warn_unused simdjson_really_inline error_code value_iterator::skip_child() noexcept { @@ -577,6 +506,50 @@ simdjson_warn_unused simdjson_really_inline json_iterator &value_iterator::json_ return *_json_iter; } +simdjson_really_inline const uint8_t *value_iterator::peek_scalar() const noexcept { + return &_json_iter->token.buf[*_start_index]; +} +simdjson_really_inline uint32_t value_iterator::peek_scalar_length() const noexcept { + return *(_start_index+1) - *_start_index; +} + +simdjson_really_inline const uint8_t *value_iterator::advance_scalar(const char *type) const noexcept { + logger::log_value(*_json_iter, _start_index, depth(), type); + if (!is_at_start()) { return peek_scalar(); } + + assert_at_start(); + auto result = _json_iter->advance(); + _json_iter->ascend_to(depth()-1); + return result; +} +simdjson_really_inline const uint8_t *value_iterator::advance_root_scalar(const char *type) const noexcept { + logger::log_value(*_json_iter, _start_index, depth(), type); + if (is_at_start()) { return peek_scalar(); } + + assert_at_root(); + auto result = _json_iter->advance(); + _json_iter->ascend_to(depth()-1); + return result; +} +simdjson_really_inline const uint8_t *value_iterator::advance_non_root_scalar(const char *type) const noexcept { + logger::log_value(*_json_iter, _start_index, depth(), type); + if (is_at_start()) { return peek_scalar(); } + + assert_at_non_root_start(); + auto result = _json_iter->advance(); + _json_iter->ascend_to(depth()-1); + return result; +} + +simdjson_really_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept { + logger::log_error(*_json_iter, _start_index, depth(), message); + return INCORRECT_TYPE; +} + +simdjson_really_inline bool value_iterator::is_at_start() const noexcept { + return _json_iter->token.index == _start_index; +} + simdjson_really_inline void value_iterator::assert_at_start() const noexcept { SIMDJSON_ASSUME( _json_iter->token.index == _start_index ); SIMDJSON_ASSUME( _json_iter->_depth == _depth ); diff --git a/include/simdjson/generic/ondemand/value_iterator.h b/include/simdjson/generic/ondemand/value_iterator.h index 2ff0b339..c6021963 100644 --- a/include/simdjson/generic/ondemand/value_iterator.h +++ b/include/simdjson/generic/ondemand/value_iterator.h @@ -292,6 +292,15 @@ protected: simdjson_really_inline simdjson_result parse_root_int64(const uint8_t *json, uint32_t max_len) const noexcept; simdjson_really_inline simdjson_result parse_root_double(const uint8_t *json, uint32_t max_len) const noexcept; + simdjson_really_inline const uint8_t *peek_scalar() const noexcept; + simdjson_really_inline uint32_t peek_scalar_length() const noexcept; + simdjson_really_inline const uint8_t *advance_scalar(const char *type) const noexcept; + simdjson_really_inline const uint8_t *advance_root_scalar(const char *type) const noexcept; + simdjson_really_inline const uint8_t *advance_non_root_scalar(const char *type) const noexcept; + + simdjson_really_inline error_code incorrect_type_error(const char *message) const noexcept; + + simdjson_really_inline bool is_at_start() const noexcept; simdjson_really_inline void assert_at_start() const noexcept; simdjson_really_inline void assert_at_root() const noexcept; simdjson_really_inline void assert_at_child() const noexcept; diff --git a/tests/ondemand/ondemand_dom_api_tests.cpp b/tests/ondemand/ondemand_dom_api_tests.cpp index b16e4380..7d440c09 100644 --- a/tests/ondemand/ondemand_dom_api_tests.cpp +++ b/tests/ondemand/ondemand_dom_api_tests.cpp @@ -664,18 +664,28 @@ namespace dom_api_tests { } template - bool test_scalar_value(const padded_string &json, const T &expected) { + bool test_scalar_value(const padded_string &json, const T &expected, bool test_twice=true) { std::cout << "- JSON: " << json << endl; SUBTEST( "simdjson_result", test_ondemand_doc(json, [&](auto doc_result) { T actual; ASSERT_SUCCESS( doc_result.get(actual) ); ASSERT_EQUAL( expected, actual ); + // Test it twice (scalars can be retrieved more than once) + if (test_twice) { + ASSERT_SUCCESS( doc_result.get(actual) ); + ASSERT_EQUAL( expected, actual ); + } return true; })); SUBTEST( "document", test_ondemand_doc(json, [&](auto doc_result) { T actual; ASSERT_SUCCESS( doc_result.get(actual) ); ASSERT_EQUAL( expected, actual ); + // Test it twice (scalars can be retrieved more than once) + if (test_twice) { + ASSERT_SUCCESS( doc_result.get(actual) ); + ASSERT_EQUAL( expected, actual ); + } return true; })); padded_string array_json = std::string("[") + std::string(json) + "]"; @@ -686,6 +696,11 @@ namespace dom_api_tests { T actual; ASSERT_SUCCESS( val_result.get(actual) ); ASSERT_EQUAL(expected, actual); + // Test it twice (scalars can be retrieved more than once) + if (test_twice) { + ASSERT_SUCCESS( val_result.get(actual) ); + ASSERT_EQUAL(expected, actual); + } count++; } ASSERT_EQUAL(count, 1); @@ -699,6 +714,11 @@ namespace dom_api_tests { T actual; ASSERT_SUCCESS( val.get(actual) ); ASSERT_EQUAL(expected, actual); + // Test it twice (scalars can be retrieved more than once) + if (test_twice) { + ASSERT_SUCCESS( val.get(actual) ); + ASSERT_EQUAL(expected, actual); + } count++; } ASSERT_EQUAL(count, 1); @@ -706,9 +726,14 @@ namespace dom_api_tests { })); TEST_SUCCEED(); } + bool string_value() { TEST_START(); - return test_scalar_value(R"("hi")"_padded, std::string_view("hi")); + // We can't retrieve a small string twice because it will blow out the string buffer + if (!test_scalar_value(R"("hi")"_padded, std::string_view("hi"), false)) { return false; } + // ... unless the document is big enough to have a big string buffer :) + if (!test_scalar_value(R"("hi" )"_padded, std::string_view("hi"))) { return false; } + TEST_SUCCEED(); } bool numeric_values() { diff --git a/tests/ondemand/ondemand_ordering_tests.cpp b/tests/ondemand/ondemand_ordering_tests.cpp index b4291f2a..905fffa2 100644 --- a/tests/ondemand/ondemand_ordering_tests.cpp +++ b/tests/ondemand/ondemand_ordering_tests.cpp @@ -108,8 +108,8 @@ namespace ordering_tests { double x{0}; double y{0}; double z{0}; - for (ondemand::object point_object : doc["coordinates"]) { - for (auto field : point_object) { + for (auto point_object : doc["coordinates"]) { + for (auto field : point_object.get_object()) { if (field.key() == "z") { z += double(field.value()); } else if (field.key() == "x") { x += double(field.value()); } else if (field.key() == "y") { y += double(field.value()); } @@ -117,6 +117,31 @@ namespace ordering_tests { } return (x == 1.1) && (y == 2.2) && (z == 3.3); } + + bool use_values_out_of_order_after_array() { + TEST_START(); + ondemand::parser parser{}; + auto doc = parser.iterate(json); + simdjson_result x{}, y{}, z{}; + for (auto point_object : doc["coordinates"]) { + x = point_object["x"]; + y = point_object["y"]; + z = point_object["z"]; + } + return (double(x) == 1.1) && (double(z) == 3.3) && (double(y) == 2.2); + } + + bool use_object_multiple_times_out_of_order() { + TEST_START(); + ondemand::parser parser{}; + auto json2 = "{\"coordinates\":{\"x\":1.1,\"y\":2.2,\"z\":3.3}}"_padded; + auto doc = parser.iterate(json2); + auto x = doc["coordinates"]["x"]; + auto y = doc["coordinates"]["y"]; + auto z = doc["coordinates"]["z"]; + return (double(x) == 1.1) && (double(z) == 3.3) && (double(y) == 2.2); + } + #endif // SIMDJSON_EXCEPTIONS bool run() { @@ -129,6 +154,8 @@ namespace ordering_tests { out_of_order_object_find_field_unordered() && out_of_order_object_find_field() && foreach_object_field_lookup() && + use_values_out_of_order_after_array() && + use_object_multiple_times_out_of_order() && #endif // SIMDJSON_EXCEPTIONS true; }