about summary refs log tree commit diff
path: root/immer/detail/iterator_facade.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'immer/detail/iterator_facade.hpp')
-rw-r--r--immer/detail/iterator_facade.hpp212
1 files changed, 212 insertions, 0 deletions
diff --git a/immer/detail/iterator_facade.hpp b/immer/detail/iterator_facade.hpp
new file mode 100644
index 000000000000..ffc237943e09
--- /dev/null
+++ b/immer/detail/iterator_facade.hpp
@@ -0,0 +1,212 @@
+//
+// immer: immutable data structures for C++
+// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
+//
+// This software is distributed under the Boost Software License, Version 1.0.
+// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
+//
+
+#pragma once
+
+#include <cstddef>
+#include <iterator>
+#include <type_traits>
+
+namespace immer {
+namespace detail {
+
+struct iterator_core_access
+{
+    template <typename T>
+    static decltype(auto) dereference(T&& x)
+    {
+        return x.dereference();
+    }
+
+    template <typename T>
+    static decltype(auto) increment(T&& x)
+    {
+        return x.increment();
+    }
+
+    template <typename T>
+    static decltype(auto) decrement(T&& x)
+    {
+        return x.decrement();
+    }
+
+    template <typename T1, typename T2>
+    static decltype(auto) equal(T1&& x1, T2&& x2)
+    {
+        return x1.equal(x2);
+    }
+
+    template <typename T, typename D>
+    static decltype(auto) advance(T&& x, D d)
+    {
+        return x.advance(d);
+    }
+
+    template <typename T1, typename T2>
+    static decltype(auto) distance_to(T1&& x1, T2&& x2)
+    {
+        return x1.distance_to(x2);
+    }
+};
+
+/*!
+ * Minimalistic reimplementation of boost::iterator_facade
+ */
+template <typename DerivedT,
+          typename IteratorCategoryT,
+          typename T,
+          typename ReferenceT      = T&,
+          typename DifferenceTypeT = std::ptrdiff_t,
+          typename PointerT        = T*>
+class iterator_facade
+{
+public:
+    using iterator_category = IteratorCategoryT;
+    using value_type        = T;
+    using difference_type   = DifferenceTypeT;
+    using pointer           = PointerT;
+    using reference         = ReferenceT;
+
+protected:
+    using access_t = iterator_core_access;
+
+    constexpr static auto is_random_access =
+        std::is_base_of<std::random_access_iterator_tag,
+                        IteratorCategoryT>::value;
+    constexpr static auto is_bidirectional =
+        std::is_base_of<std::bidirectional_iterator_tag,
+                        IteratorCategoryT>::value;
+
+    class reference_proxy
+    {
+        friend iterator_facade;
+        DerivedT iter_;
+
+        reference_proxy(DerivedT iter)
+            : iter_{std::move(iter)}
+        {}
+
+    public:
+        operator ReferenceT() const { return *iter_; }
+    };
+
+    const DerivedT& derived() const
+    {
+        static_assert(std::is_base_of<iterator_facade, DerivedT>::value,
+                      "must pass a derived thing");
+        return *static_cast<const DerivedT*>(this);
+    }
+    DerivedT& derived()
+    {
+        static_assert(std::is_base_of<iterator_facade, DerivedT>::value,
+                      "must pass a derived thing");
+        return *static_cast<DerivedT*>(this);
+    }
+
+public:
+    ReferenceT operator*() const { return access_t::dereference(derived()); }
+    PointerT operator->() const { return &access_t::dereference(derived()); }
+    reference_proxy operator[](DifferenceTypeT n) const
+    {
+        static_assert(is_random_access, "");
+        return derived() + n;
+    }
+
+    bool operator==(const DerivedT& rhs) const
+    {
+        return access_t::equal(derived(), rhs);
+    }
+    bool operator!=(const DerivedT& rhs) const
+    {
+        return !access_t::equal(derived(), rhs);
+    }
+
+    DerivedT& operator++()
+    {
+        access_t::increment(derived());
+        return derived();
+    }
+    DerivedT operator++(int)
+    {
+        auto tmp = derived();
+        access_t::increment(derived());
+        return tmp;
+    }
+
+    DerivedT& operator--()
+    {
+        static_assert(is_bidirectional || is_random_access, "");
+        access_t::decrement(derived());
+        return derived();
+    }
+    DerivedT operator--(int)
+    {
+        static_assert(is_bidirectional || is_random_access, "");
+        auto tmp = derived();
+        access_t::decrement(derived());
+        return tmp;
+    }
+
+    DerivedT& operator+=(DifferenceTypeT n)
+    {
+        access_t::advance(derived(), n);
+        return derived();
+    }
+    DerivedT& operator-=(DifferenceTypeT n)
+    {
+        access_t::advance(derived(), -n);
+        return derived();
+    }
+
+    DerivedT operator+(DifferenceTypeT n) const
+    {
+        static_assert(is_random_access, "");
+        auto tmp = derived();
+        return tmp += n;
+    }
+    friend DerivedT operator+(DifferenceTypeT n, const DerivedT& i)
+    {
+        static_assert(is_random_access, "");
+        return i + n;
+    }
+    DerivedT operator-(DifferenceTypeT n) const
+    {
+        static_assert(is_random_access, "");
+        auto tmp = derived();
+        return tmp -= n;
+    }
+    DifferenceTypeT operator-(const DerivedT& rhs) const
+    {
+        static_assert(is_random_access, "");
+        return access_t::distance_to(rhs, derived());
+    }
+
+    bool operator<(const DerivedT& rhs) const
+    {
+        static_assert(is_random_access, "");
+        return access_t::distance_to(derived(), rhs) > 0;
+    }
+    bool operator<=(const DerivedT& rhs) const
+    {
+        static_assert(is_random_access, "");
+        return access_t::distance_to(derived(), rhs) >= 0;
+    }
+    bool operator>(const DerivedT& rhs) const
+    {
+        static_assert(is_random_access, "");
+        return access_t::distance_to(derived(), rhs) < 0;
+    }
+    bool operator>=(const DerivedT& rhs) const
+    {
+        static_assert(is_random_access, "");
+        return access_t::distance_to(derived(), rhs) <= 0;
+    }
+};
+
+} // namespace detail
+} // namespace immer