Horizon
adaptor.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_VIEW_ADAPTOR_HPP
14 #define RANGES_V3_VIEW_ADAPTOR_HPP
15 
16 #include <meta/meta.hpp>
17 
18 #include <concepts/concepts.hpp>
19 
20 #include <range/v3/range_fwd.hpp>
21 
28 #include <range/v3/view/all.hpp>
29 #include <range/v3/view/facade.hpp>
30 
31 #include <range/v3/detail/prologue.hpp>
32 
33 namespace ranges
34 {
36  namespace detail
37  {
38  template<typename Derived>
39  using begin_adaptor_t = detail::decay_t<decltype(
40  range_access::begin_adaptor(std::declval<Derived &>()))>;
41 
42  template<typename Derived>
43  using end_adaptor_t = detail::decay_t<decltype(
44  range_access::end_adaptor(std::declval<Derived &>()))>;
45 
46  template<typename Derived>
47  using adapted_iterator_t = detail::decay_t<decltype(
48  std::declval<begin_adaptor_t<Derived>>().begin(std::declval<Derived &>()))>;
49 
50  template<typename Derived>
51  using adapted_sentinel_t = detail::decay_t<decltype(
52  std::declval<end_adaptor_t<Derived>>().end(std::declval<Derived &>()))>;
53 
54  struct adaptor_base_current_mem_fn
55  {};
56 
57  template<typename BaseIter, typename Adapt>
58  constexpr int which_adaptor_value_(priority_tag<0>)
59  {
60  return 0;
61  }
62  template<typename BaseIter, typename Adapt>
63  constexpr always_<int, decltype(Adapt::read(std::declval<BaseIter const &>(),
64  adaptor_base_current_mem_fn{}))> //
65  which_adaptor_value_(priority_tag<1>)
66  {
67  return 1;
68  }
69  template<typename BaseIter, typename Adapt>
70  constexpr always_<int, typename Adapt::value_type> //
71  which_adaptor_value_(priority_tag<2>)
72  {
73  return 2;
74  }
75 
76  template<typename BaseIter, typename Adapt,
77  int = detail::which_adaptor_value_<BaseIter, Adapt>(priority_tag<2>{})>
78  struct adaptor_value_type_
79  {
80  compressed_pair<BaseIter, Adapt> data_;
81  };
82  template<typename BaseIter, typename Adapt>
83  struct adaptor_value_type_<BaseIter, Adapt, 1>
84  {
85  using value_type = iter_value_t<BaseIter>;
86  compressed_pair<BaseIter, Adapt> data_;
87  };
88  template<typename BaseIter, typename Adapt>
89  struct adaptor_value_type_<BaseIter, Adapt, 2>
90  {
91 #ifdef RANGES_WORKAROUND_MSVC_688606
92  using value_type = typename indirectly_readable_traits<Adapt>::value_type;
93 #else // ^^^ workaround ^^^ / vvv no workaround vvv
94  using value_type = typename Adapt::value_type;
95 #endif // RANGES_WORKAROUND_MSVC_688606
96  compressed_pair<BaseIter, Adapt> data_;
97  };
98  } // namespace detail
100 
103  template<typename BaseIt, typename Adapt>
104  struct adaptor_cursor;
105 
106  template<typename BaseSent, typename Adapt>
107  struct base_adaptor_sentinel;
108 
110  {
111  adaptor_base() = default;
112  adaptor_base(adaptor_base &&) = default;
113  adaptor_base(adaptor_base const &) = default;
114  adaptor_base & operator=(adaptor_base &&) = default;
115  adaptor_base & operator=(adaptor_base const &) = default;
116 
117  adaptor_base(detail::ignore_t, detail::ignore_t = {}, detail::ignore_t = {})
118  {}
119  // clang-format off
120  template<typename Rng>
121  static constexpr auto CPP_auto_fun(begin)(Rng &rng)
122  (
123  return ranges::begin(rng.base())
124  )
125  template<typename Rng>
126  static constexpr auto CPP_auto_fun(end)(Rng &rng)
127  (
128  return ranges::end(rng.base())
129  )
130  // clang-format on
131  template(typename I)(
132  requires equality_comparable<I>)
133  static bool equal(I const & it0, I const & it1)
134  {
135  return it0 == it1;
136  }
137  template(typename I)(
138  requires input_or_output_iterator<I>)
139  static iter_reference_t<I> read(I const & it,
140  detail::adaptor_base_current_mem_fn = {})
141  noexcept(noexcept(iter_reference_t<I>(*it)))
142  {
143  return *it;
144  }
145  template(typename I)(
146  requires input_or_output_iterator<I>)
147  static void next(I & it)
148  {
149  ++it;
150  }
151  template(typename I)(
152  requires bidirectional_iterator<I>)
153  static void prev(I & it)
154  {
155  --it;
156  }
157  template(typename I)(
158  requires random_access_iterator<I>)
159  static void advance(I & it, iter_difference_t<I> n)
160  {
161  it += n;
162  }
163  template(typename I)(
164  requires sized_sentinel_for<I, I>)
165  static iter_difference_t<I> distance_to(I const & it0, I const & it1)
166  {
167  return it1 - it0;
168  }
169  template(typename I, typename S)(
170  requires sentinel_for<S, I>)
171  static constexpr bool empty(I const & it, S const & last)
172  {
173  return it == last;
174  }
175  };
176 
177  // Build a sentinel out of a sentinel into the adapted range, and an
178  // adaptor that customizes behavior.
179  template<typename BaseSent, typename Adapt>
181  {
182  private:
183  template<typename, typename>
184  friend struct adaptor_cursor;
185  RANGES_NO_UNIQUE_ADDRESS compressed_pair<BaseSent, Adapt> data_;
186 
187  public:
188  base_adaptor_sentinel() = default;
189  base_adaptor_sentinel(BaseSent sent, Adapt adapt)
190  : data_{std::move(sent), std::move(adapt)}
191  {}
192 
193  // All sentinels into adapted ranges have a base() member for fetching
194  // the underlying sentinel.
195  BaseSent base() const
196  {
197  return data_.first();
198  }
199 
200  protected:
201  // Adaptor accessor
202  Adapt & get()
203  {
204  return data_.second();
205  }
206  Adapt const & get() const
207  {
208  return data_.second();
209  }
210  };
211 
213  namespace detail
214  {
215  template<typename BaseSent, typename Adapt>
216  meta::id<base_adaptor_sentinel<BaseSent, Adapt>> base_adaptor_sentinel_2_(long);
217 
218  template<typename BaseSent, typename Adapt>
220  base_adaptor_sentinel_2_(int);
221 
222  template<typename BaseSent, typename Adapt>
223  struct base_adaptor_sentinel_
224  : decltype(base_adaptor_sentinel_2_<BaseSent, Adapt>(42))
225  {};
226 
227  template<typename BaseSent, typename Adapt>
228  using adaptor_sentinel_ = meta::_t<base_adaptor_sentinel_<BaseSent, Adapt>>;
229  } // namespace detail
231 
232  template<typename BaseSent, typename Adapt>
233  struct adaptor_sentinel : detail::adaptor_sentinel_<BaseSent, Adapt>
234  {
235  using detail::adaptor_sentinel_<BaseSent, Adapt>::adaptor_sentinel_;
236  };
237 
238  // Build a cursor out of an iterator into the adapted range, and an
239  // adaptor that customizes behavior.
240  template<typename BaseIter, typename Adapt>
241  struct adaptor_cursor : private detail::adaptor_value_type_<BaseIter, Adapt>
242  {
243  private:
244  friend range_access;
245  template<typename, typename>
246  friend struct adaptor_cursor;
247  using base_t = detail::adaptor_value_type_<BaseIter, Adapt>;
249  (bool)single_pass_iterator_<BaseIter>>;
250 
251  struct basic_adaptor_mixin : basic_mixin<adaptor_cursor>
252  {
253  basic_adaptor_mixin() = default;
254  #ifndef _MSC_VER
256  #else
257  constexpr explicit basic_adaptor_mixin(adaptor_cursor && cur)
258  : basic_mixin<adaptor_cursor>(static_cast<adaptor_cursor &&>(cur))
259  {}
260  constexpr explicit basic_adaptor_mixin(adaptor_cursor const & cur)
262  {}
263  #endif
264  // All iterators into adapted ranges have a base() member for fetching
265  // the underlying iterator.
266  BaseIter base() const
267  {
268  return basic_adaptor_mixin::basic_mixin::get().data_.first();
269  }
270 
271  protected:
272  // Adaptor accessor
273  Adapt & get()
274  {
275  return basic_adaptor_mixin::basic_mixin::get().data_.second();
276  }
277  const Adapt & get() const
278  {
279  return basic_adaptor_mixin::basic_mixin::get().data_.second();
280  }
281  };
282 
283  template<typename Adapt_>
284  static meta::id<basic_adaptor_mixin> basic_adaptor_mixin_2_(long);
285 
286  template<typename Adapt_>
288  basic_adaptor_mixin_2_(int);
289 
291 
292  template<typename A = Adapt, typename R = decltype(std::declval<A const &>().read(
293  std::declval<BaseIter const &>()))>
294  R read() const noexcept(
295  noexcept(std::declval<A const &>().read(std::declval<BaseIter const &>())))
296  {
297  using V = range_access::cursor_value_t<adaptor_cursor>;
298  static_assert(common_reference_with<R &&, V &>,
299  "In your adaptor, you've specified a value type that does not "
300  "share a common reference type with the return type of read.");
301  return this->data_.second().read(this->data_.first());
302  }
303  template<typename A = Adapt, typename = decltype(std::declval<A &>().next(
304  std::declval<BaseIter &>()))>
305  void next()
306  {
307  this->data_.second().next(this->data_.first());
308  }
309  template<typename A = Adapt,
310  typename = decltype(std::declval<A const &>().equal(
311  std::declval<BaseIter const &>(), std::declval<BaseIter const &>(),
312  std::declval<A const &>()))>
313  bool equal_(adaptor_cursor const & that, int) const
314  {
315  return this->data_.second().equal(
316  this->data_.first(), that.data_.first(), that.data_.second());
317  }
318  template<typename A = Adapt,
319  typename = decltype(std::declval<A const &>().equal(
320  std::declval<BaseIter const &>(), std::declval<BaseIter const &>()))>
321  bool equal_(adaptor_cursor const & that, long) const
322  {
323  return this->data_.second().equal(this->data_.first(), that.data_.first());
324  }
325  template<typename C = adaptor_cursor>
326  auto equal(adaptor_cursor const & that) const
327  -> decltype(std::declval<C const &>().equal_(that, 42))
328  {
329  return this->equal_(that, 42);
330  }
331  template<typename S, typename A,
332  typename = decltype(std::declval<A const &>().empty(
333  std::declval<BaseIter const &>(), std::declval<Adapt const &>(),
334  std::declval<S const &>()))>
335  constexpr bool equal_(adaptor_sentinel<S, A> const & that, int) const
336  {
337  return that.data_.second().empty(
338  this->data_.first(), this->data_.second(), that.data_.first());
339  }
340  template<typename S, typename A,
341  typename = decltype(std::declval<A const &>().empty(
342  std::declval<BaseIter const &>(), std::declval<S const &>()))>
343  constexpr bool equal_(adaptor_sentinel<S, A> const & that, long) const
344  {
345  return that.data_.second().empty(this->data_.first(), that.data_.first());
346  }
347  template<typename S, typename A>
348  constexpr auto equal(adaptor_sentinel<S, A> const & that) const
349  -> decltype(std::declval<adaptor_cursor const &>().equal_(that, 42))
350  {
351  return this->equal_(that, 42);
352  }
353  template<typename A = Adapt, typename = decltype(std::declval<A &>().prev(
354  std::declval<BaseIter &>()))>
355  void prev()
356  {
357  this->data_.second().prev(this->data_.first());
358  }
359  template<typename A = Adapt, typename = decltype(std::declval<A &>().advance(
360  std::declval<BaseIter &>(), 0))>
361  void advance(iter_difference_t<BaseIter> n)
362  {
363  this->data_.second().advance(this->data_.first(), n);
364  }
365  template<typename A = Adapt,
366  typename R = decltype(std::declval<A const &>().distance_to(
367  std::declval<BaseIter const &>(), std::declval<BaseIter const &>(),
368  std::declval<A const &>()))>
369  R distance_to_(adaptor_cursor const & that, int) const
370  {
371  return this->data_.second().distance_to(
372  this->data_.first(), that.data_.first(), that.data_.second());
373  }
374  template<typename A = Adapt,
375  typename R = decltype(std::declval<A const &>().distance_to(
376  std::declval<BaseIter const &>(), std::declval<BaseIter const &>()))>
377  R distance_to_(adaptor_cursor const & that, long) const
378  {
379  return this->data_.second().distance_to(this->data_.first(),
380  that.data_.first());
381  }
382  template<typename C = adaptor_cursor>
383  auto distance_to(adaptor_cursor const & that) const
384  -> decltype(std::declval<C const &>().distance_to_(that, 42))
385  {
386  return this->distance_to_(that, 42);
387  }
388  // If the adaptor has an iter_move function, use it.
389  template<typename A = Adapt,
390  typename X = decltype(std::declval<A const &>().iter_move(
391  std::declval<BaseIter const &>()))>
392  X iter_move_(int) const noexcept(noexcept(
393  std::declval<A const &>().iter_move(std::declval<BaseIter const &>())))
394  {
395  using V = range_access::cursor_value_t<adaptor_cursor>;
396  using R = decltype(this->data_.second().read(this->data_.first()));
397  static_assert(
398  common_reference_with<X &&, V const &>,
399  "In your adaptor, the result of your iter_move member function does "
400  "not share a common reference with your value type.");
401  static_assert(
402  common_reference_with<R &&, X &&>,
403  "In your adaptor, the result of your iter_move member function does "
404  "not share a common reference with the result of your read member "
405  "function.");
406  return this->data_.second().iter_move(this->data_.first());
407  }
408  // If there is no iter_move member and the adaptor has not overridden the read
409  // member function, then dispatch to the base iterator's iter_move function.
410  template<typename A = Adapt,
411  typename R = decltype(std::declval<A const &>().read(
412  std::declval<BaseIter const &>(),
413  detail::adaptor_base_current_mem_fn{})),
414  typename X = iter_rvalue_reference_t<BaseIter>>
415  X iter_move_(long) const
416  noexcept(noexcept(X(ranges::iter_move(std::declval<BaseIter const &>()))))
417  {
418  return ranges::iter_move(this->data_.first());
419  }
420  // If the adaptor does not have an iter_move function but overrides the read
421  // member function, apply std::move to the result of calling read.
422  template<typename A = Adapt,
423  typename R = decltype(
424  std::declval<A const &>().read(std::declval<BaseIter const &>())),
425  typename X = aux::move_t<R>>
426  X iter_move_(detail::ignore_t) const noexcept(noexcept(X(static_cast<X &&>(
427  std::declval<A const &>().read(std::declval<BaseIter const &>())))))
428  {
429  using V = range_access::cursor_value_t<adaptor_cursor>;
430  static_assert(
431  common_reference_with<X &&, V const &>,
432  "In your adaptor, you've specified a value type that does not share a "
433  "common "
434  "reference type with the result of moving the result of the read member "
435  "function. Consider defining an iter_move function in your adaptor.");
436  return static_cast<X &&>(this->data_.second().read(this->data_.first()));
437  }
438  // Gives users a way to override the default iter_move function in their adaptors.
439  auto move() const
440  noexcept(noexcept(std::declval<const adaptor_cursor &>().iter_move_(42)))
441  -> decltype(std::declval<const adaptor_cursor &>().iter_move_(42))
442  {
443  return iter_move_(42);
444  }
445 
446  public:
447  adaptor_cursor() = default;
448  adaptor_cursor(BaseIter iter, Adapt adapt)
449  : base_t{{std::move(iter), std::move(adapt)}}
450  {}
451  template(typename OtherIter, typename OtherAdapt)(
452  requires //
454  convertible_to<OtherIter, BaseIter> AND
455  convertible_to<OtherAdapt, Adapt>)
457  : base_t{{std::move(that.data_.first()), std::move(that.data_.second())}}
458  {}
459  };
460 
461  template<typename D>
462  using adaptor_cursor_t =
463  adaptor_cursor<detail::adapted_iterator_t<D>, detail::begin_adaptor_t<D>>;
464 
465  template<typename D>
466  using adaptor_sentinel_t = meta::if_c<
467  same_as<detail::adapted_iterator_t<D>, detail::adapted_sentinel_t<D>> &&
468  same_as<detail::begin_adaptor_t<D>, detail::end_adaptor_t<D>>,
470  adaptor_sentinel<detail::adapted_sentinel_t<D>, detail::end_adaptor_t<D>>>;
471 
472  template<typename Derived, typename BaseRng,
473  cardinality Cardinality /*= range_cardinality<BaseRng>::value*/>
474  struct view_adaptor : view_facade<Derived, Cardinality>
475  {
476  private:
477  friend Derived;
478  friend range_access;
479  friend adaptor_base;
480  CPP_assert(viewable_range<BaseRng>);
481  using base_range_t = views::all_t<BaseRng>;
483 
484  base_range_t rng_;
485 
486  constexpr adaptor_base begin_adaptor() const noexcept
487  {
488  return {};
489  }
490  constexpr adaptor_base end_adaptor() const noexcept
491  {
492  return {};
493  }
494 
495  template<typename D>
496  static constexpr adaptor_cursor_t<D> begin_cursor_(D & d) noexcept(noexcept(
497  adaptor_cursor_t<D>{std::declval<detail::begin_adaptor_t<D> &>().begin(d),
498  range_access::begin_adaptor(d)}))
499  {
500  auto adapt = range_access::begin_adaptor(d);
501  auto pos = adapt.begin(d);
502  return {std::move(pos), std::move(adapt)};
503  }
504  template(typename D = Derived)(
505  requires same_as<D, Derived>)
506  constexpr auto begin_cursor() noexcept(
507  noexcept(view_adaptor::begin_cursor_(std::declval<D &>())))
508  -> decltype(view_adaptor::begin_cursor_(std::declval<D &>()))
509  {
510  return view_adaptor::begin_cursor_(derived());
511  }
512  template(typename D = Derived)(
513  requires same_as<D, Derived> AND range<base_range_t const>)
514  constexpr auto begin_cursor() const
515  noexcept(noexcept(view_adaptor::begin_cursor_(std::declval<D const &>())))
516  -> decltype(view_adaptor::begin_cursor_(std::declval<D const &>()))
517  {
518  return view_adaptor::begin_cursor_(derived());
519  }
520 
521  template<typename D>
522  static constexpr adaptor_sentinel_t<D> end_cursor_(D & d) noexcept(noexcept(
523  adaptor_sentinel_t<D>{std::declval<detail::end_adaptor_t<D> &>().end(d),
524  range_access::end_adaptor(d)}))
525  {
526  auto adapt = range_access::end_adaptor(d);
527  auto pos = adapt.end(d);
528  return {std::move(pos), std::move(adapt)};
529  }
530  template(typename D = Derived)(
531  requires same_as<D, Derived>)
532  constexpr auto end_cursor() noexcept(
533  noexcept(view_adaptor::end_cursor_(std::declval<D &>())))
534  -> decltype(view_adaptor::end_cursor_(std::declval<D &>()))
535  {
536  return view_adaptor::end_cursor_(derived());
537  }
538  template(typename D = Derived)(
539  requires same_as<D, Derived> AND range<base_range_t const>)
540  constexpr auto end_cursor() const noexcept(
541  noexcept(view_adaptor::end_cursor_(std::declval<D const &>())))
542  -> decltype(view_adaptor::end_cursor_(std::declval<D const &>()))
543  {
544  return view_adaptor::end_cursor_(derived());
545  }
546 
547  protected:
548  ~view_adaptor() = default;
549 
550  public:
551  view_adaptor() = default;
552  view_adaptor(view_adaptor &&) = default;
553  view_adaptor(view_adaptor const &) = default;
554  view_adaptor & operator=(view_adaptor &&) = default;
555  view_adaptor & operator=(view_adaptor const &) = default;
556  constexpr explicit view_adaptor(BaseRng && rng)
557  : rng_(views::all(static_cast<BaseRng &&>(rng)))
558  {}
559  constexpr base_range_t & base() noexcept
560  {
561  return rng_;
562  }
564  constexpr base_range_t const & base() const noexcept
565  {
566  return rng_;
567  }
568  };
569 
571 } // namespace ranges
572 
573 #include <range/v3/detail/epilogue.hpp>
574 
575 #endif
meta::if_c< std::is_reference< R >::value, meta::_t< std::remove_reference< R > > &&, detail::decay_t< R > > move_t
Definition: move.hpp:59
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
bool_< 0==size< L >::type::value > empty
An Boolean integral constant wrapper around true if L is an empty type list; false,...
Definition: meta.hpp:2231
Tiny meta-programming library.
A trait that always returns its argument T.
Definition: meta.hpp:558
Definition: adaptor.hpp:110
Definition: adaptor.hpp:242
Definition: adaptor.hpp:234
Definition: adaptor.hpp:181
Definition: basic_iterator.hpp:47
Definition: adaptor.hpp:475
constexpr base_range_t const & base() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: adaptor.hpp:564
A utility for constructing a view from a (derived) type that implements begin and end cursors.
Definition: facade.hpp:66