Chris@16
|
1 // Boost.Range library
|
Chris@16
|
2 //
|
Chris@16
|
3 // Copyright Neil Groves 2007. Use, modification and
|
Chris@16
|
4 // distribution is subject to the Boost Software License, Version
|
Chris@16
|
5 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
7 //
|
Chris@16
|
8 //
|
Chris@16
|
9 // For more information, see http://www.boost.org/libs/range/
|
Chris@16
|
10 //
|
Chris@16
|
11 #ifndef BOOST_RANGE_ADAPTOR_STRIDED_HPP_INCLUDED
|
Chris@16
|
12 #define BOOST_RANGE_ADAPTOR_STRIDED_HPP_INCLUDED
|
Chris@16
|
13
|
Chris@16
|
14 #include <boost/range/adaptor/argument_fwd.hpp>
|
Chris@16
|
15 #include <boost/range/iterator_range.hpp>
|
Chris@16
|
16 #include <boost/iterator/iterator_adaptor.hpp>
|
Chris@16
|
17 #include <iterator>
|
Chris@16
|
18
|
Chris@16
|
19 namespace boost
|
Chris@16
|
20 {
|
Chris@16
|
21 namespace range_detail
|
Chris@16
|
22 {
|
Chris@16
|
23 // strided_iterator for wrapping a forward traversal iterator
|
Chris@16
|
24 template<class BaseIterator, class Category>
|
Chris@16
|
25 class strided_iterator
|
Chris@16
|
26 : public iterator_adaptor<
|
Chris@16
|
27 strided_iterator<BaseIterator, Category>
|
Chris@16
|
28 , BaseIterator
|
Chris@16
|
29 , use_default
|
Chris@16
|
30 , boost::forward_traversal_tag
|
Chris@16
|
31 >
|
Chris@16
|
32 {
|
Chris@16
|
33 friend class ::boost::iterator_core_access;
|
Chris@16
|
34
|
Chris@16
|
35 typedef iterator_adaptor<
|
Chris@16
|
36 strided_iterator<BaseIterator, Category>
|
Chris@16
|
37 , BaseIterator
|
Chris@16
|
38 , use_default
|
Chris@16
|
39 , boost::forward_traversal_tag
|
Chris@16
|
40 > super_t;
|
Chris@16
|
41
|
Chris@16
|
42 public:
|
Chris@16
|
43 typedef BOOST_DEDUCED_TYPENAME std::iterator_traits<BaseIterator>::difference_type difference_type;
|
Chris@16
|
44 typedef BaseIterator base_iterator;
|
Chris@16
|
45
|
Chris@16
|
46 strided_iterator()
|
Chris@16
|
47 : m_last()
|
Chris@16
|
48 , m_stride()
|
Chris@16
|
49 {
|
Chris@16
|
50 }
|
Chris@16
|
51
|
Chris@16
|
52 strided_iterator(base_iterator first, base_iterator it, base_iterator last, difference_type stride)
|
Chris@16
|
53 : super_t(it)
|
Chris@16
|
54 , m_last(last)
|
Chris@16
|
55 , m_stride(stride)
|
Chris@16
|
56 {
|
Chris@16
|
57 }
|
Chris@16
|
58
|
Chris@16
|
59 template<class OtherIterator>
|
Chris@16
|
60 strided_iterator(const strided_iterator<OtherIterator, Category>& other,
|
Chris@16
|
61 BOOST_DEDUCED_TYPENAME enable_if_convertible<OtherIterator, base_iterator>::type* = 0)
|
Chris@16
|
62 : super_t(other)
|
Chris@16
|
63 , m_last(other.base_end())
|
Chris@16
|
64 , m_stride(other.get_stride())
|
Chris@16
|
65 {
|
Chris@16
|
66 }
|
Chris@16
|
67
|
Chris@16
|
68 base_iterator base_end() const { return m_last; }
|
Chris@16
|
69 difference_type get_stride() const { return m_stride; }
|
Chris@16
|
70
|
Chris@16
|
71 private:
|
Chris@16
|
72 void increment()
|
Chris@16
|
73 {
|
Chris@16
|
74 base_iterator& it = this->base_reference();
|
Chris@16
|
75 for (difference_type i = 0; (it != m_last) && (i < m_stride); ++i)
|
Chris@16
|
76 ++it;
|
Chris@16
|
77 }
|
Chris@16
|
78
|
Chris@16
|
79 base_iterator m_last;
|
Chris@16
|
80 difference_type m_stride;
|
Chris@16
|
81 };
|
Chris@16
|
82
|
Chris@16
|
83 // strided_iterator for wrapping a bidirectional iterator
|
Chris@16
|
84 template<class BaseIterator>
|
Chris@16
|
85 class strided_iterator<BaseIterator, bidirectional_traversal_tag>
|
Chris@16
|
86 : public iterator_adaptor<
|
Chris@16
|
87 strided_iterator<BaseIterator, bidirectional_traversal_tag>
|
Chris@16
|
88 , BaseIterator
|
Chris@16
|
89 , use_default
|
Chris@16
|
90 , bidirectional_traversal_tag
|
Chris@16
|
91 >
|
Chris@16
|
92 {
|
Chris@16
|
93 friend class ::boost::iterator_core_access;
|
Chris@16
|
94
|
Chris@16
|
95 typedef iterator_adaptor<
|
Chris@16
|
96 strided_iterator<BaseIterator, bidirectional_traversal_tag>
|
Chris@16
|
97 , BaseIterator
|
Chris@16
|
98 , use_default
|
Chris@16
|
99 , bidirectional_traversal_tag
|
Chris@16
|
100 > super_t;
|
Chris@16
|
101 public:
|
Chris@16
|
102 typedef BOOST_DEDUCED_TYPENAME std::iterator_traits<BaseIterator>::difference_type difference_type;
|
Chris@16
|
103 typedef BaseIterator base_iterator;
|
Chris@16
|
104
|
Chris@16
|
105 strided_iterator()
|
Chris@16
|
106 : m_first()
|
Chris@16
|
107 , m_last()
|
Chris@16
|
108 , m_stride()
|
Chris@16
|
109 {
|
Chris@16
|
110 }
|
Chris@16
|
111
|
Chris@16
|
112 strided_iterator(base_iterator first, base_iterator it, base_iterator last, difference_type stride)
|
Chris@16
|
113 : super_t(it)
|
Chris@16
|
114 , m_first(first)
|
Chris@16
|
115 , m_last(last)
|
Chris@16
|
116 , m_stride(stride)
|
Chris@16
|
117 {
|
Chris@16
|
118 }
|
Chris@16
|
119
|
Chris@16
|
120 template<class OtherIterator>
|
Chris@16
|
121 strided_iterator(const strided_iterator<OtherIterator, bidirectional_traversal_tag>& other,
|
Chris@16
|
122 BOOST_DEDUCED_TYPENAME enable_if_convertible<OtherIterator, base_iterator>::type* = 0)
|
Chris@16
|
123 : super_t(other.base())
|
Chris@16
|
124 , m_first(other.base_begin())
|
Chris@16
|
125 , m_last(other.base_end())
|
Chris@16
|
126 , m_stride(other.get_stride())
|
Chris@16
|
127 {
|
Chris@16
|
128 }
|
Chris@16
|
129
|
Chris@16
|
130 base_iterator base_begin() const { return m_first; }
|
Chris@16
|
131 base_iterator base_end() const { return m_last; }
|
Chris@16
|
132 difference_type get_stride() const { return m_stride; }
|
Chris@16
|
133
|
Chris@16
|
134 private:
|
Chris@16
|
135 void increment()
|
Chris@16
|
136 {
|
Chris@16
|
137 base_iterator& it = this->base_reference();
|
Chris@16
|
138 for (difference_type i = 0; (it != m_last) && (i < m_stride); ++i)
|
Chris@16
|
139 ++it;
|
Chris@16
|
140 }
|
Chris@16
|
141
|
Chris@16
|
142 void decrement()
|
Chris@16
|
143 {
|
Chris@16
|
144 base_iterator& it = this->base_reference();
|
Chris@16
|
145 for (difference_type i = 0; (it != m_first) && (i < m_stride); ++i)
|
Chris@16
|
146 --it;
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 base_iterator m_first;
|
Chris@16
|
150 base_iterator m_last;
|
Chris@16
|
151 difference_type m_stride;
|
Chris@16
|
152 };
|
Chris@16
|
153
|
Chris@16
|
154 // strided_iterator implementation for wrapping a random access iterator
|
Chris@16
|
155 template<class BaseIterator>
|
Chris@16
|
156 class strided_iterator<BaseIterator, random_access_traversal_tag>
|
Chris@16
|
157 : public iterator_adaptor<
|
Chris@16
|
158 strided_iterator<BaseIterator, random_access_traversal_tag>
|
Chris@16
|
159 , BaseIterator
|
Chris@16
|
160 , use_default
|
Chris@16
|
161 , random_access_traversal_tag
|
Chris@16
|
162 >
|
Chris@16
|
163 {
|
Chris@16
|
164 friend class ::boost::iterator_core_access;
|
Chris@16
|
165
|
Chris@16
|
166 typedef iterator_adaptor<
|
Chris@16
|
167 strided_iterator<BaseIterator, random_access_traversal_tag>
|
Chris@16
|
168 , BaseIterator
|
Chris@16
|
169 , use_default
|
Chris@16
|
170 , random_access_traversal_tag
|
Chris@16
|
171 > super_t;
|
Chris@16
|
172 public:
|
Chris@16
|
173 typedef BOOST_DEDUCED_TYPENAME super_t::difference_type difference_type;
|
Chris@16
|
174 typedef BaseIterator base_iterator;
|
Chris@16
|
175
|
Chris@16
|
176 strided_iterator()
|
Chris@16
|
177 : m_first()
|
Chris@16
|
178 , m_last()
|
Chris@16
|
179 , m_index(0)
|
Chris@16
|
180 , m_stride()
|
Chris@16
|
181 {
|
Chris@16
|
182 }
|
Chris@16
|
183
|
Chris@16
|
184 strided_iterator(BaseIterator first, BaseIterator it, BaseIterator last, difference_type stride)
|
Chris@16
|
185 : super_t(it)
|
Chris@16
|
186 , m_first(first)
|
Chris@16
|
187 , m_last(last)
|
Chris@16
|
188 , m_index(stride ? (it - first) / stride : 0)
|
Chris@16
|
189 , m_stride(stride)
|
Chris@16
|
190 {
|
Chris@16
|
191 }
|
Chris@16
|
192
|
Chris@16
|
193 template<class OtherIterator>
|
Chris@16
|
194 strided_iterator(const strided_iterator<OtherIterator, random_access_traversal_tag>& other,
|
Chris@16
|
195 BOOST_DEDUCED_TYPENAME enable_if_convertible<OtherIterator, BaseIterator>::type* = 0)
|
Chris@16
|
196 : super_t(other.base())
|
Chris@16
|
197 , m_first(other.base_begin())
|
Chris@16
|
198 , m_last(other.base_end())
|
Chris@16
|
199 , m_index(other.get_index())
|
Chris@16
|
200 , m_stride(other.get_stride())
|
Chris@16
|
201 {
|
Chris@16
|
202 }
|
Chris@16
|
203
|
Chris@16
|
204 base_iterator base_begin() const { return m_first; }
|
Chris@16
|
205 base_iterator base_end() const { return m_last; }
|
Chris@16
|
206 difference_type get_stride() const { return m_stride; }
|
Chris@16
|
207 difference_type get_index() const { return m_index; }
|
Chris@16
|
208
|
Chris@16
|
209 private:
|
Chris@16
|
210 void increment()
|
Chris@16
|
211 {
|
Chris@16
|
212 m_index += m_stride;
|
Chris@16
|
213 if (m_index < (m_last - m_first))
|
Chris@16
|
214 this->base_reference() = m_first + m_index;
|
Chris@16
|
215 else
|
Chris@16
|
216 this->base_reference() = m_last;
|
Chris@16
|
217 }
|
Chris@16
|
218
|
Chris@16
|
219 void decrement()
|
Chris@16
|
220 {
|
Chris@16
|
221 m_index -= m_stride;
|
Chris@16
|
222 if (m_index >= 0)
|
Chris@16
|
223 this->base_reference() = m_first + m_index;
|
Chris@16
|
224 else
|
Chris@16
|
225 this->base_reference() = m_first;
|
Chris@16
|
226 }
|
Chris@16
|
227
|
Chris@16
|
228 void advance(difference_type offset)
|
Chris@16
|
229 {
|
Chris@16
|
230 offset *= m_stride;
|
Chris@16
|
231 m_index += offset;
|
Chris@16
|
232 if (m_index < 0)
|
Chris@16
|
233 this->base_reference() = m_first;
|
Chris@16
|
234 else if (m_index > (m_last - m_first))
|
Chris@16
|
235 this->base_reference() = m_last;
|
Chris@16
|
236 else
|
Chris@16
|
237 this->base_reference() = m_first + m_index;
|
Chris@16
|
238 }
|
Chris@16
|
239
|
Chris@16
|
240 template<class OtherIterator>
|
Chris@16
|
241 difference_type distance_to(const strided_iterator<OtherIterator, random_access_traversal_tag>& other,
|
Chris@16
|
242 BOOST_DEDUCED_TYPENAME enable_if_convertible<OtherIterator, BaseIterator>::type* = 0) const
|
Chris@16
|
243 {
|
Chris@16
|
244 if (other.base() >= this->base())
|
Chris@16
|
245 return (other.base() - this->base() + (m_stride - 1)) / m_stride;
|
Chris@16
|
246 return (other.base() - this->base() - (m_stride - 1)) / m_stride;
|
Chris@16
|
247 }
|
Chris@16
|
248
|
Chris@16
|
249 bool equal(const strided_iterator& other) const
|
Chris@16
|
250 {
|
Chris@16
|
251 return this->base() == other.base();
|
Chris@16
|
252 }
|
Chris@16
|
253
|
Chris@16
|
254 private:
|
Chris@16
|
255 base_iterator m_first;
|
Chris@16
|
256 base_iterator m_last;
|
Chris@16
|
257 difference_type m_index;
|
Chris@16
|
258 difference_type m_stride;
|
Chris@16
|
259 };
|
Chris@16
|
260
|
Chris@16
|
261 template<class BaseIterator, class Difference> inline
|
Chris@16
|
262 strided_iterator<BaseIterator, BOOST_DEDUCED_TYPENAME iterator_traversal<BaseIterator>::type>
|
Chris@16
|
263 make_strided_iterator(BaseIterator first, BaseIterator it,
|
Chris@16
|
264 BaseIterator last, Difference stride)
|
Chris@16
|
265 {
|
Chris@16
|
266 BOOST_ASSERT( stride >= 0 );
|
Chris@16
|
267 typedef BOOST_DEDUCED_TYPENAME iterator_traversal<BaseIterator>::type traversal_tag;
|
Chris@16
|
268 return strided_iterator<BaseIterator, traversal_tag>(first, it, last, stride);
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 template< class Rng
|
Chris@16
|
272 , class Category = BOOST_DEDUCED_TYPENAME iterator_traversal<
|
Chris@16
|
273 BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type
|
Chris@16
|
274 >::type
|
Chris@16
|
275 >
|
Chris@16
|
276 class strided_range
|
Chris@16
|
277 : public iterator_range<
|
Chris@16
|
278 range_detail::strided_iterator<
|
Chris@16
|
279 BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type,
|
Chris@16
|
280 Category
|
Chris@16
|
281 >
|
Chris@16
|
282 >
|
Chris@16
|
283 {
|
Chris@16
|
284 typedef range_detail::strided_iterator<
|
Chris@16
|
285 BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type,
|
Chris@16
|
286 Category
|
Chris@16
|
287 > iter_type;
|
Chris@16
|
288 typedef iterator_range<iter_type> super_t;
|
Chris@16
|
289 public:
|
Chris@16
|
290 template<class Difference>
|
Chris@16
|
291 strided_range(Difference stride, Rng& rng)
|
Chris@16
|
292 : super_t(make_strided_iterator(boost::begin(rng), boost::begin(rng), boost::end(rng), stride),
|
Chris@16
|
293 make_strided_iterator(boost::begin(rng), boost::end(rng), boost::end(rng), stride))
|
Chris@16
|
294 {
|
Chris@16
|
295 BOOST_ASSERT( stride >= 0 );
|
Chris@16
|
296 }
|
Chris@16
|
297 };
|
Chris@16
|
298
|
Chris@16
|
299 template<class Difference>
|
Chris@16
|
300 class strided_holder : public holder<Difference>
|
Chris@16
|
301 {
|
Chris@16
|
302 public:
|
Chris@16
|
303 explicit strided_holder(Difference value) : holder<Difference>(value) {}
|
Chris@16
|
304 };
|
Chris@16
|
305
|
Chris@16
|
306 template<class Rng, class Difference>
|
Chris@16
|
307 inline strided_range<Rng>
|
Chris@16
|
308 operator|(Rng& rng, const strided_holder<Difference>& stride)
|
Chris@16
|
309 {
|
Chris@16
|
310 return strided_range<Rng>(stride.val, rng);
|
Chris@16
|
311 }
|
Chris@16
|
312
|
Chris@16
|
313 template<class Rng, class Difference>
|
Chris@16
|
314 inline strided_range<const Rng>
|
Chris@16
|
315 operator|(const Rng& rng, const strided_holder<Difference>& stride)
|
Chris@16
|
316 {
|
Chris@16
|
317 return strided_range<const Rng>(stride.val, rng);
|
Chris@16
|
318 }
|
Chris@16
|
319
|
Chris@16
|
320 } // namespace range_detail
|
Chris@16
|
321
|
Chris@16
|
322 using range_detail::strided_range;
|
Chris@16
|
323
|
Chris@16
|
324 namespace adaptors
|
Chris@16
|
325 {
|
Chris@16
|
326
|
Chris@16
|
327 namespace
|
Chris@16
|
328 {
|
Chris@16
|
329 const range_detail::forwarder<range_detail::strided_holder>
|
Chris@16
|
330 strided = range_detail::forwarder<range_detail::strided_holder>();
|
Chris@16
|
331 }
|
Chris@16
|
332
|
Chris@16
|
333 template<class Range, class Difference>
|
Chris@16
|
334 inline strided_range<Range>
|
Chris@16
|
335 stride(Range& rng, Difference step)
|
Chris@16
|
336 {
|
Chris@16
|
337 return strided_range<Range>(step, rng);
|
Chris@16
|
338 }
|
Chris@16
|
339
|
Chris@16
|
340 template<class Range, class Difference>
|
Chris@16
|
341 inline strided_range<const Range>
|
Chris@16
|
342 stride(const Range& rng, Difference step)
|
Chris@16
|
343 {
|
Chris@16
|
344 return strided_range<const Range>(step, rng);
|
Chris@16
|
345 }
|
Chris@16
|
346
|
Chris@16
|
347 } // namespace 'adaptors'
|
Chris@16
|
348 } // namespace 'boost'
|
Chris@16
|
349
|
Chris@16
|
350 #endif
|