Horizon
counted_iterator.hpp
Go to the documentation of this file.
1 // 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 
20 #include <range/v3/range_fwd.hpp>
21 
26 
27 #include <range/v3/detail/prologue.hpp>
28 
29 namespace 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>,
417  meta::nil_>
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 
438 namespace 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 
461 namespace 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