From 33610b59eb853bb6444497aa543ff56f283a240c Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Mon, 5 Feb 2024 23:52:01 +0100 Subject: [PATCH] Allow some iterators to be used in standard C++ iterator functions (#2106) --- include/simdjson/dom/array.h | 5 ++- include/simdjson/dom/object.h | 7 +++- .../generic/ondemand/document_stream.h | 9 ++--- tests/dom/basictests.cpp | 39 +++++++++++++++++++ .../ondemand_document_stream_tests.cpp | 21 +++++++++- 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/include/simdjson/dom/array.h b/include/simdjson/dom/array.h index f01a72b7be..40029752b6 100644 --- a/include/simdjson/dom/array.h +++ b/include/simdjson/dom/array.h @@ -19,11 +19,14 @@ class array { public: using value_type = element; using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = value_type; + using iterator_category = std::forward_iterator_tag; /** * Get the actual value */ - inline value_type operator*() const noexcept; + inline reference operator*() const noexcept; /** * Get the next value. * diff --git a/include/simdjson/dom/object.h b/include/simdjson/dom/object.h index 443b44f455..14a643c18f 100644 --- a/include/simdjson/dom/object.h +++ b/include/simdjson/dom/object.h @@ -18,13 +18,16 @@ class object { class iterator { public: - using value_type = key_value_pair; + using value_type = const key_value_pair; using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = value_type; + using iterator_category = std::forward_iterator_tag; /** * Get the actual key/value pair */ - inline const value_type operator*() const noexcept; + inline reference operator*() const noexcept; /** * Get the next key/value pair. * diff --git a/include/simdjson/generic/ondemand/document_stream.h b/include/simdjson/generic/ondemand/document_stream.h index d63534e1d9..4a381db343 100644 --- a/include/simdjson/generic/ondemand/document_stream.h +++ b/include/simdjson/generic/ondemand/document_stream.h @@ -122,10 +122,9 @@ class document_stream { class iterator { public: using value_type = simdjson_result; - using reference = value_type; - + using reference = simdjson_result; + using pointer = void; using difference_type = std::ptrdiff_t; - using iterator_category = std::input_iterator_tag; /** @@ -135,7 +134,7 @@ class document_stream { /** * Get the current document (or error). */ - simdjson_inline simdjson_result operator*() noexcept; + simdjson_inline reference operator*() noexcept; /** * Advance to the next document (prefix). */ @@ -335,4 +334,4 @@ struct simdjson_result : pub } // namespace simdjson -#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H \ No newline at end of file +#endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_STREAM_H diff --git a/tests/dom/basictests.cpp b/tests/dom/basictests.cpp index 8982b1e071..f5a1146e89 100644 --- a/tests/dom/basictests.cpp +++ b/tests/dom/basictests.cpp @@ -912,6 +912,43 @@ namespace dom_api_tests { return true; } + bool object_iterator_advance() { + std::cout << "Running " << __func__ << std::endl; + string json(R"({ "a": 1, "b": 2, "c": 3 })"); + const char* expected_key[] = { "a", "b", "c" }; + uint64_t expected_value[] = { 1, 2, 3 }; + + dom::parser parser; + dom::object object; + ASSERT_SUCCESS( parser.parse(json).get(object) ); + auto iter = object.begin(); + for (auto i = 0; i * sizeof(expected_value[0]) < sizeof(expected_value); i++) { + auto [key, value] = *iter; + ASSERT_EQUAL( key, expected_key[i] ); + ASSERT_EQUAL( value.get_uint64().value_unsafe(), expected_value[i] ); + std::advance( iter, 1 ); + } + return true; + } + + bool array_iterator_advance() { + std::cout << "Running " << __func__ << std::endl; + string json(R"([ 1, 10, 100 ])"); + uint64_t expected_value[] = { 1, 10, 100 }; + + dom::parser parser; + dom::array array; + ASSERT_SUCCESS( parser.parse(json).get(array) ); + auto iter = array.begin(); + for (auto i = 0; i * sizeof(expected_value[0]) < sizeof(expected_value); i++) { + uint64_t v; + ASSERT_SUCCESS( (*iter).get(v) ); + ASSERT_EQUAL( v, expected_value[i] ); + std::advance( iter, 1 ); + } + return true; + } + bool string_value() { std::cout << "Running " << __func__ << std::endl; string json(R"([ "hi", "has backslash\\" ])"); @@ -1291,6 +1328,8 @@ namespace dom_api_tests { array_iterator() && object_iterator_empty() && array_iterator_empty() && + object_iterator_advance() && + array_iterator_advance() && string_value() && numeric_values() && boolean_values() && diff --git a/tests/ondemand/ondemand_document_stream_tests.cpp b/tests/ondemand/ondemand_document_stream_tests.cpp index 712aed6854..b1b91b0c6c 100644 --- a/tests/ondemand/ondemand_document_stream_tests.cpp +++ b/tests/ondemand/ondemand_document_stream_tests.cpp @@ -322,6 +322,24 @@ namespace document_stream_tests { TEST_SUCCEED(); } + bool simple_document_iteration_advance() { + TEST_START(); + auto json = R"([1,[1,2]] {"a":1,"b":2} {"o":{"1":1,"2":2}} [1,2,3])"_padded; + ondemand::parser parser; + ondemand::document_stream stream; + ASSERT_SUCCESS(parser.iterate_many(json).get(stream)); + std::string_view expected[4] = {"[1,[1,2]]", "{\"a\":1,\"b\":2}", "{\"o\":{\"1\":1,\"2\":2}}", "[1,2,3]"}; + auto iter = stream.begin(); + for (auto i = 0; i < 4; i++) { + auto doc = *iter; + std::string_view view; + ASSERT_SUCCESS(to_json_string(doc).get(view)); + ASSERT_EQUAL(view, expected[i]); + std::advance(iter, 1); + } + TEST_SUCCEED(); + } + bool skipbom() { TEST_START(); auto json = "\xEF\xBB\xBF[1,[1,2]] {\"a\":1,\"b\":2} {\"o\":{\"1\":1,\"2\":2}} [1,2,3]"_padded; @@ -856,6 +874,7 @@ namespace document_stream_tests { simple_document_iteration() && simple_document_iteration_multiple_batches() && simple_document_iteration_with_parsing() && + simple_document_iteration_advance() && atoms_json() && doc_index() && doc_index_multiple_batches() && @@ -879,4 +898,4 @@ namespace document_stream_tests { int main (int argc, char *argv[]) { return test_main(argc, argv, document_stream_tests::run); -} \ No newline at end of file +}