From 73c7b7db3da10dfd7dcaee6f1658231c2a227b6f Mon Sep 17 00:00:00 2001 From: John Keiser Date: Fri, 11 Dec 2020 11:55:32 -0800 Subject: [PATCH] Safety: check index of scalar values before use --- .../simdjson/generic/ondemand/document-inl.h | 13 +- include/simdjson/generic/ondemand/document.h | 2 +- .../generic/ondemand/json_iterator-inl.h | 6 +- .../simdjson/generic/ondemand/json_iterator.h | 4 +- .../generic/ondemand/token_iterator-inl.h | 4 + .../generic/ondemand/token_iterator.h | 6 + .../generic/ondemand/value_iterator-inl.h | 118 ++++++++++-------- .../generic/ondemand/value_iterator.h | 10 +- 8 files changed, 98 insertions(+), 65 deletions(-) diff --git a/include/simdjson/generic/ondemand/document-inl.h b/include/simdjson/generic/ondemand/document-inl.h index 50fdf1881..4972123df 100644 --- a/include/simdjson/generic/ondemand/document-inl.h +++ b/include/simdjson/generic/ondemand/document-inl.h @@ -8,8 +8,8 @@ simdjson_really_inline document::document(ondemand::json_iterator &&_iter) noexc logger::log_start_value(iter, "document"); } -simdjson_really_inline void document::assert_at_start() const noexcept { - iter.assert_at_start(); +simdjson_really_inline void document::assert_at_root() const noexcept { + iter.assert_at_root(); } simdjson_really_inline document document::start(json_iterator &&iter) noexcept { return document(std::forward(iter)); @@ -19,8 +19,8 @@ simdjson_really_inline value document::as_value() noexcept { return as_value_iterator(); } simdjson_really_inline value_iterator document::as_value_iterator() noexcept { - assert_at_start(); - return value_iterator(&iter, 1); + assert_at_root(); + return value_iterator(&iter, 1, iter.token.checkpoint()); } simdjson_really_inline simdjson_result document::get_array() & noexcept { @@ -30,15 +30,12 @@ simdjson_really_inline simdjson_result document::get_object() & noexcept return as_value().get_object(); } simdjson_really_inline simdjson_result document::get_uint64() noexcept { - assert_at_start(); return as_value_iterator().require_root_uint64(); } simdjson_really_inline simdjson_result document::get_int64() noexcept { - assert_at_start(); return as_value_iterator().require_root_int64(); } simdjson_really_inline simdjson_result document::get_double() noexcept { - assert_at_start(); return as_value_iterator().require_root_double(); } simdjson_really_inline simdjson_result document::get_string() & noexcept { @@ -48,11 +45,9 @@ simdjson_really_inline simdjson_result document::get_raw_json_s return as_value().get_raw_json_string(); } simdjson_really_inline simdjson_result document::get_bool() noexcept { - assert_at_start(); return as_value_iterator().require_root_bool(); } simdjson_really_inline bool document::is_null() noexcept { - assert_at_start(); return as_value_iterator().is_root_null(); } diff --git a/include/simdjson/generic/ondemand/document.h b/include/simdjson/generic/ondemand/document.h index cc1e6e863..44847c1a1 100644 --- a/include/simdjson/generic/ondemand/document.h +++ b/include/simdjson/generic/ondemand/document.h @@ -232,7 +232,7 @@ protected: simdjson_really_inline value_iterator as_value_iterator() noexcept; static simdjson_really_inline document start(ondemand::json_iterator &&iter) noexcept; - simdjson_really_inline void assert_at_start() const noexcept; + simdjson_really_inline void assert_at_root() const noexcept; // // Fields diff --git a/include/simdjson/generic/ondemand/json_iterator-inl.h b/include/simdjson/generic/ondemand/json_iterator-inl.h index 761c333c4..49bac01db 100644 --- a/include/simdjson/generic/ondemand/json_iterator-inl.h +++ b/include/simdjson/generic/ondemand/json_iterator-inl.h @@ -90,11 +90,11 @@ simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child return report_error(TAPE_ERROR, "not enough close braces"); } -simdjson_really_inline bool json_iterator::at_start() const noexcept { - return token.index == &parser->dom_parser.structural_indexes[0]; +simdjson_really_inline bool json_iterator::at_root() const noexcept { + return token.index == parser->dom_parser.structural_indexes.get(); } -simdjson_really_inline void json_iterator::assert_at_start() const noexcept { +simdjson_really_inline void json_iterator::assert_at_root() const noexcept { SIMDJSON_ASSUME( _depth == 1 ); // Visual Studio Clang treats unique_ptr.get() as "side effecting." #ifndef SIMDJSON_CLANG_VISUAL_STUDIO diff --git a/include/simdjson/generic/ondemand/json_iterator.h b/include/simdjson/generic/ondemand/json_iterator.h index 1d107e12c..9be042676 100644 --- a/include/simdjson/generic/ondemand/json_iterator.h +++ b/include/simdjson/generic/ondemand/json_iterator.h @@ -60,12 +60,12 @@ public: /** * Tell whether the iterator is still at the start */ - simdjson_really_inline bool at_start() const noexcept; + simdjson_really_inline bool at_root() const noexcept; /** * Assert if the iterator is not at the start */ - simdjson_really_inline void assert_at_start() const noexcept; + simdjson_really_inline void assert_at_root() const noexcept; /** * Tell whether the iterator is at the EOF mark diff --git a/include/simdjson/generic/ondemand/token_iterator-inl.h b/include/simdjson/generic/ondemand/token_iterator-inl.h index ea71af21f..c16d324ea 100644 --- a/include/simdjson/generic/ondemand/token_iterator-inl.h +++ b/include/simdjson/generic/ondemand/token_iterator-inl.h @@ -39,6 +39,10 @@ simdjson_really_inline bool token_iterator::operator<=(const token_iterator &oth return index <= other.index; } +simdjson_really_inline const uint32_t *token_iterator::checkpoint() const noexcept { + return index; +} + } // namespace ondemand } // namespace SIMDJSON_IMPLEMENTATION } // namespace simdjson diff --git a/include/simdjson/generic/ondemand/token_iterator.h b/include/simdjson/generic/ondemand/token_iterator.h index ac72c7120..286d3d7d6 100644 --- a/include/simdjson/generic/ondemand/token_iterator.h +++ b/include/simdjson/generic/ondemand/token_iterator.h @@ -49,6 +49,11 @@ public: */ simdjson_really_inline const uint8_t *advance() noexcept; + /** + * Save the current index to be restored later. + */ + simdjson_really_inline const uint32_t *checkpoint() const noexcept; + // NOTE: we don't support a full C++ iterator interface, because we expect people to make // different calls to advance the iterator based on *their own* state. @@ -77,6 +82,7 @@ protected: const uint32_t *index{}; friend class json_iterator; + 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; }; diff --git a/include/simdjson/generic/ondemand/value_iterator-inl.h b/include/simdjson/generic/ondemand/value_iterator-inl.h index c301420d2..0c0258745 100644 --- a/include/simdjson/generic/ondemand/value_iterator-inl.h +++ b/include/simdjson/generic/ondemand/value_iterator-inl.h @@ -2,20 +2,21 @@ namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand { -simdjson_really_inline value_iterator::value_iterator(json_iterator *json_iter, depth_t depth) noexcept +simdjson_really_inline value_iterator::value_iterator(json_iterator *json_iter, depth_t depth, const uint32_t *start_index) noexcept : _json_iter{json_iter}, - _depth{depth} + _depth{depth}, + _start_index{start_index} { } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::start_object() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); + assert_at_start(); if (*_json_iter->advance() != '{') { logger::log_error(*_json_iter, "Not an object"); return INCORRECT_TYPE; } return started_object(); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_start_object() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); + assert_at_start(); if (*_json_iter->peek() != '{') { logger::log_error(*_json_iter, "Not an object"); return INCORRECT_TYPE; } _json_iter->advance(); @@ -23,8 +24,6 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator } simdjson_warn_unused simdjson_really_inline bool value_iterator::started_object() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); - if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->advance(); @@ -37,7 +36,7 @@ simdjson_warn_unused simdjson_really_inline bool value_iterator::started_object( } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::has_next_field() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth ); + assert_at_next(); switch (*_json_iter->advance()) { case '}': @@ -54,7 +53,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::find_field_raw(const char *key) noexcept { // We assume we are sitting at a key: at "key": - SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 ); + assert_at_child(); bool has_next; do { @@ -81,7 +80,8 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::field_key() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 ); + logger::log_event(*this, "hi"); + assert_at_child(); const uint8_t *key = _json_iter->advance(); if (*(key++) != '"') { return _json_iter->report_error(TAPE_ERROR, "Object key is not a string"); } @@ -89,21 +89,21 @@ simdjson_warn_unused simdjson_really_inline simdjson_result val } simdjson_warn_unused simdjson_really_inline error_code value_iterator::field_value() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 ); + assert_at_child(); if (*_json_iter->advance() != ':') { return _json_iter->report_error(TAPE_ERROR, "Missing colon in object field"); } return SUCCESS; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::start_array() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0); + assert_at_start(); if (*_json_iter->advance() != '[') { logger::log_error(*_json_iter, "Not an array"); return INCORRECT_TYPE; } return started_array(); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_start_array() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0); + assert_at_start(); if (*_json_iter->peek() != '[') { logger::log_error(*_json_iter, "Not an array"); return INCORRECT_TYPE; } _json_iter->advance(); @@ -111,8 +111,6 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator } simdjson_warn_unused simdjson_really_inline bool value_iterator::started_array() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); - if (*_json_iter->peek() == ']') { logger::log_value(*_json_iter, "empty array"); _json_iter->advance(); @@ -125,7 +123,7 @@ simdjson_warn_unused simdjson_really_inline bool value_iterator::started_array() } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::has_next_element() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth ); + assert_at_next(); switch (*_json_iter->advance()) { case ']': @@ -147,7 +145,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result 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 { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); + assert_at_start(); logger::log_value(*_json_iter, "string", "", 0); auto json = _json_iter->peek(); @@ -157,7 +155,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result val return raw_json_string(json+1); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_raw_json_string() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 0 ); + assert_at_start(); logger::log_value(*_json_iter, "string", "", 0); auto json = _json_iter->advance(); @@ -166,7 +164,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result val return raw_json_string(json+1); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_uint64() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + assert_at_non_root_start(); logger::log_value(*_json_iter, "uint64", "", 0); uint64_t result; @@ -176,14 +174,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iter return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_uint64() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + 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()); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_int64() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + assert_at_non_root_start(); logger::log_value(*_json_iter, "int64", "", 0); int64_t result; @@ -193,14 +191,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_itera return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_int64() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + 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()); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_double() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + assert_at_non_root_start(); logger::log_value(*_json_iter, "double", "", 0); double result; @@ -210,7 +208,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterat return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_double() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + assert_at_non_root_start(); logger::log_value(*_json_iter, "double", "", 0); _json_iter->ascend_to(depth()-1); @@ -225,7 +223,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator return simdjson_result(!not_true); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_bool() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + assert_at_non_root_start(); bool result; SIMDJSON_TRY( parse_bool(_json_iter->peek()).get(result) ); @@ -234,7 +232,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_bool() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + assert_at_non_root_start(); _json_iter->ascend_to(depth()-1); return parse_bool(_json_iter->advance()); @@ -247,7 +245,7 @@ simdjson_really_inline bool value_iterator::is_null(const uint8_t *json) const n return false; } simdjson_really_inline bool value_iterator::is_null() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + assert_at_non_root_start(); if (is_null(_json_iter->peek())) { _json_iter->advance(); @@ -257,7 +255,7 @@ simdjson_really_inline bool value_iterator::is_null() noexcept { return false; } simdjson_really_inline bool value_iterator::require_null() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth > 1 ); + assert_at_non_root_start(); _json_iter->ascend_to(depth()-1); return is_null(_json_iter->advance()); @@ -266,8 +264,6 @@ simdjson_really_inline bool value_iterator::require_null() noexcept { 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 { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); - 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); @@ -276,7 +272,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iter return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_root_uint64() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); uint64_t result; SIMDJSON_TRY( parse_root_uint64(_json_iter->peek(), _json_iter->peek_length()).get(result) ); @@ -284,14 +280,12 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iter return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_root_uint64() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); auto max_len = _json_iter->peek_length(); return parse_root_uint64(_json_iter->advance(), 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 { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); - 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); @@ -300,7 +294,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_itera return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_root_int64() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); int64_t result; SIMDJSON_TRY( parse_root_int64(_json_iter->peek(), _json_iter->peek_length()).get(result) ); @@ -308,14 +302,12 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_itera return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_root_int64() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); auto max_len = _json_iter->peek_length(); return parse_root_int64(_json_iter->advance(), 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 { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); - // 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; } @@ -325,7 +317,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterat return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_root_double() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); double result; SIMDJSON_TRY( parse_root_double(_json_iter->peek(), _json_iter->peek_length()).get(result) ); @@ -333,20 +325,18 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterat return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_root_double() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); auto max_len = _json_iter->peek_length(); return parse_root_double(_json_iter->advance(), 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 { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); - 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; } return parse_bool(tmpbuf); } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::try_get_root_bool() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); bool result; SIMDJSON_TRY( parse_root_bool(_json_iter->peek(), _json_iter->peek_length()).get(result) ); @@ -354,38 +344,39 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator return result; } simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator::require_root_bool() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); auto max_len = _json_iter->peek_length(); return parse_root_bool(_json_iter->advance(), max_len); } simdjson_really_inline bool value_iterator::is_root_null(const uint8_t *json, uint32_t max_len) const noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); - uint8_t tmpbuf[4+1]; if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return false; } return is_null(tmpbuf); } simdjson_really_inline bool value_iterator::is_root_null() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); if (!is_root_null(_json_iter->peek(), _json_iter->peek_length())) { return false; } _json_iter->advance(); return true; } simdjson_really_inline bool value_iterator::require_root_null() noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth && _depth == 1 ); + assert_at_root(); auto max_len = _json_iter->peek_length(); return is_root_null(_json_iter->advance(), max_len); } simdjson_warn_unused simdjson_really_inline error_code value_iterator::skip_child() noexcept { + SIMDJSON_ASSUME( _json_iter->token.index > _start_index ); + SIMDJSON_ASSUME( _json_iter->_depth >= _depth ); + return _json_iter->skip_child(depth()); } simdjson_really_inline value_iterator value_iterator::child() const noexcept { - SIMDJSON_ASSUME( _json_iter->_depth == _depth+1 ); - return { _json_iter, depth()+1 }; + assert_at_child(); + return { _json_iter, depth()+1, _json_iter->token.checkpoint() }; } simdjson_really_inline bool value_iterator::is_open() const noexcept { @@ -413,6 +404,35 @@ simdjson_warn_unused simdjson_really_inline json_iterator &value_iterator::json_ return *_json_iter; } +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 ); + SIMDJSON_ASSUME( _depth > 0 ); +} + +simdjson_really_inline void value_iterator::assert_at_next() const noexcept { + SIMDJSON_ASSUME( _json_iter->token.index > _start_index ); + SIMDJSON_ASSUME( _json_iter->_depth == _depth ); + SIMDJSON_ASSUME( _depth > 0 ); +} + +simdjson_really_inline void value_iterator::assert_at_child() const noexcept { + SIMDJSON_ASSUME( _json_iter->token.index > _start_index ); + SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 ); + SIMDJSON_ASSUME( _depth > 0 ); +} + +simdjson_really_inline void value_iterator::assert_at_root() const noexcept { + assert_at_start(); + SIMDJSON_ASSUME( _depth == 1 ); +} + +simdjson_really_inline void value_iterator::assert_at_non_root_start() const noexcept { + assert_at_start(); + SIMDJSON_ASSUME( _depth > 1 ); +} + + } // namespace ondemand } // namespace SIMDJSON_IMPLEMENTATION } // namespace simdjson diff --git a/include/simdjson/generic/ondemand/value_iterator.h b/include/simdjson/generic/ondemand/value_iterator.h index 1e48724d4..066bfd877 100644 --- a/include/simdjson/generic/ondemand/value_iterator.h +++ b/include/simdjson/generic/ondemand/value_iterator.h @@ -23,6 +23,8 @@ protected: json_iterator *_json_iter{}; /** The depth of this value */ depth_t _depth{}; + /** The starting token index for this value */ + const uint32_t *_start_index{}; public: simdjson_really_inline value_iterator() noexcept = default; @@ -246,7 +248,7 @@ public: /** @} */ protected: - simdjson_really_inline value_iterator(json_iterator *json_iter, depth_t depth) noexcept; + simdjson_really_inline value_iterator(json_iterator *json_iter, depth_t depth, const uint32_t *start_index) noexcept; simdjson_really_inline bool is_null(const uint8_t *json) const noexcept; simdjson_really_inline simdjson_result parse_bool(const uint8_t *json) const noexcept; simdjson_really_inline bool is_root_null(const uint8_t *json, uint32_t max_len) const noexcept; @@ -255,6 +257,12 @@ 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 void assert_at_start() const noexcept; + simdjson_really_inline void assert_at_root() const noexcept; + simdjson_really_inline void assert_at_child() const noexcept; + simdjson_really_inline void assert_at_next() const noexcept; + simdjson_really_inline void assert_at_non_root_start() const noexcept; + friend class document; friend class object; friend class array;