/src/immer/immer/detail/iterator_facade.hpp
Line | Count | Source |
1 | | // |
2 | | // immer: immutable data structures for C++ |
3 | | // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente |
4 | | // |
5 | | // This software is distributed under the Boost Software License, Version 1.0. |
6 | | // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt |
7 | | // |
8 | | |
9 | | #pragma once |
10 | | |
11 | | #include <cstddef> |
12 | | #include <iterator> |
13 | | #include <type_traits> |
14 | | |
15 | | namespace immer { |
16 | | namespace detail { |
17 | | |
18 | | struct iterator_core_access |
19 | | { |
20 | | template <typename T> |
21 | | static decltype(auto) dereference(T&& x) |
22 | 354k | { |
23 | 354k | return x.dereference(); |
24 | 354k | } |
25 | | |
26 | | template <typename T> |
27 | | static decltype(auto) increment(T&& x) |
28 | 354k | { |
29 | 354k | return x.increment(); |
30 | 354k | } |
31 | | |
32 | | template <typename T> |
33 | | static decltype(auto) decrement(T&& x) |
34 | | { |
35 | | return x.decrement(); |
36 | | } |
37 | | |
38 | | template <typename T1, typename T2> |
39 | | static decltype(auto) equal(T1&& x1, T2&& x2) |
40 | 363k | { |
41 | 363k | return x1.equal(x2); |
42 | 363k | } |
43 | | |
44 | | template <typename T, typename D> |
45 | | static decltype(auto) advance(T&& x, D d) |
46 | | { |
47 | | return x.advance(d); |
48 | | } |
49 | | |
50 | | template <typename T1, typename T2> |
51 | | static decltype(auto) distance_to(T1&& x1, T2&& x2) |
52 | | { |
53 | | return x1.distance_to(x2); |
54 | | } |
55 | | }; |
56 | | |
57 | | /*! |
58 | | * Minimalistic reimplementation of boost::iterator_facade |
59 | | */ |
60 | | template <typename DerivedT, |
61 | | typename IteratorCategoryT, |
62 | | typename T, |
63 | | typename ReferenceT = T&, |
64 | | typename DifferenceTypeT = std::ptrdiff_t, |
65 | | typename PointerT = T*> |
66 | | class iterator_facade |
67 | | { |
68 | | public: |
69 | | using iterator_category = IteratorCategoryT; |
70 | | using value_type = T; |
71 | | using difference_type = DifferenceTypeT; |
72 | | using pointer = PointerT; |
73 | | using reference = ReferenceT; |
74 | | |
75 | | protected: |
76 | | using access_t = iterator_core_access; |
77 | | |
78 | | constexpr static auto is_random_access = |
79 | | std::is_base_of<std::random_access_iterator_tag, |
80 | | IteratorCategoryT>::value; |
81 | | constexpr static auto is_bidirectional = |
82 | | std::is_base_of<std::bidirectional_iterator_tag, |
83 | | IteratorCategoryT>::value; |
84 | | |
85 | | const DerivedT& derived() const |
86 | 354k | { |
87 | 354k | static_assert(std::is_base_of<iterator_facade, DerivedT>::value, |
88 | 354k | "must pass a derived thing"); |
89 | 354k | return *static_cast<const DerivedT*>(this); |
90 | 354k | } |
91 | | DerivedT& derived() |
92 | 708k | { |
93 | 708k | static_assert(std::is_base_of<iterator_facade, DerivedT>::value, |
94 | 708k | "must pass a derived thing"); |
95 | 708k | return *static_cast<DerivedT*>(this); |
96 | 708k | } |
97 | | |
98 | | public: |
99 | 354k | ReferenceT operator*() const { return access_t::dereference(derived()); } |
100 | | PointerT operator->() const { return &access_t::dereference(derived()); } |
101 | | |
102 | | template <typename U = iterator_facade, |
103 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
104 | | ReferenceT operator[](DifferenceTypeT n) const |
105 | | { |
106 | | return *(derived() + n); |
107 | | } |
108 | | |
109 | | friend bool operator==(const DerivedT& a, const DerivedT& b) |
110 | | { |
111 | | return access_t::equal(a, b); |
112 | | } |
113 | | friend bool operator!=(const DerivedT& a, const DerivedT& b) |
114 | 363k | { |
115 | 363k | return !access_t::equal(a, b); |
116 | 363k | } |
117 | | |
118 | | DerivedT& operator++() |
119 | 354k | { |
120 | 354k | access_t::increment(derived()); |
121 | 354k | return derived(); |
122 | 354k | } |
123 | | DerivedT operator++(int) |
124 | | { |
125 | | auto tmp = derived(); |
126 | | access_t::increment(derived()); |
127 | | return tmp; |
128 | | } |
129 | | |
130 | | template < |
131 | | typename U = iterator_facade, |
132 | | typename std::enable_if_t<U::is_bidirectional || U::is_random_access, |
133 | | bool> = true> |
134 | | DerivedT& operator--() |
135 | | { |
136 | | access_t::decrement(derived()); |
137 | | return derived(); |
138 | | } |
139 | | template < |
140 | | typename U = iterator_facade, |
141 | | typename std::enable_if_t<U::is_bidirectional || U::is_random_access, |
142 | | bool> = true> |
143 | | DerivedT operator--(int) |
144 | | { |
145 | | auto tmp = derived(); |
146 | | access_t::decrement(derived()); |
147 | | return tmp; |
148 | | } |
149 | | |
150 | | DerivedT& operator+=(DifferenceTypeT n) |
151 | | { |
152 | | access_t::advance(derived(), n); |
153 | | return derived(); |
154 | | } |
155 | | DerivedT& operator-=(DifferenceTypeT n) |
156 | | { |
157 | | access_t::advance(derived(), -n); |
158 | | return derived(); |
159 | | } |
160 | | |
161 | | template <typename U = iterator_facade, |
162 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
163 | | DerivedT operator+(DifferenceTypeT n) const |
164 | | { |
165 | | auto tmp = derived(); |
166 | | return tmp += n; |
167 | | } |
168 | | template <typename U = iterator_facade, |
169 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
170 | | friend DerivedT operator+(DifferenceTypeT n, const DerivedT& i) |
171 | | { |
172 | | return i + n; |
173 | | } |
174 | | template <typename U = iterator_facade, |
175 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
176 | | DerivedT operator-(DifferenceTypeT n) const |
177 | | { |
178 | | auto tmp = derived(); |
179 | | return tmp -= n; |
180 | | } |
181 | | |
182 | | template <typename U = iterator_facade, |
183 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
184 | | friend DifferenceTypeT operator-(const DerivedT& a, const DerivedT& b) |
185 | | { |
186 | | return access_t::distance_to(b, a); |
187 | | } |
188 | | |
189 | | template <typename U = iterator_facade, |
190 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
191 | | friend bool operator<(const DerivedT& a, const DerivedT& b) |
192 | | |
193 | | { |
194 | | return access_t::distance_to(a, b) > 0; |
195 | | } |
196 | | template <typename U = iterator_facade, |
197 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
198 | | friend bool operator<=(const DerivedT& a, const DerivedT& b) |
199 | | { |
200 | | return access_t::distance_to(a, b) >= 0; |
201 | | } |
202 | | template <typename U = iterator_facade, |
203 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
204 | | friend bool operator>(const DerivedT& a, const DerivedT& b) |
205 | | |
206 | | { |
207 | | return access_t::distance_to(a, b) < 0; |
208 | | } |
209 | | template <typename U = iterator_facade, |
210 | | typename std::enable_if_t<U::is_random_access, bool> = true> |
211 | | friend bool operator>=(const DerivedT& a, const DerivedT& b) |
212 | | { |
213 | | return access_t::distance_to(a, b) <= 0; |
214 | | } |
215 | | }; |
216 | | |
217 | | } // namespace detail |
218 | | } // namespace immer |