From 568940ad9855d647d349f653b7521d6d255683e5 Mon Sep 17 00:00:00 2001
From: Gabor <moggabor@gmail.com>
Date: Thu, 30 May 2019 13:48:31 +0200
Subject: [PATCH] added variant_associative_view::iterator

---
 .../detail/impl/associative_mapper_impl.h     |  20 ++
 .../variant_associative_view_private.h        |  25 ++-
 src/rttr/variant_associative_view.cpp         | 192 +++++++++++++++++-
 src/rttr/variant_associative_view.h           | 155 +++++++++++++-
 4 files changed, 387 insertions(+), 5 deletions(-)

diff --git a/src/rttr/detail/impl/associative_mapper_impl.h b/src/rttr/detail/impl/associative_mapper_impl.h
index 99cc8814..13d5aca1 100644
--- a/src/rttr/detail/impl/associative_mapper_impl.h
+++ b/src/rttr/detail/impl/associative_mapper_impl.h
@@ -72,6 +72,14 @@ struct associative_container_mapper_wrapper : iterator_wrapper_base<Tp>
         return variant(std::ref(base_class::get_key(it)));
     }
 
+    template<typename..., typename V = value_t, enable_if_t<!std::is_void<V>::value, int> = 0>
+    static variant
+    get_value(iterator_data& itr)
+    {
+        auto& it = itr_wrapper::get_iterator(itr);
+        return variant(std::ref(base_class::get_value(it)));
+    }
+
     template<typename..., typename V = value_t, enable_if_t<!std::is_void<V>::value, int> = 0>
     static variant
     get_value(const iterator_data& itr)
@@ -80,6 +88,13 @@ struct associative_container_mapper_wrapper : iterator_wrapper_base<Tp>
         return variant(std::ref(base_class::get_value(it)));
     }
 
+    template<typename..., typename V = value_t, enable_if_t<std::is_void<V>::value, int> = 0>
+    static variant
+    get_value(iterator_data& itr)
+    {
+        return variant();
+    }
+
     template<typename..., typename V = value_t, enable_if_t<std::is_void<V>::value, int> = 0>
     static variant
     get_value(const iterator_data& itr)
@@ -478,6 +493,11 @@ struct associative_container_empty
         return variant();
     }
 
+    static variant get_value(iterator_data& itr)
+    {
+        return variant();
+    }
+
     static variant get_value(const iterator_data& itr)
     {
         return variant();
diff --git a/src/rttr/detail/variant_associative_view/variant_associative_view_private.h b/src/rttr/detail/variant_associative_view/variant_associative_view_private.h
index eea43fcb..74e4807f 100644
--- a/src/rttr/detail/variant_associative_view/variant_associative_view_private.h
+++ b/src/rttr/detail/variant_associative_view/variant_associative_view_private.h
@@ -58,6 +58,7 @@ class RTTR_LOCAL variant_associative_view_private
             m_delete_func(associative_container_empty::destroy),
             m_get_key_func(associative_container_empty::get_key),
             m_get_value_func(associative_container_empty::get_value),
+            m_get_const_value_func(associative_container_empty::get_value),
             m_advance_func(associative_container_empty::advance),
             m_find_func(associative_container_empty::find),
             m_erase_func(associative_container_empty::erase),
@@ -85,6 +86,7 @@ class RTTR_LOCAL variant_associative_view_private
             m_delete_func(associative_container_mapper_wrapper<RawType, ConstType>::destroy),
             m_get_key_func(associative_container_mapper_wrapper<RawType, ConstType>::get_key),
             m_get_value_func(associative_container_mapper_wrapper<RawType, ConstType>::get_value),
+            m_get_const_value_func(associative_container_mapper_wrapper<RawType, ConstType>::get_value),
             m_advance_func(associative_container_mapper_wrapper<RawType, ConstType>::advance),
             m_find_func(associative_container_mapper_wrapper<RawType, ConstType>::find),
             m_erase_func(associative_container_mapper_wrapper<RawType, ConstType>::erase),
@@ -157,22 +159,37 @@ class RTTR_LOCAL variant_associative_view_private
             return m_get_key_func(itr);
         }
 
-        RTTR_INLINE const variant get_value(const iterator_data& itr) const
+        RTTR_INLINE variant get_value(iterator_data& itr) const
         {
             return m_get_value_func(itr);
         }
 
-        RTTR_INLINE const std::pair<variant, variant> get_key_value(const iterator_data& itr) const
+        RTTR_INLINE const variant get_value(const iterator_data& itr) const
+        {
+            return m_get_const_value_func(itr);
+        }
+
+        RTTR_INLINE std::pair<variant, variant> get_key_value(iterator_data& itr) const
         {
             return {m_get_key_func(itr), m_get_value_func(itr)};
         }
 
+        RTTR_INLINE const std::pair<variant, variant> get_key_value(const iterator_data& itr) const
+        {
+            return {m_get_key_func(itr), m_get_const_value_func(itr)};
+        }
+
 
         RTTR_INLINE void advance(iterator_data& itr, std::ptrdiff_t index) const
         {
             m_advance_func(itr, index);
         }
 
+        RTTR_INLINE void find(iterator_data& itr, argument& key) const
+        {
+            m_find_func(m_container, itr, key);
+        }
+
         RTTR_INLINE void find(iterator_data& itr, argument& key)
         {
             m_find_func(m_container, itr, key);
@@ -216,7 +233,8 @@ class RTTR_LOCAL variant_associative_view_private
         using create_func       = void(*)(iterator_data& itr_tgt, const iterator_data& itr_src);
         using delete_func       = void(*)(iterator_data& itr);
         using get_key_func      = variant (*)(const iterator_data& itr);
-        using get_value_func    = variant (*)(const iterator_data& itr);
+        using get_value_func    = variant(*)(iterator_data& itr);
+        using get_const_value_func = variant(*)(const iterator_data& itr);
         using clear_func        = void(*)(void* container);
         using erase_func        = std::size_t(*)(void* container, argument& key);
         using find_func         = void(*)(void* container, detail::iterator_data& itr, argument& key);
@@ -238,6 +256,7 @@ class RTTR_LOCAL variant_associative_view_private
         delete_func             m_delete_func;
         get_key_func            m_get_key_func;
         get_value_func          m_get_value_func;
+        get_const_value_func    m_get_const_value_func;
         advance_func            m_advance_func;
         find_func               m_find_func;
         erase_func              m_erase_func;
diff --git a/src/rttr/variant_associative_view.cpp b/src/rttr/variant_associative_view.cpp
index ee2119cc..3ccd4ce9 100644
--- a/src/rttr/variant_associative_view.cpp
+++ b/src/rttr/variant_associative_view.cpp
@@ -151,7 +151,19 @@ std::pair<variant_associative_view::const_iterator, bool> variant_associative_vi
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
-variant_associative_view::const_iterator variant_associative_view::find(argument arg)
+variant_associative_view::iterator variant_associative_view::find(argument arg)
+{
+    iterator itr(&m_view);
+
+    m_view.find(itr.m_itr, arg);
+
+    return itr;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::const_iterator variant_associative_view::find(argument arg) const
 {
     const_iterator itr(&m_view);
 
@@ -190,6 +202,17 @@ variant_associative_view::equal_range(argument key)
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
+variant_associative_view::iterator variant_associative_view::begin()
+{
+    iterator itr(&m_view);
+
+    m_view.begin(itr.m_itr);
+
+    return itr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
 variant_associative_view::const_iterator variant_associative_view::begin() const
 {
     const_iterator itr(&m_view);
@@ -201,6 +224,17 @@ variant_associative_view::const_iterator variant_associative_view::begin() const
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
+variant_associative_view::iterator variant_associative_view::end()
+{
+    iterator itr(&m_view);
+
+    m_view.end(itr.m_itr);
+
+    return itr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
 variant_associative_view::const_iterator variant_associative_view::end() const
 {
     const_iterator itr(&m_view);
@@ -214,6 +248,162 @@ variant_associative_view::const_iterator variant_associative_view::end() const
 /////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////////
 
+variant_associative_view::iterator::iterator(detail::variant_associative_view_private* view) RTTR_NOEXCEPT
+:   m_view(view)
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator::~iterator()
+{
+    m_view->destroy(m_itr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator::iterator(const iterator &other)
+:   m_view(other.m_view),
+    m_itr(other.m_itr)
+{
+    m_view->copy(m_itr, other.m_itr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator& variant_associative_view::iterator::operator=(iterator other)
+{
+    swap(other);
+    return *this;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void variant_associative_view::iterator::swap(iterator& other)
+{
+    std::swap(m_itr, other.m_itr);
+    std::swap(m_view, other.m_view);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+std::pair<variant, variant> variant_associative_view::iterator::operator*()
+{
+    return m_view->get_key_value(m_itr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+const variant variant_associative_view::iterator::get_key() const
+{
+    return m_view->get_key(m_itr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant variant_associative_view::iterator::get_value()
+{
+    return m_view->get_value(m_itr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator& variant_associative_view::iterator::operator++()
+{
+    m_view->advance(m_itr, 1);
+    return *this;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator variant_associative_view::iterator::operator++(int)
+{
+    iterator result(m_view);
+
+    m_view->copy(result.m_itr, m_itr);
+    m_view->advance(m_itr, 1);
+
+    return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator& variant_associative_view::iterator::operator--()
+{
+    m_view->advance(m_itr, -1);
+    return *this;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator variant_associative_view::iterator::operator--(int)
+{
+    iterator result(m_view);
+
+    m_view->copy(result.m_itr, m_itr);
+    m_view->advance(m_itr, -1);
+
+    return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator& variant_associative_view::iterator::operator+=(int i)
+{
+    m_view->advance(m_itr, i);
+    return *this;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator& variant_associative_view::iterator::operator-=(int i)
+{
+    m_view->advance(m_itr, -i);
+    return *this;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator variant_associative_view::iterator::operator+(int i) const
+{
+    iterator result(m_view);
+
+    m_view->copy(result.m_itr, m_itr);
+    result.m_view->advance(result.m_itr, i);
+
+    return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+variant_associative_view::iterator variant_associative_view::iterator::operator-(int i) const
+{
+    iterator result(m_view);
+
+    m_view->copy(result.m_itr, m_itr);
+    result.m_view->advance(result.m_itr, -i);
+
+    return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool variant_associative_view::iterator::operator==(const iterator& other) const
+{
+    return m_view->equal(m_itr, other.m_itr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool variant_associative_view::iterator::operator!=(const iterator& other) const
+{
+    return !m_view->equal(m_itr, other.m_itr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
 variant_associative_view::const_iterator::const_iterator(const detail::variant_associative_view_private* view) RTTR_NOEXCEPT
 :   m_view(view)
 {
diff --git a/src/rttr/variant_associative_view.h b/src/rttr/variant_associative_view.h
index 44029ee3..a777108e 100644
--- a/src/rttr/variant_associative_view.h
+++ b/src/rttr/variant_associative_view.h
@@ -92,6 +92,7 @@ namespace rttr
 class RTTR_API variant_associative_view
 {
     public:
+        class iterator;
         class const_iterator;
 
         /*!
@@ -217,7 +218,14 @@ class RTTR_API variant_associative_view
          *
          * \return The element with key equivalent to \p key. If no element is found an invalid iterator is returned.
          */
-        const_iterator find(argument key);
+        iterator find(argument key);
+
+        /*!
+         * \brief Finds an element with specific key \p key .
+         *
+         * \return The element with key equivalent to \p key. If no element is found an invalid iterator is returned.
+         */
+        const_iterator find(argument key) const;
 
         /*!
          * \brief Removes the element (if one exists) with the key equivalent to \p key.
@@ -276,6 +284,15 @@ class RTTR_API variant_associative_view
          *
          * \return Iterator to the first element .
          */
+        iterator begin();
+
+        /*!
+         * \brief Returns a const_iterator to the first element of the container.
+         *
+         * \see end()
+         *
+         * \return Iterator to the first element .
+         */
         const_iterator begin() const;
 
         /*!
@@ -285,8 +302,144 @@ class RTTR_API variant_associative_view
          *
          * \return Iterator to the element following the last element.
          */
+        iterator end();
+
+        /*!
+         * \brief Returns a const_iterator to the element following the last element of the container.
+         *
+         * \see begin()
+         *
+         * \return Iterator to the element following the last element.
+         */
         const_iterator end() const;
 
+        /*!
+         * The \ref variant_associative_view::iterator allows iteration over an associative container in a variant.
+         * An instance can only be created by a non-const variant_associative_view.
+         * 
+         * \see variant_associative_view::const_iterator
+         */
+        class RTTR_API iterator
+        {
+            public:
+                using self_type = iterator;
+                using value_type = variant;
+
+                /*!
+                 * \brief Destroys the variant_associative_view::iterator
+                 */
+                ~iterator();
+
+                /*!
+                 * \brief Creates a copy of \p other
+                 */
+                iterator(const iterator& other);
+
+                 /*!
+                 * \brief Assigns \p other to `this`.
+                 */
+                iterator& operator=(iterator other);
+
+                /*!
+                 * Returns the underlying key and value stored in a `std::pair<key, value>`.
+                 * The actual data in the variant is stored inside a `std::reference_wrapper<T>`
+                 *
+                 * \see variant::extract_wrapped_value(), variant::get_wrapped_value<T>()
+                 */
+                std::pair<variant, variant> operator*();
+
+                /*!
+                 * \brief Returns the current key, stored inside a `std::reference_wrapper<T>`
+                 *        and copied to a variant.
+                 *
+                 * \see variant::extract_wrapped_value(), variant::get_wrapped_value<T>()
+                 */
+                const variant get_key() const;
+
+                /*!
+                 * \brief Returns the current value, stored inside a `std::reference_wrapper<T>`
+                 *        and copied to a variant.
+                 *
+                 * \see variant::extract_wrapped_value(), variant::get_wrapped_value<T>()
+                 */
+                variant get_value();
+
+                /*!
+                 * \brief Pre-increment operator advances the iterator to the next item
+                 *        in the container and returns an iterator to the new current item.
+                 *
+                 * \remark Calling this function on and iterator with value variant_associative_view::end()
+                 *         leads to undefined behaviour.
+                 */
+                iterator &operator++();
+
+                /*!
+                 * \brief Post-increment operator advances the iterator to the next item
+                 *        in the container and returns an iterator to the previously current item.
+                 */
+                iterator operator++(int);
+
+                /*!
+                 * \brief Pre-decrement operator makes the preceding item current and returns
+                 *        an iterator to the new current item.
+                 *
+                 * \remark Calling this function on and iterator with value variant_associative_view::begin()
+                 *         leads to undefined behaviour.
+                 */
+                iterator &operator--();
+
+                /*!
+                 * \brief Post-decrement operator makes the preceding item current
+                 *        and returns an iterator to the previously current item.
+                 */
+                iterator operator--(int);
+
+                /*!
+                 * \brief Advances the iterator by i items.
+                 */
+                iterator &operator+=(int i);
+
+                /*!
+                 * \brief Returns an iterator to the item at i positions backward from this iterator.
+                 */
+                iterator &operator-=(int i);
+
+                /*!
+                 * \brief Returns an iterator to the item at i positions forward from this iterator.
+                 */
+                iterator operator+(int i) const;
+
+                /*!
+                 * \brief Returns an iterator to the item at i positions backward from this iterator.
+                 */
+                iterator operator-(int i) const;
+
+                /*!
+                 * \brief Returns `true` if \p other points to the same item
+                 *        as this iterator; otherwise returns false.
+                 *
+                 * \see \ref iterator::operator!= "operator!="
+                 */
+                bool operator==(const iterator& other) const;
+
+                /*!
+                 * \brief Returns true if \p other points to a different item
+                 *        than this iterator; otherwise returns false.
+                 *
+                 * \see \ref operator== "operator=="
+                 */
+                bool operator!=(const iterator& other) const;
+
+            private:
+                iterator(detail::variant_associative_view_private* view) RTTR_NOEXCEPT;
+                void swap(iterator& other);
+
+                friend class variant_associative_view;
+
+                detail::variant_associative_view_private* m_view;
+                detail::iterator_data m_itr;
+        };
+
         /*!
          * The \ref variant_associative_view::const_iterator allows iteration over an associative container in a variant.
          * An instance can only be created by an variant_associative_view.