diff --git a/src/json.hpp b/src/json.hpp index 1016ab18..3c338eb8 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -44,7 +44,7 @@ SOFTWARE. #include // initializer_list #include // hex #include // istream, ostream -#include // advance, begin, back_inserter, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator +#include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator #include // numeric_limits #include // locale #include // map @@ -281,6 +281,8 @@ json.exception.invalid_iterator.204 | iterators out of range | When an iterator json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. @@ -3553,7 +3555,7 @@ class iter_impl : public std::iterator::type; /// the category of the iterator - using iterator_category = std::random_access_iterator_tag; + using iterator_category = std::bidirectional_iterator_tag; /// default constructor iter_impl() = default; @@ -3947,8 +3949,7 @@ class iter_impl : public std::iteratorm_type) { case value_t::object: - std::advance(m_it.object_iterator, i); - break; + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); case value_t::array: { @@ -4019,11 +4020,7 @@ class iter_impl : public std::iteratorm_type) { case value_t::object: - { - difference_type result = 0; - for (auto it = other; it != *this; ++it, ++result); - return result; - } + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); case value_t::array: return m_it.array_iterator - other.m_it.array_iterator; @@ -4044,11 +4041,7 @@ class iter_impl : public std::iteratorm_type) { case value_t::object: - { - auto it = *this; - std::advance(it.m_it.object_iterator, n); - return *it; - } + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); case value_t::array: return *std::next(m_it.array_iterator, n); @@ -13194,7 +13187,7 @@ class basic_json */ template::value, int> = 0> - static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) + static basic_json from_cbor(A1&& a1, A2&& a2, const bool strict = true) { return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); } @@ -13281,7 +13274,7 @@ class basic_json */ template::value, int> = 0> - static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) + static basic_json from_msgpack(A1&& a1, A2&& a2, const bool strict = true) { return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); } diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index e67ea404..5a106b6a 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -240,8 +240,9 @@ TEST_CASE("algorithms") SECTION("sorting an object") { json j({{"one", 1}, {"two", 2}}); - std::sort(j.begin(), j.end()); - CHECK(j == json({{"one", 1}, {"two", 2}})); + CHECK_THROWS_AS(std::sort(j.begin(), j.end()), json::invalid_iterator&); + CHECK_THROWS_WITH(std::sort(j.begin(), j.end()), + "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index 6391b54b..be4e2770 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -240,7 +240,7 @@ TEST_CASE("iterators 2") SECTION("iterator arithmetic") { - json j_object = {{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}}; + json j_object = {{"one", 1}, {"two", 2}, {"three", 3}}; json j_array = {1, 2, 3, 4, 5, 6}; json j_null = nullptr; json j_value = 42; @@ -251,25 +251,63 @@ TEST_CASE("iterators 2") { { auto it = j_object.begin(); - it += 3; - CHECK((j_object.begin() + 3) == it); - CHECK((3 + j_object.begin()) == it); - CHECK((it - 3) == j_object.begin()); - CHECK((it - j_object.begin()) == 3); - CHECK(*it == json(2)); - it -= 2; - CHECK(*it == json(1)); + CHECK_THROWS_AS(it += 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - it += 3; - CHECK((j_object.cbegin() + 3) == it); - CHECK((3 + j_object.cbegin()) == it); - CHECK((it - 3) == j_object.cbegin()); - CHECK((it - j_object.cbegin()) == 3); - CHECK(*it == json(2)); - it -= 2; - CHECK(*it == json(1)); + CHECK_THROWS_AS(it += 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it + 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it + 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(1 + it, json::invalid_iterator&); + CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(1 + it, json::invalid_iterator&); + CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it - 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it - 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it - it, json::invalid_iterator&); + CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it - it, json::invalid_iterator&); + CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -358,17 +396,17 @@ TEST_CASE("iterators 2") { { auto it = j_object.begin(); - CHECK(it[0] == json(4)); - CHECK(it[1] == json(1)); - CHECK(it[2] == json(3)); - CHECK(it[3] == json(2)); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); } { auto it = j_object.cbegin(); - CHECK(it[0] == json(4)); - CHECK(it[1] == json(1)); - CHECK(it[2] == json(3)); - CHECK(it[3] == json(2)); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); } } @@ -637,7 +675,7 @@ TEST_CASE("iterators 2") SECTION("reverse iterator arithmetic") { - json j_object = {{"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}}; + json j_object = {{"one", 1}, {"two", 2}, {"three", 3}}; json j_array = {1, 2, 3, 4, 5, 6}; json j_null = nullptr; json j_value = 42; @@ -648,25 +686,63 @@ TEST_CASE("iterators 2") { { auto it = j_object.rbegin(); - it += 3; - CHECK((j_object.rbegin() + 3) == it); - CHECK(json::reverse_iterator(3 + j_object.rbegin()) == it); - CHECK((it - 3) == j_object.rbegin()); - CHECK((it - j_object.rbegin()) == 3); - CHECK(*it == json(4)); - it -= 2; - CHECK(*it == json(3)); + CHECK_THROWS_AS(it += 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - it += 3; - CHECK((j_object.crbegin() + 3) == it); - CHECK(json::const_reverse_iterator(3 + j_object.crbegin()) == it); - CHECK((it - 3) == j_object.crbegin()); - CHECK((it - j_object.crbegin()) == 3); - CHECK(*it == json(4)); - it -= 2; - CHECK(*it == json(3)); + CHECK_THROWS_AS(it += 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it + 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it + 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(1 + it, json::invalid_iterator&); + CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(1 + it, json::invalid_iterator&); + CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it - 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it - 1, json::invalid_iterator&); + CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it - it, json::invalid_iterator&); + CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it - it, json::invalid_iterator&); + CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -755,17 +831,17 @@ TEST_CASE("iterators 2") { { auto it = j_object.rbegin(); - CHECK(it[0] == json(2)); - CHECK(it[1] == json(3)); - CHECK(it[2] == json(1)); - CHECK(it[3] == json(4)); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK(it[0] == json(2)); - CHECK(it[1] == json(3)); - CHECK(it[2] == json(1)); - CHECK(it[3] == json(4)); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } }