From 374de826ab07e57522f36ea8d935886f1d45d662 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Sat, 26 Jun 2021 11:33:37 -0400 Subject: [PATCH] This introduces a reset functionality for object and array containers (#1639) * This introduces a reset functionality. * Minor simplification. * Tweaking further. * This should fix the tests. --- .vscode/settings.json | 5 +++- include/simdjson/generic/ondemand/array-inl.h | 6 +---- .../generic/ondemand/value_iterator-inl.h | 25 +++++++++++------- .../generic/ondemand/value_iterator.h | 26 ++++++++++++------- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a06dee88..93a244ac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,9 @@ ], "files.trimTrailingWhitespace": true, "files.associations": { - "array": "cpp" + "array": "cpp", + "iterator": "cpp", + "chrono": "cpp", + "optional": "cpp" } } \ No newline at end of file diff --git a/include/simdjson/generic/ondemand/array-inl.h b/include/simdjson/generic/ondemand/array-inl.h index 729de0ae..9a745517 100644 --- a/include/simdjson/generic/ondemand/array-inl.h +++ b/include/simdjson/generic/ondemand/array-inl.h @@ -73,9 +73,6 @@ simdjson_really_inline simdjson_result array::end() noexcept { } simdjson_really_inline simdjson_result array::count_elements() & noexcept { - // If the array is empty (i.e., we already scanned past it), then we use a - // fast path and return 0. - if(!iter.is_open()) { return 0; } size_t count{0}; // Important: we do not consume any of the values. for(simdjson_unused auto v : *this) { count++; } @@ -83,8 +80,7 @@ simdjson_really_inline simdjson_result array::count_elements() & noexcep if(iter.error()) { return iter.error(); } // We need to move back at the start because we expect users to iterate through // the array after counting the number of elements. - // enter_at_container_start is safe here because we know that we do not have an empty array. - iter.enter_at_container_start(); // sets the depth to indicate that we are inside the container and accesses the first element + iter.reset_array(); return count; } diff --git a/include/simdjson/generic/ondemand/value_iterator-inl.h b/include/simdjson/generic/ondemand/value_iterator-inl.h index 86ea4b75..04c43ee6 100644 --- a/include/simdjson/generic/ondemand/value_iterator-inl.h +++ b/include/simdjson/generic/ondemand/value_iterator-inl.h @@ -194,9 +194,8 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator // this object iterator will blithely scan that object for fields. if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; } #endif - _json_iter->reenter_child(_start_position + 1, _depth); + has_value = reset_object(); at_first = true; - has_value = started_object(); // 3. When a previous search found a field or an iterator yielded a value: // // ``` @@ -288,8 +287,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterator // beginning of the object. // (We have already run through the object before, so we've already validated its structure. We // don't check errors in this bit.) - _json_iter->reenter_child(_start_position + 1, _depth); - has_value = started_object(); + has_value = reset_object(); while (true) { SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field @@ -628,15 +626,24 @@ inline void value_iterator::assert_at_next() const noexcept { SIMDJSON_ASSUME( _depth > 0 ); } +simdjson_really_inline void value_iterator::move_at_start() noexcept { + _json_iter->_depth = _depth; + _json_iter->token.index = _start_position; +} -simdjson_really_inline void value_iterator::enter_at_container_start() noexcept { - _json_iter->_depth = _depth + 1; +simdjson_really_inline void value_iterator::move_at_container_start() noexcept { + _json_iter->_depth = _depth; _json_iter->token.index = _start_position + 1; } -simdjson_really_inline void value_iterator::move_at_start() noexcept { - _json_iter->_depth = _depth; - _json_iter->token.index = _start_position; +simdjson_really_inline bool value_iterator::reset_array() noexcept { + move_at_container_start(); + return started_array(); +} + +simdjson_really_inline bool value_iterator::reset_object() noexcept { + move_at_container_start(); + return started_object(); } inline void value_iterator::assert_at_child() const noexcept { diff --git a/include/simdjson/generic/ondemand/value_iterator.h b/include/simdjson/generic/ondemand/value_iterator.h index d544d1a3..7d3d7253 100644 --- a/include/simdjson/generic/ondemand/value_iterator.h +++ b/include/simdjson/generic/ondemand/value_iterator.h @@ -281,24 +281,32 @@ public: /** @} */ protected: + /** + * Restarts an array iteration. + * @returns Whether the array has any elements (returns false for empty). + */ + simdjson_really_inline bool reset_array() noexcept; + /** + * Restarts an object iteration. + * @returns Whether the object has any fields (returns false for empty). + */ + simdjson_really_inline bool reset_object() noexcept; /** * move_at_start(): moves us so that we are pointing at the beginning of * the container. It updates the index so that at_start() is true and it * syncs the depth. The user can then create a new container instance. * - * Usage: used with value::count_elements() + * Usage: used with value::count_elements(). **/ - simdjson_really_inline void move_at_start() noexcept; + simdjson_really_inline void move_at_start() noexcept; + /** - * enter_at_container_start moves at the beginning of the container - * and sets the depth to indicate that we are inside the - * container and ready to access the first element. It is only - * safely used with non-empty containers. The caller is responsible - * to ensure that the container is not empty! + * move_at_container_start(): moves us so that we are pointing at the beginning of + * the container so that assert_at_container_start() passes. * - * Usage: used with array::count_elements(). + * Usage: used with reset_array() and reset_object(). **/ - simdjson_really_inline void enter_at_container_start() noexcept; + simdjson_really_inline void move_at_container_start() noexcept; /* Useful for debugging and logging purposes. */ inline std::string to_string() const noexcept; simdjson_really_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;