Horizon
Loading...
Searching...
No Matches
counted_iterator.hpp
Go to the documentation of this file.
1
2// Range v3 library
3//
4// Copyright Eric Niebler 2014-present
5//
6// Use, modification and distribution is subject to the
7// Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10//
11// Project home: https://github.com/ericniebler/range-v3
12//
13#ifndef RANGES_V3_ITERATOR_COUNTED_ITERATOR_HPP
14#define RANGES_V3_ITERATOR_COUNTED_ITERATOR_HPP
15
16#include <utility>
17
18#include <meta/meta.hpp>
19
21
26
27#include <range/v3/detail/prologue.hpp>
28
29namespace ranges
30{
33
35 namespace _counted_iterator_
36 {
37 struct access
38 {
39 template<typename I>
40 static constexpr iter_difference_t<counted_iterator<I>> & count(
41 counted_iterator<I> & ci) noexcept
42 {
43 return ci.cnt_;
44 }
45
46 template<typename I>
47 static constexpr I & current(counted_iterator<I> & ci) noexcept
48 {
49 return ci.current_;
50 }
51
52 template<typename I>
53 static constexpr I const & current(counted_iterator<I> const & ci) noexcept
54 {
55 return ci.current_;
56 }
57 };
58
59 template<bool>
60 struct contiguous_iterator_concept_base
61 {};
62
63 template<>
64 struct contiguous_iterator_concept_base<true>
65 {
66 using iterator_concept = ranges::contiguous_iterator_tag;
67 };
68 } // namespace _counted_iterator_
70
71 template<typename I>
72 // requires input_or_output_iterator<I>
73 struct counted_iterator
74 : _counted_iterator_::contiguous_iterator_concept_base<(bool)contiguous_iterator<I>>
75 {
76 private:
77 friend advance_fn;
78 CPP_assert(input_or_output_iterator<I>);
79 friend _counted_iterator_::access;
80
81 I current_{};
82 iter_difference_t<I> cnt_{0};
83
84 constexpr void post_increment_(std::true_type)
85 {
86 CPP_assert(std::is_void<decltype(current_++)>());
87 ++current_;
88 --cnt_;
89 }
90 constexpr auto post_increment_(std::false_type) -> decltype(current_++)
91 {
92 CPP_assert(!std::is_void<decltype(current_++)>());
93 auto && tmp = current_++;
94 --cnt_;
95 return static_cast<decltype(tmp) &&>(tmp);
96 }
97
98 public:
99 using iterator_type = I;
100 using difference_type = iter_difference_t<I>;
101
102 counted_iterator() = default;
103
104 constexpr counted_iterator(I x, iter_difference_t<I> n)
105 : current_(std::move(x))
106 , cnt_(n)
107 {
108 RANGES_EXPECT(n >= 0);
109 }
110
111 template(typename I2)(
112 requires convertible_to<I2, I>)
113 constexpr counted_iterator(counted_iterator<I2> const & i)
114 : current_(_counted_iterator_::access::current(i))
115 , cnt_(i.count())
116 {}
117
118 template(typename I2)(
119 requires convertible_to<I2, I>)
120 constexpr counted_iterator & operator=(counted_iterator<I2> const & i)
121 {
122 current_ = _counted_iterator_::access::current(i);
123 cnt_ = i.count();
124 }
125
126 constexpr I base() const
127 {
128 return current_;
129 }
130
131 constexpr iter_difference_t<I> count() const
132 {
133 return cnt_;
134 }
135
136 constexpr iter_reference_t<I> operator*() noexcept(
137 noexcept(iter_reference_t<I>(*current_)))
138 {
139 RANGES_EXPECT(cnt_ > 0);
140 return *current_;
141 }
142 template(typename I2 = I)(
143 requires indirectly_readable<I2 const>)
144 constexpr iter_reference_t<I2> operator*() const //
145 noexcept(noexcept(iter_reference_t<I>(*current_)))
146 {
147 RANGES_EXPECT(cnt_ > 0);
148 return *current_;
149 }
150
151 constexpr counted_iterator & operator++()
152 {
153 RANGES_EXPECT(cnt_ > 0);
154 ++current_;
155 --cnt_;
156 return *this;
157 }
158
159#ifdef RANGES_WORKAROUND_MSVC_677925
160 template(typename I2 = I)(
161 requires (!forward_iterator<I2>)) //
162 constexpr auto operator++(int) -> decltype(std::declval<I2 &>()++)
163#else // ^^^ workaround ^^^ / vvv no workaround vvv
164 CPP_member
165 constexpr auto operator++(int) //
166 -> CPP_ret(decltype(std::declval<I &>()++))(
167 requires (!forward_iterator<I>))
168#endif // RANGES_WORKAROUND_MSVC_677925
169 {
170 RANGES_EXPECT(cnt_ > 0);
171 return post_increment_(std::is_void<decltype(current_++)>());
172 }
173
174 CPP_member
175 constexpr auto operator++(int) //
176 -> CPP_ret(counted_iterator)(
177 requires forward_iterator<I>)
178 {
179 auto tmp(*this);
180 ++*this;
181 return tmp;
182 }
183
184 CPP_member
185 constexpr auto operator--() //
186 -> CPP_ret(counted_iterator &)(
187 requires bidirectional_iterator<I>)
188 {
189 --current_;
190 ++cnt_;
191 return *this;
192 }
193
194 CPP_member
195 constexpr auto operator--(int) //
196 -> CPP_ret(counted_iterator)(
197 requires bidirectional_iterator<I>)
198 {
199 auto tmp(*this);
200 --*this;
201 return tmp;
202 }
203
204 CPP_member
205 constexpr auto operator+=(difference_type n) //
206 -> CPP_ret(counted_iterator &)(
207 requires random_access_iterator<I>)
208 {
209 RANGES_EXPECT(cnt_ >= n);
210 current_ += n;
211 cnt_ -= n;
212 return *this;
213 }
214
215 CPP_member
216 constexpr auto operator+(difference_type n) const //
217 -> CPP_ret(counted_iterator)(
218 requires random_access_iterator<I>)
219 {
220 auto tmp(*this);
221 tmp += n;
222 return tmp;
223 }
224
225 CPP_member
226 constexpr auto operator-=(difference_type n) //
227 -> CPP_ret(counted_iterator &)(
228 requires random_access_iterator<I>)
229 {
230 RANGES_EXPECT(cnt_ >= -n);
231 current_ -= n;
232 cnt_ += n;
233 return *this;
234 }
235
236 CPP_member
237 constexpr auto operator-(difference_type n) const //
238 -> CPP_ret(counted_iterator)(
239 requires random_access_iterator<I>)
240 {
241 auto tmp(*this);
242 tmp -= n;
243 return tmp;
244 }
245
246 CPP_member
247 constexpr auto operator[](difference_type n) const //
248 -> CPP_ret(iter_reference_t<I>)(
249 requires random_access_iterator<I>)
250 {
251 RANGES_EXPECT(cnt_ >= n);
252 return current_[n];
253 }
254
255#if !RANGES_BROKEN_CPO_LOOKUP
257 friend constexpr auto iter_move(counted_iterator const & i) //
258 noexcept(detail::has_nothrow_iter_move_v<I>)
259 -> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
260 requires input_iterator<I>)
261 {
262 return ranges::iter_move(i.current_);
263 }
264 template<typename I2, typename S2>
265 friend constexpr auto iter_swap(counted_iterator const & x,
266 counted_iterator<I2> const & y) //
267 noexcept(is_nothrow_indirectly_swappable<I, I2>::value)
268 -> CPP_broken_friend_ret(void)(
269 requires indirectly_swappable<I2, I>)
270 {
271 return ranges::iter_swap(x.current_, _counted_iterator_::access::current(y));
272 }
273#endif
274 };
275
277#if RANGES_BROKEN_CPO_LOOKUP
278 namespace _counted_iterator_
279 {
280 template<typename I>
281 constexpr auto iter_move(counted_iterator<I> const & i) noexcept(
282 detail::has_nothrow_iter_move_v<I>)
283 -> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
284 requires input_iterator<I>)
285 {
286 return ranges::iter_move(_counted_iterator_::access::current(i));
287 }
288 template<typename I1, typename I2>
289 constexpr auto iter_swap(
290 counted_iterator<I1> const & x,
291 counted_iterator<I2> const &
292 y) noexcept(is_nothrow_indirectly_swappable<I1, I2>::value)
293 -> CPP_broken_friend_ret(void)(
294 requires indirectly_swappable<I2, I1>)
295 {
296 return ranges::iter_swap(_counted_iterator_::access::current(x),
297 _counted_iterator_::access::current(y));
298 }
299 } // namespace _counted_iterator_
300#endif
302
303 template(typename I1, typename I2)(
304 requires common_with<I1, I2>)
305 constexpr bool operator==(counted_iterator<I1> const & x,
306 counted_iterator<I2> const & y)
307 {
308 return x.count() == y.count();
309 }
310
311 template<typename I>
312 constexpr bool operator==(counted_iterator<I> const & x, default_sentinel_t)
313 {
314 return x.count() == 0;
315 }
316
317 template<typename I>
318 constexpr bool operator==(default_sentinel_t, counted_iterator<I> const & x)
319 {
320 return x.count() == 0;
321 }
322
323 template(typename I1, typename I2)(
324 requires common_with<I1, I2>)
325 constexpr bool operator!=(counted_iterator<I1> const & x,
326 counted_iterator<I2> const & y)
327 {
328 return !(x == y);
329 }
330
331 template<typename I>
332 constexpr bool operator!=(counted_iterator<I> const & x, default_sentinel_t y)
333 {
334 return !(x == y);
335 }
336
337 template<typename I>
338 constexpr bool operator!=(default_sentinel_t x, counted_iterator<I> const & y)
339 {
340 return !(x == y);
341 }
342
343 template(typename I1, typename I2)(
344 requires common_with<I1, I2>)
345 constexpr bool operator<(counted_iterator<I1> const & x,
346 counted_iterator<I2> const & y)
347 {
348 return y.count() < x.count();
349 }
350
351 template(typename I1, typename I2)(
352 requires common_with<I1, I2>)
353 constexpr bool operator<=(counted_iterator<I1> const & x,
354 counted_iterator<I2> const & y)
355 {
356 return !(y < x);
357 }
358
359 template(typename I1, typename I2)(
360 requires common_with<I1, I2>)
361 constexpr bool operator>(counted_iterator<I1> const & x,
362 counted_iterator<I2> const & y)
363 {
364 return y < x;
365 }
366
367 template(typename I1, typename I2)(
368 requires common_with<I1, I2>)
369 constexpr bool operator>=(counted_iterator<I1> const & x,
370 counted_iterator<I2> const & y)
371 {
372 return !(x < y);
373 }
374
375 template(typename I1, typename I2)(
376 requires common_with<I1, I2>)
377 constexpr iter_difference_t<I2> operator-(counted_iterator<I1> const & x,
378 counted_iterator<I2> const & y)
379 {
380 return y.count() - x.count();
381 }
382
383 template<typename I>
384 constexpr iter_difference_t<I> operator-(counted_iterator<I> const & x,
385 default_sentinel_t)
386 {
387 return -x.count();
388 }
389
390 template<typename I>
391 constexpr iter_difference_t<I> operator-(default_sentinel_t,
392 counted_iterator<I> const & y)
393 {
394 return y.count();
395 }
396
397 template(typename I)(
398 requires random_access_iterator<I>)
399 constexpr counted_iterator<I> operator+(iter_difference_t<I> n,
400 counted_iterator<I> const & x)
401 {
402 return x + n;
403 }
404
405 template(typename I)(
406 requires input_or_output_iterator<I>)
407 constexpr counted_iterator<I> make_counted_iterator(I i, iter_difference_t<I> n)
408 {
409 return {std::move(i), n};
410 }
411
412 template<typename I>
413 struct indirectly_readable_traits<counted_iterator<I>>
415 (bool)indirectly_readable<I>,
416 indirectly_readable_traits<I>,
418 {};
419
420 CPP_template_def(typename I)(
421 requires input_or_output_iterator<I>)
422 constexpr void advance_fn::operator()(counted_iterator<I> & i,
423 iter_difference_t<I> n) const
424 {
425 RANGES_EXPECT(n <= i.cnt_);
426 advance(i.current_, n);
427 i.cnt_ -= n;
428 }
429
430 namespace cpp20
431 {
432 using ranges::counted_iterator;
433 }
435} // namespace ranges
436
438namespace ranges
439{
440 namespace _counted_iterator_
441 {
442 template<typename I, typename = void>
443 struct iterator_traits_
444 {
445 using difference_type = iter_difference_t<I>;
446 using value_type = void;
447 using reference = void;
448 using pointer = void;
449 using iterator_category = std::output_iterator_tag;
450 };
451
452 template<typename I>
453 struct iterator_traits_<I, meta::if_c<input_iterator<I>>>
454 : std::iterator_traits<I>
455 {
456 using pointer = void;
457 };
458 } // namespace _counted_iterator_
459} // namespace ranges
460
461namespace std
462{
463 template<typename I>
464 struct iterator_traits<::ranges::counted_iterator<I>>
465 : ::ranges::_counted_iterator_::iterator_traits_<I>
466 {};
467} // namespace std
469
470#include <range/v3/detail/epilogue.hpp>
471
472#endif
#define CPP_broken_friend_member
INTERNAL ONLY.
Definition concepts.hpp:447
typename detail::_cond< If >::template invoke< Then, Else > conditional_t
Select one type or another depending on a compile-time Boolean.
Definition meta.hpp:1148
_t< detail::count_< L, T > > count
Count the number of times a type T appears in the list L.
Definition meta.hpp:2725
Tiny meta-programming library.
Tiny metaprogramming library.
Definition meta.hpp:116
Point operator*(double s, const Point &a)
Multiply point by scalar.
Definition shapes.h:250
Point operator-(const Point &a, const Point &b)
Subtract two points_ component-wise.
Definition shapes.h:244
An empty type.
Definition meta.hpp:135
Definition traits.hpp:48