Horizon
Loading...
Searching...
No Matches
adaptor.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_VIEW_ADAPTOR_HPP
14#define RANGES_V3_VIEW_ADAPTOR_HPP
15
16#include <meta/meta.hpp>
17
18#include <concepts/concepts.hpp>
19
21
28#include <range/v3/view/all.hpp>
30
31#include <range/v3/detail/prologue.hpp>
32
33namespace 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)(
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)(
147 static void next(I & it)
148 {
149 ++it;
150 }
151 template(typename I)(
153 static void prev(I & it)
154 {
155 --it;
156 }
157 template(typename I)(
159 static void advance(I & it, iter_difference_t<I> n)
160 {
161 it += n;
162 }
163 template(typename 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
255 using basic_mixin<adaptor_cursor>::basic_mixin;
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>;
482 using view_facade<Derived, Cardinality>::derived;
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
The bidirectional_iterator concept.
The input_or_output_iterator concept.
The random_access_iterator concept.
The range concept.
The sentinel_for concept.
The sized_sentinel_for concept.
The viewable_range concept.
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
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 compressed_pair.hpp:124
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