Chris@101
|
1 // Copyright 2014 Neil Groves
|
Chris@16
|
2 //
|
Chris@101
|
3 // Copyright (c) 2010 Ilya Murav'jov
|
Chris@101
|
4 //
|
Chris@101
|
5 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@101
|
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8 //
|
Chris@101
|
9 // Credits:
|
Chris@101
|
10 // My (Neil's) first indexed adaptor was hindered by having the underlying
|
Chris@101
|
11 // iterator return the same reference as the wrapped iterator. This meant that
|
Chris@101
|
12 // to obtain the index one had to get to the index_iterator and call the
|
Chris@101
|
13 // index() function on it. Ilya politely pointed out that this was useless in
|
Chris@101
|
14 // a number of scenarios since one naturally hides the use of iterators in
|
Chris@101
|
15 // good range-based code. Ilya provided a new interface (which has remained)
|
Chris@101
|
16 // and a first implementation. Much of this original implementation has
|
Chris@101
|
17 // been simplified and now supports more compilers and platforms.
|
Chris@16
|
18 //
|
Chris@101
|
19 #ifndef BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED
|
Chris@101
|
20 #define BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED
|
Chris@16
|
21
|
Chris@101
|
22 #include <boost/range/config.hpp>
|
Chris@16
|
23 #include <boost/range/adaptor/argument_fwd.hpp>
|
Chris@16
|
24 #include <boost/range/iterator_range.hpp>
|
Chris@101
|
25 #include <boost/range/traversal.hpp>
|
Chris@101
|
26 #include <boost/range/size.hpp>
|
Chris@16
|
27 #include <boost/range/begin.hpp>
|
Chris@16
|
28 #include <boost/range/end.hpp>
|
Chris@101
|
29 #include <boost/mpl/if.hpp>
|
Chris@101
|
30 #include <boost/type_traits/is_convertible.hpp>
|
Chris@16
|
31
|
Chris@101
|
32 #include <boost/iterator/iterator_traits.hpp>
|
Chris@101
|
33 #include <boost/iterator/iterator_facade.hpp>
|
Chris@16
|
34
|
Chris@101
|
35 #include <boost/tuple/tuple.hpp>
|
Chris@16
|
36
|
Chris@16
|
37 namespace boost
|
Chris@16
|
38 {
|
Chris@16
|
39 namespace adaptors
|
Chris@16
|
40 {
|
Chris@101
|
41
|
Chris@101
|
42 struct indexed
|
Chris@101
|
43 {
|
Chris@101
|
44 explicit indexed(std::ptrdiff_t x = 0)
|
Chris@101
|
45 : val(x)
|
Chris@101
|
46 {
|
Chris@101
|
47 }
|
Chris@101
|
48 std::ptrdiff_t val;
|
Chris@101
|
49 };
|
Chris@101
|
50
|
Chris@101
|
51 } // namespace adaptors
|
Chris@101
|
52
|
Chris@101
|
53 namespace range
|
Chris@101
|
54 {
|
Chris@101
|
55
|
Chris@101
|
56 // Why yet another "pair" class:
|
Chris@101
|
57 // - std::pair can't store references
|
Chris@101
|
58 // - no need for typing for index type (default to "std::ptrdiff_t"); this is
|
Chris@101
|
59 // useful in BOOST_FOREACH() expressions that have pitfalls with commas
|
Chris@101
|
60 // ( see http://www.boost.org/doc/libs/1_44_0/doc/html/foreach/pitfalls.html )
|
Chris@101
|
61 // - meaningful access functions index(), value()
|
Chris@101
|
62 template<class T, class Indexable = std::ptrdiff_t>
|
Chris@101
|
63 class index_value
|
Chris@101
|
64 : public tuple<Indexable, T>
|
Chris@101
|
65 {
|
Chris@101
|
66 typedef tuple<Indexable, T> base_t;
|
Chris@101
|
67
|
Chris@101
|
68 template<int N>
|
Chris@101
|
69 struct iv_types
|
Chris@101
|
70 {
|
Chris@101
|
71 typedef typename tuples::element<N, base_t>::type n_type;
|
Chris@101
|
72
|
Chris@101
|
73 typedef typename tuples::access_traits<n_type>::non_const_type non_const_type;
|
Chris@101
|
74 typedef typename tuples::access_traits<n_type>::const_type const_type;
|
Chris@101
|
75 };
|
Chris@101
|
76
|
Chris@101
|
77 public:
|
Chris@101
|
78 typedef typename iv_types<0>::non_const_type index_type;
|
Chris@101
|
79 typedef typename iv_types<0>::const_type const_index_type;
|
Chris@101
|
80 typedef typename iv_types<1>::non_const_type value_type;
|
Chris@101
|
81 typedef typename iv_types<1>::const_type const_value_type;
|
Chris@101
|
82
|
Chris@101
|
83 index_value()
|
Chris@101
|
84 {
|
Chris@16
|
85 }
|
Chris@16
|
86
|
Chris@101
|
87 index_value(typename tuples::access_traits<Indexable>::parameter_type t0,
|
Chris@101
|
88 typename tuples::access_traits<T>::parameter_type t1)
|
Chris@101
|
89 : base_t(t0, t1)
|
Chris@16
|
90 {
|
Chris@101
|
91 }
|
Chris@16
|
92
|
Chris@101
|
93 // member functions index(), value() (non-const and const)
|
Chris@101
|
94 index_type index()
|
Chris@101
|
95 {
|
Chris@101
|
96 return boost::tuples::get<0>(*this);
|
Chris@101
|
97 }
|
Chris@16
|
98
|
Chris@101
|
99 const_index_type index() const
|
Chris@101
|
100 {
|
Chris@101
|
101 return boost::tuples::get<0>(*this);
|
Chris@101
|
102 }
|
Chris@16
|
103
|
Chris@101
|
104 value_type value()
|
Chris@101
|
105 {
|
Chris@101
|
106 return boost::tuples::get<1>(*this);
|
Chris@101
|
107 }
|
Chris@16
|
108
|
Chris@101
|
109 const_value_type value() const
|
Chris@101
|
110 {
|
Chris@101
|
111 return boost::tuples::get<1>(*this);
|
Chris@101
|
112 }
|
Chris@101
|
113 };
|
Chris@16
|
114
|
Chris@101
|
115 } // namespace range
|
Chris@16
|
116
|
Chris@101
|
117 namespace range_detail
|
Chris@101
|
118 {
|
Chris@16
|
119
|
Chris@101
|
120 template<typename Iter>
|
Chris@101
|
121 struct indexed_iterator_value_type
|
Chris@101
|
122 {
|
Chris@101
|
123 typedef ::boost::range::index_value<
|
Chris@101
|
124 typename iterator_reference<Iter>::type,
|
Chris@101
|
125 typename iterator_difference<Iter>::type
|
Chris@101
|
126 > type;
|
Chris@101
|
127 };
|
Chris@16
|
128
|
Chris@101
|
129 // Meta-function to get the traversal for the range and therefore iterator
|
Chris@101
|
130 // returned by the indexed adaptor for a specified iterator type.
|
Chris@101
|
131 //
|
Chris@101
|
132 // Random access -> Random access
|
Chris@101
|
133 // Bidirectional -> Forward
|
Chris@101
|
134 // Forward -> Forward
|
Chris@101
|
135 // SinglePass -> SinglePass
|
Chris@101
|
136 //
|
Chris@101
|
137 // The rationale for demoting a Bidirectional input to Forward is that the end
|
Chris@101
|
138 // iterator cannot cheaply have an index computed for it. Therefore I chose to
|
Chris@101
|
139 // demote to forward traversal. I can maintain the ability to traverse randomly
|
Chris@101
|
140 // when the input is Random Access since the index for the end iterator is cheap
|
Chris@101
|
141 // to compute.
|
Chris@101
|
142 template<typename Iter>
|
Chris@101
|
143 struct indexed_traversal
|
Chris@101
|
144 {
|
Chris@101
|
145 private:
|
Chris@101
|
146 typedef typename iterator_traversal<Iter>::type wrapped_traversal;
|
Chris@16
|
147
|
Chris@101
|
148 public:
|
Chris@16
|
149
|
Chris@101
|
150 typedef typename mpl::if_<
|
Chris@101
|
151 is_convertible<wrapped_traversal, random_access_traversal_tag>,
|
Chris@101
|
152 random_access_traversal_tag,
|
Chris@101
|
153 typename mpl::if_<
|
Chris@101
|
154 is_convertible<wrapped_traversal, bidirectional_traversal_tag>,
|
Chris@101
|
155 forward_traversal_tag,
|
Chris@101
|
156 wrapped_traversal
|
Chris@101
|
157 >::type
|
Chris@101
|
158 >::type type;
|
Chris@101
|
159 };
|
Chris@16
|
160
|
Chris@101
|
161 template<typename Iter>
|
Chris@101
|
162 class indexed_iterator
|
Chris@101
|
163 : public iterator_facade<
|
Chris@101
|
164 indexed_iterator<Iter>,
|
Chris@101
|
165 typename indexed_iterator_value_type<Iter>::type,
|
Chris@101
|
166 typename indexed_traversal<Iter>::type,
|
Chris@101
|
167 typename indexed_iterator_value_type<Iter>::type,
|
Chris@101
|
168 typename iterator_difference<Iter>::type
|
Chris@101
|
169 >
|
Chris@101
|
170 {
|
Chris@101
|
171 public:
|
Chris@101
|
172 typedef Iter wrapped;
|
Chris@16
|
173
|
Chris@101
|
174 private:
|
Chris@101
|
175 typedef iterator_facade<
|
Chris@101
|
176 indexed_iterator<wrapped>,
|
Chris@101
|
177 typename indexed_iterator_value_type<wrapped>::type,
|
Chris@101
|
178 typename indexed_traversal<wrapped>::type,
|
Chris@101
|
179 typename indexed_iterator_value_type<wrapped>::type,
|
Chris@101
|
180 typename iterator_difference<wrapped>::type
|
Chris@101
|
181 > base_t;
|
Chris@101
|
182
|
Chris@101
|
183 public:
|
Chris@101
|
184 typedef typename base_t::difference_type difference_type;
|
Chris@101
|
185 typedef typename base_t::reference reference;
|
Chris@101
|
186 typedef typename base_t::difference_type index_type;
|
Chris@101
|
187
|
Chris@101
|
188 indexed_iterator()
|
Chris@101
|
189 : m_it()
|
Chris@101
|
190 , m_index()
|
Chris@101
|
191 {
|
Chris@101
|
192 }
|
Chris@101
|
193
|
Chris@101
|
194 template<typename OtherWrapped>
|
Chris@101
|
195 indexed_iterator(
|
Chris@101
|
196 const indexed_iterator<OtherWrapped>& other,
|
Chris@101
|
197 typename enable_if<is_convertible<OtherWrapped, wrapped> >::type* = 0
|
Chris@101
|
198 )
|
Chris@101
|
199 : m_it(other.get())
|
Chris@101
|
200 , m_index(other.get_index())
|
Chris@101
|
201 {
|
Chris@101
|
202 }
|
Chris@101
|
203
|
Chris@101
|
204 explicit indexed_iterator(wrapped it, index_type index)
|
Chris@101
|
205 : m_it(it)
|
Chris@101
|
206 , m_index(index)
|
Chris@101
|
207 {
|
Chris@101
|
208 }
|
Chris@101
|
209
|
Chris@101
|
210 wrapped get() const
|
Chris@101
|
211 {
|
Chris@101
|
212 return m_it;
|
Chris@101
|
213 }
|
Chris@101
|
214
|
Chris@101
|
215 index_type get_index() const
|
Chris@101
|
216 {
|
Chris@101
|
217 return m_index;
|
Chris@101
|
218 }
|
Chris@101
|
219
|
Chris@101
|
220 private:
|
Chris@101
|
221 friend class boost::iterator_core_access;
|
Chris@101
|
222
|
Chris@101
|
223 reference dereference() const
|
Chris@101
|
224 {
|
Chris@101
|
225 return reference(m_index, *m_it);
|
Chris@101
|
226 }
|
Chris@101
|
227
|
Chris@101
|
228 bool equal(const indexed_iterator& other) const
|
Chris@101
|
229 {
|
Chris@101
|
230 return m_it == other.m_it;
|
Chris@101
|
231 }
|
Chris@101
|
232
|
Chris@101
|
233 void increment()
|
Chris@101
|
234 {
|
Chris@101
|
235 ++m_index;
|
Chris@101
|
236 ++m_it;
|
Chris@101
|
237 }
|
Chris@101
|
238
|
Chris@101
|
239 void decrement()
|
Chris@101
|
240 {
|
Chris@101
|
241 BOOST_ASSERT_MSG(m_index > 0, "indexed Iterator out of bounds");
|
Chris@101
|
242 --m_index;
|
Chris@101
|
243 --m_it;
|
Chris@101
|
244 }
|
Chris@101
|
245
|
Chris@101
|
246 void advance(index_type n)
|
Chris@101
|
247 {
|
Chris@101
|
248 m_index += n;
|
Chris@101
|
249 BOOST_ASSERT_MSG(m_index >= 0, "indexed Iterator out of bounds");
|
Chris@101
|
250 m_it += n;
|
Chris@101
|
251 }
|
Chris@101
|
252
|
Chris@101
|
253 difference_type distance_to(const indexed_iterator& other) const
|
Chris@101
|
254 {
|
Chris@101
|
255 return other.m_it - m_it;
|
Chris@101
|
256 }
|
Chris@101
|
257
|
Chris@101
|
258 wrapped m_it;
|
Chris@101
|
259 index_type m_index;
|
Chris@101
|
260 };
|
Chris@101
|
261
|
Chris@101
|
262 template<typename SinglePassRange>
|
Chris@101
|
263 struct indexed_range
|
Chris@101
|
264 : iterator_range<
|
Chris@101
|
265 indexed_iterator<
|
Chris@101
|
266 typename range_iterator<SinglePassRange>::type
|
Chris@101
|
267 >
|
Chris@101
|
268 >
|
Chris@101
|
269 {
|
Chris@101
|
270 typedef iterator_range<
|
Chris@101
|
271 indexed_iterator<
|
Chris@101
|
272 typename range_iterator<SinglePassRange>::type
|
Chris@101
|
273 >
|
Chris@101
|
274 > base_t;
|
Chris@101
|
275
|
Chris@101
|
276 BOOST_RANGE_CONCEPT_ASSERT((
|
Chris@101
|
277 boost::SinglePassRangeConcept<SinglePassRange>));
|
Chris@101
|
278 public:
|
Chris@101
|
279 typedef indexed_iterator<
|
Chris@101
|
280 typename range_iterator<SinglePassRange>::type
|
Chris@101
|
281 > iterator;
|
Chris@101
|
282
|
Chris@101
|
283 // Constructor for non-random access iterators.
|
Chris@101
|
284 // This sets the end iterator index to i despite this being incorrect it
|
Chris@101
|
285 // is never observable since bidirectional iterators are demoted to
|
Chris@101
|
286 // forward iterators.
|
Chris@101
|
287 indexed_range(
|
Chris@101
|
288 typename base_t::difference_type i,
|
Chris@101
|
289 SinglePassRange& r,
|
Chris@101
|
290 single_pass_traversal_tag
|
Chris@101
|
291 )
|
Chris@101
|
292 : base_t(iterator(boost::begin(r), i),
|
Chris@101
|
293 iterator(boost::end(r), i))
|
Chris@101
|
294 {
|
Chris@101
|
295 }
|
Chris@101
|
296
|
Chris@101
|
297 indexed_range(
|
Chris@101
|
298 typename base_t::difference_type i,
|
Chris@101
|
299 SinglePassRange& r,
|
Chris@101
|
300 random_access_traversal_tag
|
Chris@101
|
301 )
|
Chris@101
|
302 : base_t(iterator(boost::begin(r), i),
|
Chris@101
|
303 iterator(boost::end(r), i + boost::size(r)))
|
Chris@101
|
304 {
|
Chris@101
|
305 }
|
Chris@101
|
306 };
|
Chris@101
|
307
|
Chris@101
|
308 } // namespace range_detail
|
Chris@101
|
309
|
Chris@16
|
310 using range_detail::indexed_range;
|
Chris@16
|
311
|
Chris@16
|
312 namespace adaptors
|
Chris@16
|
313 {
|
Chris@16
|
314
|
Chris@101
|
315 template<class SinglePassRange>
|
Chris@101
|
316 inline indexed_range<SinglePassRange>
|
Chris@101
|
317 operator|(SinglePassRange& r, indexed e)
|
Chris@101
|
318 {
|
Chris@101
|
319 BOOST_RANGE_CONCEPT_ASSERT((
|
Chris@101
|
320 boost::SinglePassRangeConcept<SinglePassRange>
|
Chris@101
|
321 ));
|
Chris@101
|
322 return indexed_range<SinglePassRange>(
|
Chris@101
|
323 e.val, r,
|
Chris@101
|
324 typename range_traversal<SinglePassRange>::type());
|
Chris@16
|
325 }
|
Chris@16
|
326
|
Chris@101
|
327 template<class SinglePassRange>
|
Chris@101
|
328 inline indexed_range<const SinglePassRange>
|
Chris@101
|
329 operator|(const SinglePassRange& r, indexed e)
|
Chris@101
|
330 {
|
Chris@101
|
331 BOOST_RANGE_CONCEPT_ASSERT((
|
Chris@101
|
332 boost::SinglePassRangeConcept<const SinglePassRange>
|
Chris@101
|
333 ));
|
Chris@101
|
334 return indexed_range<const SinglePassRange>(
|
Chris@101
|
335 e.val, r,
|
Chris@101
|
336 typename range_traversal<const SinglePassRange>::type());
|
Chris@101
|
337 }
|
Chris@16
|
338
|
Chris@101
|
339 template<class SinglePassRange>
|
Chris@101
|
340 inline indexed_range<SinglePassRange>
|
Chris@101
|
341 index(
|
Chris@101
|
342 SinglePassRange& rng,
|
Chris@101
|
343 typename range_difference<SinglePassRange>::type index_value = 0)
|
Chris@101
|
344 {
|
Chris@101
|
345 BOOST_RANGE_CONCEPT_ASSERT((
|
Chris@101
|
346 boost::SinglePassRangeConcept<SinglePassRange>
|
Chris@101
|
347 ));
|
Chris@101
|
348 return indexed_range<SinglePassRange>(
|
Chris@101
|
349 index_value, rng,
|
Chris@101
|
350 typename range_traversal<SinglePassRange>::type());
|
Chris@101
|
351 }
|
Chris@101
|
352
|
Chris@101
|
353 template<class SinglePassRange>
|
Chris@101
|
354 inline indexed_range<const SinglePassRange>
|
Chris@101
|
355 index(
|
Chris@101
|
356 const SinglePassRange& rng,
|
Chris@101
|
357 typename range_difference<const SinglePassRange>::type index_value = 0)
|
Chris@101
|
358 {
|
Chris@101
|
359 BOOST_RANGE_CONCEPT_ASSERT((
|
Chris@101
|
360 boost::SinglePassRangeConcept<SinglePassRange>
|
Chris@101
|
361 ));
|
Chris@101
|
362 return indexed_range<const SinglePassRange>(
|
Chris@101
|
363 index_value, rng,
|
Chris@101
|
364 typename range_traversal<const SinglePassRange>::type());
|
Chris@101
|
365 }
|
Chris@101
|
366
|
Chris@101
|
367 } // namespace adaptors
|
Chris@101
|
368 } // namespace boost
|
Chris@101
|
369
|
Chris@101
|
370 #endif // include guard
|