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 | { return x.dereference(); } |
23 | |
24 | template <typename T> |
25 | static decltype(auto) increment(T&& x) |
26 | { return x.increment(); } |
27 | |
28 | template <typename T> |
29 | static decltype(auto) decrement(T&& x) |
30 | { return x.decrement(); } |
31 | |
32 | template <typename T1, typename T2> |
33 | static decltype(auto) equal(T1&& x1, T2&& x2) |
34 | { return x1.equal(x2); } |
35 | |
36 | template <typename T, typename D> |
37 | static decltype(auto) advance(T&& x, D d) |
38 | { return x.advance(d); } |
39 | |
40 | template <typename T1, typename T2> |
41 | static decltype(auto) distance_to(T1&& x1, T2&& x2) |
42 | { return x1.distance_to(x2); } |
43 | }; |
44 | |
45 | /*! |
46 | * Minimalistic reimplementation of boost::iterator_facade |
47 | */ |
48 | template <typename DerivedT, |
49 | typename IteratorCategoryT, |
50 | typename T, |
51 | typename ReferenceT = T&, |
52 | typename DifferenceTypeT = std::ptrdiff_t, |
53 | typename PointerT = T*> |
54 | class iterator_facade |
55 | : public std::iterator<IteratorCategoryT, |
56 | T, |
57 | DifferenceTypeT, |
58 | PointerT, |
59 | ReferenceT> |
60 | { |
61 | protected: |
62 | using access_t = iterator_core_access; |
63 | |
64 | constexpr static auto is_random_access = |
65 | std::is_base_of<std::random_access_iterator_tag, |
66 | IteratorCategoryT>::value; |
67 | constexpr static auto is_bidirectional = |
68 | std::is_base_of<std::bidirectional_iterator_tag, |
69 | IteratorCategoryT>::value; |
70 | |
71 | class reference_proxy |
72 | { |
73 | friend iterator_facade; |
74 | DerivedT iter_; |
75 | |
76 | reference_proxy(DerivedT iter) |
77 | : iter_{std::move(iter)} {} |
78 | public: |
79 | operator ReferenceT() const { return *iter_; } |
80 | }; |
81 | |
82 | const DerivedT& derived() const |
83 | { |
84 | static_assert(std::is_base_of<iterator_facade, DerivedT>::value, |
85 | "must pass a derived thing" ); |
86 | return *static_cast<const DerivedT*>(this); |
87 | } |
88 | DerivedT& derived() |
89 | { |
90 | static_assert(std::is_base_of<iterator_facade, DerivedT>::value, |
91 | "must pass a derived thing" ); |
92 | return *static_cast<DerivedT*>(this); |
93 | } |
94 | |
95 | public: |
96 | ReferenceT operator*() const |
97 | { |
98 | return access_t::dereference(derived()); |
99 | } |
100 | PointerT operator->() const |
101 | { |
102 | return &access_t::dereference(derived()); |
103 | } |
104 | reference_proxy operator[](DifferenceTypeT n) const |
105 | { |
106 | static_assert(is_random_access, "" ); |
107 | return derived() + n; |
108 | } |
109 | |
110 | bool operator==(const DerivedT& rhs) const |
111 | { |
112 | return access_t::equal(derived(), rhs); |
113 | } |
114 | bool operator!=(const DerivedT& rhs) const |
115 | { |
116 | return !access_t::equal(derived(), rhs); |
117 | } |
118 | |
119 | DerivedT& operator++() |
120 | { |
121 | access_t::increment(derived()); |
122 | return derived(); |
123 | } |
124 | DerivedT operator++(int) |
125 | { |
126 | auto tmp = derived(); |
127 | access_t::increment(derived()); |
128 | return tmp; |
129 | } |
130 | |
131 | DerivedT& operator--() |
132 | { |
133 | static_assert(is_bidirectional || is_random_access, "" ); |
134 | access_t::decrement(derived()); |
135 | return derived(); |
136 | } |
137 | DerivedT operator--(int) |
138 | { |
139 | static_assert(is_bidirectional || is_random_access, "" ); |
140 | auto tmp = derived(); |
141 | access_t::decrement(derived()); |
142 | return tmp; |
143 | } |
144 | |
145 | DerivedT& operator+=(DifferenceTypeT n) |
146 | { |
147 | access_t::advance(derived(), n); |
148 | return derived(); |
149 | } |
150 | DerivedT& operator-=(DifferenceTypeT n) |
151 | { |
152 | access_t::advance(derived(), -n); |
153 | return derived(); |
154 | } |
155 | |
156 | DerivedT operator+(DifferenceTypeT n) const |
157 | { |
158 | static_assert(is_random_access, "" ); |
159 | auto tmp = derived(); |
160 | return tmp += n; |
161 | } |
162 | friend DerivedT operator+(DifferenceTypeT n, const DerivedT& i) |
163 | { |
164 | static_assert(is_random_access, "" ); |
165 | return i + n; |
166 | } |
167 | DerivedT operator-(DifferenceTypeT n) const |
168 | { |
169 | static_assert(is_random_access, "" ); |
170 | auto tmp = derived(); |
171 | return tmp -= n; |
172 | } |
173 | DifferenceTypeT operator-(const DerivedT& rhs) const |
174 | { |
175 | static_assert(is_random_access, "" ); |
176 | return access_t::distance_to(rhs, derived()); |
177 | } |
178 | |
179 | bool operator<(const DerivedT& rhs) const |
180 | { |
181 | static_assert(is_random_access, "" ); |
182 | return access_t::distance_to(derived(), rhs) > 0; |
183 | } |
184 | bool operator<=(const DerivedT& rhs) const |
185 | { |
186 | static_assert(is_random_access, "" ); |
187 | return access_t::distance_to(derived(), rhs) >= 0; |
188 | } |
189 | bool operator>(const DerivedT& rhs) const |
190 | { |
191 | static_assert(is_random_access, "" ); |
192 | return access_t::distance_to(derived(), rhs) < 0; |
193 | } |
194 | bool operator>=(const DerivedT& rhs) const |
195 | { |
196 | static_assert(is_random_access, "" ); |
197 | return access_t::distance_to(derived(), rhs) <= 0; |
198 | } |
199 | }; |
200 | |
201 | } // namespace detail |
202 | } // namespace immer |
203 | |