Line data Source code
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 350173 : static decltype(auto) dereference(T&& x)
22 : {
23 350173 : return x.dereference();
24 : }
25 :
26 : template <typename T>
27 350082 : static decltype(auto) increment(T&& x)
28 : {
29 350082 : return x.increment();
30 : }
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 429438 : static decltype(auto) equal(T1&& x1, T2&& x2)
40 : {
41 429438 : return x1.equal(x2);
42 : }
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 : class reference_proxy
86 : {
87 : friend iterator_facade;
88 : DerivedT iter_;
89 :
90 : reference_proxy(DerivedT iter)
91 : : iter_{std::move(iter)}
92 : {}
93 :
94 : public:
95 : operator ReferenceT() const { return *iter_; }
96 : };
97 :
98 350173 : const DerivedT& derived() const
99 : {
100 : static_assert(std::is_base_of<iterator_facade, DerivedT>::value,
101 : "must pass a derived thing");
102 : return *static_cast<const DerivedT*>(this);
103 : }
104 350082 : DerivedT& derived()
105 : {
106 : static_assert(std::is_base_of<iterator_facade, DerivedT>::value,
107 : "must pass a derived thing");
108 : return *static_cast<DerivedT*>(this);
109 : }
110 :
111 : public:
112 350173 : ReferenceT operator*() const { return access_t::dereference(derived()); }
113 : PointerT operator->() const { return &access_t::dereference(derived()); }
114 : reference_proxy operator[](DifferenceTypeT n) const
115 : {
116 : static_assert(is_random_access, "");
117 : return derived() + n;
118 : }
119 :
120 : friend bool operator==(const DerivedT& a, const DerivedT& b)
121 : {
122 : return access_t::equal(a, b);
123 : }
124 429438 : friend bool operator!=(const DerivedT& a, const DerivedT& b)
125 : {
126 429438 : return !access_t::equal(a, b);
127 : }
128 :
129 350082 : DerivedT& operator++()
130 : {
131 350082 : access_t::increment(derived());
132 350082 : return derived();
133 : }
134 : DerivedT operator++(int)
135 : {
136 : auto tmp = derived();
137 : access_t::increment(derived());
138 : return tmp;
139 : }
140 :
141 : DerivedT& operator--()
142 : {
143 : static_assert(is_bidirectional || is_random_access, "");
144 : access_t::decrement(derived());
145 : return derived();
146 : }
147 : DerivedT operator--(int)
148 : {
149 : static_assert(is_bidirectional || is_random_access, "");
150 : auto tmp = derived();
151 : access_t::decrement(derived());
152 : return tmp;
153 : }
154 :
155 : DerivedT& operator+=(DifferenceTypeT n)
156 : {
157 : access_t::advance(derived(), n);
158 : return derived();
159 : }
160 : DerivedT& operator-=(DifferenceTypeT n)
161 : {
162 : access_t::advance(derived(), -n);
163 : return derived();
164 : }
165 :
166 : DerivedT operator+(DifferenceTypeT n) const
167 : {
168 : static_assert(is_random_access, "");
169 : auto tmp = derived();
170 : return tmp += n;
171 : }
172 : friend DerivedT operator+(DifferenceTypeT n, const DerivedT& i)
173 : {
174 : static_assert(is_random_access, "");
175 : return i + n;
176 : }
177 : DerivedT operator-(DifferenceTypeT n) const
178 : {
179 : static_assert(is_random_access, "");
180 : auto tmp = derived();
181 : return tmp -= n;
182 : }
183 : friend DifferenceTypeT operator-(const DerivedT& a, const DerivedT& b)
184 : {
185 : static_assert(is_random_access, "");
186 : return access_t::distance_to(b, a);
187 : }
188 :
189 : friend bool operator<(const DerivedT& a, const DerivedT& b)
190 : {
191 : static_assert(is_random_access, "");
192 : return access_t::distance_to(a, b) > 0;
193 : }
194 : friend bool operator<=(const DerivedT& a, const DerivedT& b)
195 : {
196 : static_assert(is_random_access, "");
197 : return access_t::distance_to(a, b) >= 0;
198 : }
199 : friend bool operator>(const DerivedT& a, const DerivedT& b)
200 : {
201 : static_assert(is_random_access, "");
202 : return access_t::distance_to(a, b) < 0;
203 : }
204 : friend bool operator>=(const DerivedT& a, const DerivedT& b)
205 : {
206 : static_assert(is_random_access, "");
207 : return access_t::distance_to(a, b) <= 0;
208 : }
209 : };
210 :
211 : } // namespace detail
212 : } // namespace immer
|