Horizon
common_iterator.hpp
Go to the documentation of this file.
1 // Range v3 library
3 //
4 // Copyright Eric Niebler 2014-present
5 // Copyright Casey Carter 2016
6 //
7 // Use, modification and distribution is subject to the
8 // Boost Software License, Version 1.0. (See accompanying
9 // file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
11 //
12 // Project home: https://github.com/ericniebler/range-v3
13 //
14 #ifndef RANGES_V3_ITERATOR_COMMON_ITERATOR_HPP
15 #define RANGES_V3_ITERATOR_COMMON_ITERATOR_HPP
16 
17 #include <cstdint>
18 #include <iterator>
19 #include <type_traits>
20 
21 #include <meta/meta.hpp>
22 
23 #include <concepts/concepts.hpp>
24 
25 #include <range/v3/range_fwd.hpp>
26 
27 #include <range/v3/detail/variant.hpp>
31 
32 #include <range/v3/detail/prologue.hpp>
33 
34 namespace ranges
35 {
38 
40  namespace detail
41  {
42  template<typename I, typename S>
43  variant<I, S> & cidata(common_iterator<I, S> & that)
44  {
45  return that.data_;
46  }
47 
48  template<typename I, typename S>
49  variant<I, S> const & cidata(common_iterator<I, S> const & that)
50  {
51  return that.data_;
52  }
53  } // namespace detail
54 
55 #if RANGES_BROKEN_CPO_LOOKUP
56  namespace _common_iterator_
57  {
58  struct adl_hook
59  {};
60  } // namespace _common_iterator_
61 #endif
63 
64  template<typename I, typename S>
66 #if RANGES_BROKEN_CPO_LOOKUP
67  : private _common_iterator_::adl_hook
68 #endif
69  {
70  private:
71  CPP_assert(input_or_output_iterator<I>);
72  CPP_assert(sentinel_for<S, I>);
73  CPP_assert(!same_as<I, S>);
74  variant<I, S> data_;
75 
76  friend variant<I, S> & detail::cidata<>(common_iterator<I, S> &);
77  friend variant<I, S> const & detail::cidata<>(common_iterator<I, S> const &);
78  struct emplace_fn
79  {
80  variant<I, S> * data_;
81  template<typename T, std::size_t N>
82  void operator()(indexed_element<T, N> t) const
83  {
84  ranges::emplace<N>(*data_, t.get());
85  }
86  };
87  struct arrow_proxy_
88  {
89  private:
90  friend common_iterator;
91  iter_value_t<I> keep_;
92  arrow_proxy_(iter_reference_t<I> && x)
93  : keep_(std::move(x))
94  {}
95 
96  public:
97  const iter_value_t<I> * operator->() const noexcept
98  {
99  return std::addressof(keep_);
100  }
101  };
102  template<typename T>
103  static T * operator_arrow_(T * p, int) noexcept
104  {
105  return p;
106  }
107  template<typename J, typename = detail::iter_arrow_t<J const>>
108  static J operator_arrow_(J const & j, int) noexcept(noexcept(J(j)))
109  {
110  return j;
111  }
112  template(typename J, typename R = iter_reference_t<J>)(
113  requires std::is_reference<R>::value) //
114  static meta::_t<std::add_pointer<R>> operator_arrow_(J const & j, long) noexcept
115  {
116  auto && r = *j;
117  return std::addressof(r);
118  }
119  template(typename J, typename V = iter_value_t<J>)(
120  requires constructible_from<V, iter_reference_t<J>>)
121  static arrow_proxy_ operator_arrow_(J const & j, ...) noexcept(noexcept(V(V(*j))))
122  {
123  return arrow_proxy_(*j);
124  }
125 
126  public:
127  using difference_type = iter_difference_t<I>;
128 
129  common_iterator() = default;
130  common_iterator(I i)
131  : data_(emplaced_index<0>, std::move(i))
132  {}
133  common_iterator(S s)
134  : data_(emplaced_index<1>, std::move(s))
135  {}
136  template(typename I2, typename S2)(
137  requires convertible_to<I2, I> AND convertible_to<S2, S>)
139  : data_(detail::variant_core_access::make_empty<I, S>())
140  {
141  detail::cidata(that).visit_i(emplace_fn{&data_});
142  }
143  template(typename I2, typename S2)(
144  requires convertible_to<I2, I> AND convertible_to<S2, S>)
145  common_iterator & operator=(common_iterator<I2, S2> const & that)
146  {
147  detail::cidata(that).visit_i(emplace_fn{&data_});
148  return *this;
149  }
150  iter_reference_t<I> operator*() //
151  noexcept(noexcept(iter_reference_t<I>(*std::declval<I &>())))
152  {
153  return *ranges::get<0>(data_);
154  }
155  CPP_member
156  auto operator*() const //
157  noexcept(noexcept(iter_reference_t<I>(*std::declval<I const &>())))
158  -> CPP_ret(iter_reference_t<I>)(
159  requires indirectly_readable<I const>)
160  {
161  return *ranges::get<0>(data_);
162  }
163  template(typename J = I)(
164  requires indirectly_readable<J>)
165  auto operator->() const //
166  noexcept(
167  noexcept(common_iterator::operator_arrow_(std::declval<I const &>(), 42)))
168  -> decltype(common_iterator::operator_arrow_(std::declval<J const &>(), 42))
169  {
170  return common_iterator::operator_arrow_(ranges::get<0>(data_), 42);
171  }
172  common_iterator & operator++()
173  {
174  ++ranges::get<0>(data_);
175  return *this;
176  }
177 #ifdef RANGES_WORKAROUND_MSVC_677925
178  template(typename I2 = I)(
179  requires (!forward_iterator<I2>)) //
180  auto operator++(int) //
181  -> decltype(std::declval<I2 &>()++)
182  {
183  return ranges::get<0>(data_)++;
184  }
185 #else // ^^^ workaround ^^^ / vvv no workaround vvv
186  CPP_member
187  auto operator++(int) //
188  -> CPP_ret(decltype(std::declval<I &>()++))(
189  requires (!forward_iterator<I>))
190  {
191  return ranges::get<0>(data_)++;
192  }
193 #endif // RANGES_WORKAROUND_MSVC_677925
194  CPP_member
195  auto operator++(int) //
196  -> CPP_ret(common_iterator)(
197  requires forward_iterator<I>)
198  {
199  return common_iterator(ranges::get<0>(data_)++);
200  }
201 
202 #if !RANGES_BROKEN_CPO_LOOKUP
203  template<typename I_ = I>
204  friend constexpr auto iter_move(common_iterator const & i) //
205  noexcept(detail::has_nothrow_iter_move_v<I>)
206  -> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
207  requires input_iterator<I_>)
208  {
209  return ranges::iter_move(ranges::get<0>(detail::cidata(i)));
210  }
211  template<typename I2, typename S2>
212  friend auto iter_swap(
213  common_iterator const & x,
216  -> CPP_broken_friend_ret(void)(
217  requires indirectly_swappable<I2, I>)
218  {
219  return ranges::iter_swap(ranges::get<0>(detail::cidata(x)),
220  ranges::get<0>(detail::cidata(y)));
221  }
222 #endif
223  };
224 
226 #if RANGES_BROKEN_CPO_LOOKUP
227  namespace _common_iterator_
228  {
229  template<typename I, typename S>
230  constexpr auto iter_move(common_iterator<I, S> const & i) noexcept(
231  detail::has_nothrow_iter_move_v<I>)
232  -> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
233  requires input_iterator<I>)
234  {
235  return ranges::iter_move(ranges::get<0>(detail::cidata(i)));
236  }
237  template<typename I1, typename S1, typename I2, typename S2>
238  auto iter_swap(common_iterator<I1, S1> const & x,
239  common_iterator<I2, S2> const & y) //
240  noexcept(is_nothrow_indirectly_swappable<I1, I2>::value)
241  -> CPP_broken_friend_ret(void)(
242  requires indirectly_swappable<I1, I2>)
243  {
244  return ranges::iter_swap(ranges::get<0>(detail::cidata(x)),
245  ranges::get<0>(detail::cidata(y)));
246  }
247  } // namespace _common_iterator_
248 #endif
250 
251  template(typename I1, typename I2, typename S1, typename S2)(
252  requires sentinel_for<S1, I2> AND sentinel_for<S2, I1> AND
253  (!equality_comparable_with<I1, I2>)) //
254  bool operator==(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
255  {
256  return detail::cidata(x).index() == 1u ? (detail::cidata(y).index() == 1u ||
257  ranges::get<0>(detail::cidata(y)) ==
258  ranges::get<1>(detail::cidata(x)))
259  : (detail::cidata(y).index() != 1u ||
260  ranges::get<0>(detail::cidata(x)) ==
261  ranges::get<1>(detail::cidata(y)));
262  }
263 
264  template(typename I1, typename I2, typename S1, typename S2)(
265  requires sentinel_for<S1, I2> AND sentinel_for<S2, I1> AND
266  equality_comparable_with<I1, I2>)
267  bool operator==(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
268  {
269  return detail::cidata(x).index() == 1u
270  ? (detail::cidata(y).index() == 1u ||
271  ranges::get<0>(detail::cidata(y)) ==
272  ranges::get<1>(detail::cidata(x)))
273  : (detail::cidata(y).index() == 1u
274  ? ranges::get<0>(detail::cidata(x)) ==
275  ranges::get<1>(detail::cidata(y))
276  : ranges::get<0>(detail::cidata(x)) ==
277  ranges::get<0>(detail::cidata(y)));
278  }
279 
280  template(typename I1, typename I2, typename S1, typename S2)(
281  requires sentinel_for<S1, I2> AND sentinel_for<S2, I1>)
282  bool operator!=(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
283  {
284  return !(x == y);
285  }
286 
287  template(typename I1, typename I2, typename S1, typename S2)(
288  requires sized_sentinel_for<I1, I2> AND sized_sentinel_for<S1, I2> AND
289  sized_sentinel_for<S2, I1>)
290  iter_difference_t<I2> operator-(common_iterator<I1, S1> const & x,
291  common_iterator<I2, S2> const & y)
292  {
293  return detail::cidata(x).index() == 1u
294  ? (detail::cidata(y).index() == 1u
295  ? 0
296  : ranges::get<1>(detail::cidata(x)) -
297  ranges::get<0>(detail::cidata(y)))
298  : (detail::cidata(y).index() == 1u
299  ? ranges::get<0>(detail::cidata(x)) -
300  ranges::get<1>(detail::cidata(y))
301  : ranges::get<0>(detail::cidata(x)) -
302  ranges::get<0>(detail::cidata(y)));
303  }
304 
305  template<typename I, typename S>
306  struct indirectly_readable_traits<common_iterator<I, S>>
307  : meta::if_c<
308  (bool)indirectly_readable<I>,
309  indirectly_readable_traits<I>,
310  meta::nil_>
311  {};
312 
314  namespace detail
315  {
316  template<typename I>
317  auto demote_common_iter_cat(...) -> nil_;
318  template<typename I>
319  auto demote_common_iter_cat(long)
320  -> with_iterator_category<std::input_iterator_tag>;
321  template(typename I)(
322  requires derived_from<typename std::iterator_traits<I>::iterator_category,
323  std::forward_iterator_tag>)
324  auto demote_common_iter_cat(int)
325  -> with_iterator_category<std::forward_iterator_tag>;
326 
327  template<typename I, bool = (bool)input_iterator<I>>
328  struct common_iterator_std_traits : decltype(detail::demote_common_iter_cat<I>(0))
329  {
330  using difference_type = iter_difference_t<I>;
331  using value_type = iter_value_t<I>;
332  using reference = iter_reference_t<I>;
333  using pointer = detail::iter_pointer_t<I>;
334  using iterator_concept =
335  meta::conditional_t<(bool)forward_iterator<I>, std::forward_iterator_tag,
336  std::input_iterator_tag>;
337  };
338 
339  template<typename I>
340  struct common_iterator_std_traits<I, false>
341  {
342  using difference_type = iter_difference_t<I>;
343  using value_type = void;
344  using reference = void;
345  using pointer = void;
346  using iterator_category = std::output_iterator_tag;
347  };
348 
349  // An iterator adaptor that demotes a user-defined difference_type to
350  // std::intmax_t, for use when constructing containers from such
351  // iterators.
352  template<typename I>
353  struct cpp17_iterator_cursor
354  {
355  private:
356  friend range_access;
357  I it_;
358  struct mixin : basic_mixin<cpp17_iterator_cursor>
359  {
360  mixin() = default;
361  #ifndef _MSC_VER
362  using basic_mixin<cpp17_iterator_cursor>::basic_mixin;
363  #else
364  constexpr explicit mixin(cpp17_iterator_cursor && cur)
365  : basic_mixin<cpp17_iterator_cursor>(
366  static_cast<cpp17_iterator_cursor &&>(cur))
367  {}
368  constexpr explicit mixin(cpp17_iterator_cursor const & cur)
369  : basic_mixin<cpp17_iterator_cursor>(cur)
370  {}
371  #endif
372  explicit mixin(I it)
373  : mixin{cpp17_iterator_cursor{std::move(it)}}
374  {}
375  I base() const
376  {
377  return this->get().it_;
378  }
379  };
380 
381  public:
382  using single_pass = meta::bool_<!forward_iterator<I>>;
383  using difference_type = std::ptrdiff_t;
384  using value_type = iter_value_t<I>;
385 
386  cpp17_iterator_cursor() = default;
387  constexpr explicit cpp17_iterator_cursor(I i)
388  : it_(static_cast<I &&>(i))
389  {}
390 
391  I arrow() const
392  {
393  return it_;
394  }
395  decltype(auto) read()
396  {
397  return *it_;
398  }
399  decltype(auto) read() const
400  {
401  return *it_;
402  }
403  void next()
404  {
405  ++it_;
406  }
407  bool equal(cpp17_iterator_cursor const & that) const
408  {
409  return it_ == that.it_;
410  }
411  CPP_member
412  auto prev() //
413  -> CPP_ret(void)(
414  requires bidirectional_iterator<I>)
415  {
416  --it_;
417  }
418  CPP_member
419  auto advance(std::ptrdiff_t n) //
420  -> CPP_ret(void)(
421  requires random_access_iterator<I>)
422  {
423  it_ += static_cast<iter_difference_t<I>>(n);
424  }
425  CPP_member
426  auto distance_to(cpp17_iterator_cursor const & that) //
427  -> CPP_ret(std::ptrdiff_t)(
428  requires random_access_iterator<I>)
429  {
430  auto d = that.it_ - it_;
431  RANGES_EXPECT(d <= PTRDIFF_MAX);
432  return static_cast<std::ptrdiff_t>(d);
433  }
434  };
435  } // namespace detail
437 
438  namespace cpp20
439  {
441  }
443 } // namespace ranges
444 
446 RANGES_DIAGNOSTIC_PUSH
447 RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
448 
449 namespace std
450 {
451  template<typename I, typename S>
452  struct iterator_traits<::ranges::common_iterator<I, S>>
453  : ::ranges::detail::common_iterator_std_traits<I>
454  {};
455 } // namespace std
456 
457 RANGES_DIAGNOSTIC_POP
459 
460 #include <range/v3/detail/epilogue.hpp>
461 
462 #endif
std::integral_constant< bool, B > bool_
An integral constant wrapper for bool.
Definition: meta.hpp:168
typename T::type _t
Type alias for T::type.
Definition: meta.hpp:141
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
Tiny meta-programming library.
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: common_iterator.hpp:69
Definition: variant.hpp:71
Definition: access.hpp:290