diff --git a/src/json.hpp b/src/json.hpp index d1338969f..61b18f108 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -5712,10 +5712,41 @@ class basic_json json_iterator anchor; /// an index for arrays size_t array_index = 0; - size_t container_size = 0; - /// calculate a key for the iterator - std::string calculate_key() + public: + /// construct wrapper given an iterator + iterator_wrapper_internal(json_iterator i) : anchor(i) + {} + + /// dereference operator (needed for range-based for) + iterator_wrapper_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iterator_wrapper_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!= (const iterator_wrapper_internal& o) + { + return anchor != o.anchor; + } + + /// stream operator + friend std::ostream& operator<<(std::ostream& o, const iterator_wrapper_internal& w) + { + return o << w.value(); + } + + /// return key of the iterator + typename basic_json::string_t key() const { switch (anchor.m_object->type()) { @@ -5739,61 +5770,11 @@ class basic_json } } - public: - /// construct wrapper given an iterator - iterator_wrapper_internal(json_iterator i, size_t s) - : anchor(i), container_size(s), first(calculate_key()), second(*i) - {} - - /// dereference operator (needed for range-based for) - iterator_wrapper_internal operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iterator_wrapper_internal& operator++() - { - ++anchor; - ++array_index; - - if (array_index < container_size) - { - first = calculate_key(); - second = *anchor; - } - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!= (const iterator_wrapper_internal& o) - { - return anchor != o.anchor; - } - - /// stream operator - friend std::ostream& operator<<(std::ostream& o, const iterator_wrapper_internal& w) - { - return o << w.value(); - } - - /// return key of the iterator - typename basic_json::string_t key() const - { - return first; - } - /// return value of the iterator - basic_json value() const + typename json_iterator::reference value() const { - return second; + return anchor.value(); } - - /// public member to simulate std::map::iterator access - typename basic_json::string_t first; - /// public member to simulate std::map::iterator access - basic_json& second; }; public: @@ -5805,13 +5786,13 @@ class basic_json /// return iterator begin (needed for range-based for) iterator_wrapper_internal begin() { - return iterator_wrapper_internal(container.begin(), container.size()); + return iterator_wrapper_internal(container.begin()); } /// return iterator end (needed for range-based for) iterator_wrapper_internal end() { - return iterator_wrapper_internal(container.end(), container.size()); + return iterator_wrapper_internal(container.end()); } }; diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index f8547367d..2f01c007b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5712,10 +5712,41 @@ class basic_json json_iterator anchor; /// an index for arrays size_t array_index = 0; - size_t container_size = 0; - /// calculate a key for the iterator - std::string calculate_key() + public: + /// construct wrapper given an iterator + iterator_wrapper_internal(json_iterator i) : anchor(i) + {} + + /// dereference operator (needed for range-based for) + iterator_wrapper_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iterator_wrapper_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!= (const iterator_wrapper_internal& o) + { + return anchor != o.anchor; + } + + /// stream operator + friend std::ostream& operator<<(std::ostream& o, const iterator_wrapper_internal& w) + { + return o << w.value(); + } + + /// return key of the iterator + typename basic_json::string_t key() const { switch (anchor.m_object->type()) { @@ -5739,61 +5770,11 @@ class basic_json } } - public: - /// construct wrapper given an iterator - iterator_wrapper_internal(json_iterator i, size_t s) - : anchor(i), container_size(s), first(calculate_key()), second(*i) - {} - - /// dereference operator (needed for range-based for) - iterator_wrapper_internal operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iterator_wrapper_internal& operator++() - { - ++anchor; - ++array_index; - - if (array_index < container_size) - { - first = calculate_key(); - second = *anchor; - } - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!= (const iterator_wrapper_internal& o) - { - return anchor != o.anchor; - } - - /// stream operator - friend std::ostream& operator<<(std::ostream& o, const iterator_wrapper_internal& w) - { - return o << w.value(); - } - - /// return key of the iterator - typename basic_json::string_t key() const - { - return first; - } - /// return value of the iterator - basic_json value() const + typename json_iterator::reference value() const { - return second; + return anchor.value(); } - - /// public member to simulate std::map::iterator access - typename basic_json::string_t first; - /// public member to simulate std::map::iterator access - basic_json& second; }; public: @@ -5805,13 +5786,13 @@ class basic_json /// return iterator begin (needed for range-based for) iterator_wrapper_internal begin() { - return iterator_wrapper_internal(container.begin(), container.size()); + return iterator_wrapper_internal(container.begin()); } /// return iterator end (needed for range-based for) iterator_wrapper_internal end() { - return iterator_wrapper_internal(container.end(), container.size()); + return iterator_wrapper_internal(container.end()); } }; diff --git a/test/unit.cpp b/test/unit.cpp index 816021615..d866b96d2 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -9260,70 +9260,301 @@ TEST_CASE("concepts") } } -/* TEST_CASE("iterator_wrapper") { SECTION("object") { - json j = {{"A", 1}, {"B", 2}}; - int counter = 1; - - for (auto i : json::iterator_wrapper(j)) + SECTION("value") { - switch (counter++) - { - case 1: - { - CHECK(i.key() == "A"); - CHECK(i.value() == json(1)); - CHECK(i.first == "A"); - CHECK(i.second == json(1)); - break; - } + json j = {{"A", 1}, {"B", 2}}; + int counter = 1; - case 2: + for (auto i : json::iterator_wrapper(j)) + { + switch (counter++) { - CHECK(i.key() == "B"); - CHECK(i.value() == json(2)); - CHECK(i.first == "B"); - CHECK(i.second == json(2)); - break; + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } } } + + CHECK(counter == 3); + } + + SECTION("reference") + { + json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (auto& i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const value") + { + json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (const auto i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const reference") + { + json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (const auto& i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + } + } + + CHECK(counter == 3); } } SECTION("array") { - json j = {"A", "B"}; - int counter = 1; - - for (auto i : json::iterator_wrapper(j)) + SECTION("value") { - switch (counter++) - { - case 1: - { - CHECK(i.key() == "0"); - CHECK(i.value() == "A"); - CHECK(i.first == "0"); - CHECK(i.second == "A"); - break; - } + json j = {"A", "B"}; + int counter = 1; - case 2: + for (auto i : json::iterator_wrapper(j)) + { + switch (counter++) { - CHECK(i.key() == "1"); - CHECK(i.value() == "B"); - CHECK(i.first == "1"); - CHECK(i.second == "B"); - break; + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } } } + + CHECK(counter == 3); + } + + SECTION("reference") + { + json j = {"A", "B"}; + int counter = 1; + + for (auto& i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const value") + { + json j = {"A", "B"}; + int counter = 1; + + for (const auto i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const reference") + { + json j = {"A", "B"}; + int counter = 1; + + for (const auto& i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + } + } + + CHECK(counter == 3); + } + } + + SECTION("primitive") + { + SECTION("value") + { + json j = 1; + int counter = 1; + + for (auto i : json::iterator_wrapper(j)) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("reference") + { + json j = 1; + int counter = 1; + + for (auto& i : json::iterator_wrapper(j)) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("const value") + { + json j = 1; + int counter = 1; + + for (const auto i : json::iterator_wrapper(j)) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("reference") + { + json j = 1; + int counter = 1; + + for (const auto& i : json::iterator_wrapper(j)) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); } } } -*/ TEST_CASE("compliance tests from json.org") {