From 330ffd952b891abe7d1902ef3b55d799ceb1573d Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Sun, 8 Feb 2015 19:18:39 +0100
Subject: [PATCH] removed reverse_iterators and fixed some bugs

---
 src/json.hpp      |  52 +----
 src/json.hpp.re2c |  52 +----
 test/unit.cpp     | 469 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 471 insertions(+), 102 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index 7207aeec..e6804832 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -84,10 +84,6 @@ class basic_json
     using iterator = basic_json::iterator;
     /// a const iterator for a basic_json container
     using const_iterator = basic_json::const_iterator;
-    // a reverse iterator for a basic_json container
-    using reverse_iterator = std::reverse_iterator<iterator>;
-    /// a const reverse iterator for a basic_json container
-    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
 
     ///////////////////////////
@@ -259,8 +255,6 @@ class basic_json
               std::enable_if<
                   not std::is_same<V, basic_json::iterator>::value and
                   not std::is_same<V, basic_json::const_iterator>::value and
-                  not std::is_same<V, basic_json::reverse_iterator>::value and
-                  not std::is_same<V, basic_json::const_reverse_iterator>::value and
                   std::is_constructible<basic_json, typename V::value_type>::value, int>::type
               = 0>
     inline basic_json(const V& value)
@@ -732,18 +726,6 @@ class basic_json
         return m_value.object->operator[](key);
     }
 
-    /// access specified element
-    inline reference operator[](typename object_t::key_type&& key)
-    {
-        // at only works for objects
-        if (m_type != value_t::object)
-        {
-            throw std::runtime_error("cannot use [] with " + type_name());
-        }
-
-        return m_value.object->operator[](std::move(key));
-    }
-
 
     /// find an element in an object
     inline iterator find(typename object_t::key_type key)
@@ -824,38 +806,6 @@ class basic_json
         return result;
     }
 
-    /// returns a reverse iterator to the end of the container
-    inline reverse_iterator rbegin() const noexcept
-    {
-        reverse_iterator result(this);
-        result.set_end();
-        return result;
-    }
-
-    /// returns a reverse iterator to the beginning of the container
-    inline reverse_iterator rend() const noexcept
-    {
-        reverse_iterator result(this);
-        result.set_begin();
-        return result;
-    }
-
-    /// returns a const reverse iterator to the end of the container
-    inline const_reverse_iterator crbegin() const noexcept
-    {
-        const_reverse_iterator result(this);
-        result.set_end();
-        return result;
-    }
-
-    /// returns a const reverse iterator to the beginning of the container
-    inline const_reverse_iterator crend() const noexcept
-    {
-        const_reverse_iterator result(this);
-        result.set_begin();
-        return result;
-    }
-
 
     //////////////
     // capacity //
@@ -2326,7 +2276,7 @@ class basic_json
         /// post-decrement (it--)
         inline const_iterator operator--(int)
         {
-            iterator result = *this;
+            const_iterator result = *this;
 
             switch (m_object->m_type)
             {
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 7e4e4701..f8cc0148 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -84,10 +84,6 @@ class basic_json
     using iterator = basic_json::iterator;
     /// a const iterator for a basic_json container
     using const_iterator = basic_json::const_iterator;
-    // a reverse iterator for a basic_json container
-    using reverse_iterator = std::reverse_iterator<iterator>;
-    /// a const reverse iterator for a basic_json container
-    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
 
     ///////////////////////////
@@ -259,8 +255,6 @@ class basic_json
               std::enable_if<
                   not std::is_same<V, basic_json::iterator>::value and
                   not std::is_same<V, basic_json::const_iterator>::value and
-                  not std::is_same<V, basic_json::reverse_iterator>::value and
-                  not std::is_same<V, basic_json::const_reverse_iterator>::value and
                   std::is_constructible<basic_json, typename V::value_type>::value, int>::type
               = 0>
     inline basic_json(const V& value)
@@ -732,18 +726,6 @@ class basic_json
         return m_value.object->operator[](key);
     }
 
-    /// access specified element
-    inline reference operator[](typename object_t::key_type&& key)
-    {
-        // at only works for objects
-        if (m_type != value_t::object)
-        {
-            throw std::runtime_error("cannot use [] with " + type_name());
-        }
-
-        return m_value.object->operator[](std::move(key));
-    }
-
 
     /// find an element in an object
     inline iterator find(typename object_t::key_type key)
@@ -824,38 +806,6 @@ class basic_json
         return result;
     }
 
-    /// returns a reverse iterator to the end of the container
-    inline reverse_iterator rbegin() const noexcept
-    {
-        reverse_iterator result(this);
-        result.set_end();
-        return result;
-    }
-
-    /// returns a reverse iterator to the beginning of the container
-    inline reverse_iterator rend() const noexcept
-    {
-        reverse_iterator result(this);
-        result.set_begin();
-        return result;
-    }
-
-    /// returns a const reverse iterator to the end of the container
-    inline const_reverse_iterator crbegin() const noexcept
-    {
-        const_reverse_iterator result(this);
-        result.set_end();
-        return result;
-    }
-
-    /// returns a const reverse iterator to the beginning of the container
-    inline const_reverse_iterator crend() const noexcept
-    {
-        const_reverse_iterator result(this);
-        result.set_begin();
-        return result;
-    }
-
 
     //////////////
     // capacity //
@@ -2326,7 +2276,7 @@ class basic_json
         /// post-decrement (it--)
         inline const_iterator operator--(int)
         {
-            iterator result = *this;
+            const_iterator result = *this;
 
             switch (m_object->m_type)
             {
diff --git a/test/unit.cpp b/test/unit.cpp
index c8022ed3..d246aa50 100644
--- a/test/unit.cpp
+++ b/test/unit.cpp
@@ -2275,3 +2275,472 @@ TEST_CASE("element access")
         }
     }
 }
+
+TEST_CASE("iterators")
+{
+    SECTION("boolean")
+    {
+        json j = true;
+        json j_const(j);
+
+        SECTION("json + begin/end")
+        {
+            auto it = j.begin();
+            CHECK(it != j.end());
+            CHECK(*it == j);
+
+            it++;
+            CHECK(it != j.begin());
+            CHECK(it == j.end());
+
+            it--;
+            CHECK(it == j.begin());
+            CHECK(it != j.end());
+            CHECK(*it == j);
+
+            ++it;
+            CHECK(it != j.begin());
+            CHECK(it == j.end());
+
+            --it;
+            CHECK(it == j.begin());
+            CHECK(it != j.end());
+            CHECK(*it == j);
+        }
+
+        SECTION("const json + begin/end")
+        {
+            auto it = j_const.begin();
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+
+            it++;
+            CHECK(it != j_const.begin());
+            CHECK(it == j_const.end());
+
+            it--;
+            CHECK(it == j_const.begin());
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+
+            ++it;
+            CHECK(it != j_const.begin());
+            CHECK(it == j_const.end());
+
+            --it;
+            CHECK(it == j_const.begin());
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+        }
+
+        SECTION("json + cbegin/cend")
+        {
+            auto it = j.cbegin();
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+
+            it++;
+            CHECK(it != j.cbegin());
+            CHECK(it == j.cend());
+
+            it--;
+            CHECK(it == j.cbegin());
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+
+            ++it;
+            CHECK(it != j.cbegin());
+            CHECK(it == j.cend());
+
+            --it;
+            CHECK(it == j.cbegin());
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+        }
+
+        SECTION("const json + cbegin/cend")
+        {
+            auto it = j_const.cbegin();
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+
+            it++;
+            CHECK(it != j_const.cbegin());
+            CHECK(it == j_const.cend());
+
+            it--;
+            CHECK(it == j_const.cbegin());
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+
+            ++it;
+            CHECK(it != j_const.cbegin());
+            CHECK(it == j_const.cend());
+
+            --it;
+            CHECK(it == j_const.cbegin());
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+        }
+    }
+
+    SECTION("string")
+    {
+        json j = "hello world";
+        json j_const(j);
+
+        SECTION("json + begin/end")
+        {
+            auto it = j.begin();
+            CHECK(it != j.end());
+            CHECK(*it == j);
+
+            it++;
+            CHECK(it != j.begin());
+            CHECK(it == j.end());
+
+            it--;
+            CHECK(it == j.begin());
+            CHECK(it != j.end());
+            CHECK(*it == j);
+
+            ++it;
+            CHECK(it != j.begin());
+            CHECK(it == j.end());
+
+            --it;
+            CHECK(it == j.begin());
+            CHECK(it != j.end());
+            CHECK(*it == j);
+        }
+
+        SECTION("const json + begin/end")
+        {
+            auto it = j_const.begin();
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+
+            it++;
+            CHECK(it != j_const.begin());
+            CHECK(it == j_const.end());
+
+            it--;
+            CHECK(it == j_const.begin());
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+
+            ++it;
+            CHECK(it != j_const.begin());
+            CHECK(it == j_const.end());
+
+            --it;
+            CHECK(it == j_const.begin());
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+        }
+
+        SECTION("json + cbegin/cend")
+        {
+            auto it = j.cbegin();
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+
+            it++;
+            CHECK(it != j.cbegin());
+            CHECK(it == j.cend());
+
+            it--;
+            CHECK(it == j.cbegin());
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+
+            ++it;
+            CHECK(it != j.cbegin());
+            CHECK(it == j.cend());
+
+            --it;
+            CHECK(it == j.cbegin());
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+        }
+
+        SECTION("const json + cbegin/cend")
+        {
+            auto it = j_const.cbegin();
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+
+            it++;
+            CHECK(it != j_const.cbegin());
+            CHECK(it == j_const.cend());
+
+            it--;
+            CHECK(it == j_const.cbegin());
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+
+            ++it;
+            CHECK(it != j_const.cbegin());
+            CHECK(it == j_const.cend());
+
+            --it;
+            CHECK(it == j_const.cbegin());
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+        }
+    }
+
+    SECTION("array")
+    {
+        json j = {1, 2, 3, 4};
+        json j_const(j);
+    }
+
+    SECTION("object")
+    {
+        json j = {{"one", 1}, {"two", 2}, {"three", 3}};
+        json j_const(j);
+    }
+
+    SECTION("number (integer)")
+    {
+        json j = 23;
+        json j_const(j);
+
+        SECTION("json + begin/end")
+        {
+            auto it = j.begin();
+            CHECK(it != j.end());
+            CHECK(*it == j);
+
+            it++;
+            CHECK(it != j.begin());
+            CHECK(it == j.end());
+
+            it--;
+            CHECK(it == j.begin());
+            CHECK(it != j.end());
+            CHECK(*it == j);
+
+            ++it;
+            CHECK(it != j.begin());
+            CHECK(it == j.end());
+
+            --it;
+            CHECK(it == j.begin());
+            CHECK(it != j.end());
+            CHECK(*it == j);
+        }
+
+        SECTION("const json + begin/end")
+        {
+            auto it = j_const.begin();
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+
+            it++;
+            CHECK(it != j_const.begin());
+            CHECK(it == j_const.end());
+
+            it--;
+            CHECK(it == j_const.begin());
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+
+            ++it;
+            CHECK(it != j_const.begin());
+            CHECK(it == j_const.end());
+
+            --it;
+            CHECK(it == j_const.begin());
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+        }
+
+        SECTION("json + cbegin/cend")
+        {
+            auto it = j.cbegin();
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+
+            it++;
+            CHECK(it != j.cbegin());
+            CHECK(it == j.cend());
+
+            it--;
+            CHECK(it == j.cbegin());
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+
+            ++it;
+            CHECK(it != j.cbegin());
+            CHECK(it == j.cend());
+
+            --it;
+            CHECK(it == j.cbegin());
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+        }
+
+        SECTION("const json + cbegin/cend")
+        {
+            auto it = j_const.cbegin();
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+
+            it++;
+            CHECK(it != j_const.cbegin());
+            CHECK(it == j_const.cend());
+
+            it--;
+            CHECK(it == j_const.cbegin());
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+
+            ++it;
+            CHECK(it != j_const.cbegin());
+            CHECK(it == j_const.cend());
+
+            --it;
+            CHECK(it == j_const.cbegin());
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+        }
+    }
+
+    SECTION("number (float)")
+    {
+        json j = 23.42;
+        json j_const(j);
+
+        SECTION("json + begin/end")
+        {
+            auto it = j.begin();
+            CHECK(it != j.end());
+            CHECK(*it == j);
+
+            it++;
+            CHECK(it != j.begin());
+            CHECK(it == j.end());
+
+            it--;
+            CHECK(it == j.begin());
+            CHECK(it != j.end());
+            CHECK(*it == j);
+
+            ++it;
+            CHECK(it != j.begin());
+            CHECK(it == j.end());
+
+            --it;
+            CHECK(it == j.begin());
+            CHECK(it != j.end());
+            CHECK(*it == j);
+        }
+
+        SECTION("const json + begin/end")
+        {
+            auto it = j_const.begin();
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+
+            it++;
+            CHECK(it != j_const.begin());
+            CHECK(it == j_const.end());
+
+            it--;
+            CHECK(it == j_const.begin());
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+
+            ++it;
+            CHECK(it != j_const.begin());
+            CHECK(it == j_const.end());
+
+            --it;
+            CHECK(it == j_const.begin());
+            CHECK(it != j_const.end());
+            CHECK(*it == j_const);
+        }
+
+        SECTION("json + cbegin/cend")
+        {
+            auto it = j.cbegin();
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+
+            it++;
+            CHECK(it != j.cbegin());
+            CHECK(it == j.cend());
+
+            it--;
+            CHECK(it == j.cbegin());
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+
+            ++it;
+            CHECK(it != j.cbegin());
+            CHECK(it == j.cend());
+
+            --it;
+            CHECK(it == j.cbegin());
+            CHECK(it != j.cend());
+            CHECK(*it == j);
+        }
+
+        SECTION("const json + cbegin/cend")
+        {
+            auto it = j_const.cbegin();
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+
+            it++;
+            CHECK(it != j_const.cbegin());
+            CHECK(it == j_const.cend());
+
+            it--;
+            CHECK(it == j_const.cbegin());
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+
+            ++it;
+            CHECK(it != j_const.cbegin());
+            CHECK(it == j_const.cend());
+
+            --it;
+            CHECK(it == j_const.cbegin());
+            CHECK(it != j_const.cend());
+            CHECK(*it == j_const);
+        }
+    }
+
+    SECTION("null")
+    {
+        json j = nullptr;
+        json j_const(j);
+
+        SECTION("json + begin/end")
+        {
+            auto it = j.begin();
+            CHECK(it == j.end());
+        }
+
+        SECTION("const json + begin/end")
+        {
+            auto it = j_const.begin();
+            CHECK(it == j_const.end());
+        }
+
+        SECTION("json + cbegin/cend")
+        {
+            auto it = j.cbegin();
+            CHECK(it == j.cend());
+        }
+
+        SECTION("const json + cbegin/cend")
+        {
+            auto it = j_const.cbegin();
+            CHECK(it == j_const.cend());
+        }
+    }
+}