Horizon
Loading...
Searching...
No Matches
access.hpp
Go to the documentation of this file.
1
2// Range v3 library
3//
4// Copyright Eric Niebler 2013-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
14#ifndef RANGES_V3_RANGE_ACCESS_HPP
15#define RANGES_V3_RANGE_ACCESS_HPP
16
17#include <range/v3/detail/config.hpp>
18
19#include <functional> // for reference_wrapper (whose use with begin/end is deprecated)
20#include <initializer_list>
21#include <iterator>
22#include <limits>
23#include <utility>
24
25#ifdef __has_include
26#if __has_include(<span>) && !defined(RANGES_WORKAROUND_MSVC_UNUSABLE_SPAN)
27#include <span>
28#endif
29#if __has_include(<string_view>)
30#include <string_view>
31#endif
32#endif
33
35
39#include <range/v3/utility/static_const.hpp>
40
41#include <range/v3/detail/prologue.hpp>
42
43namespace ranges
44{
45#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201603L
46 template<class CharT, class Traits>
47 RANGES_INLINE_VAR constexpr bool
48 enable_borrowed_range<std::basic_string_view<CharT, Traits>> = true;
49#endif
50
51// libstdc++'s <span> header only defines std::span when concepts
52// are also enabled. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97869
53#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L && \
54 (!defined(__GLIBCXX__) || defined(__cpp_lib_concepts))
55 template<class T, std::size_t N>
56 RANGES_INLINE_VAR constexpr bool enable_borrowed_range<std::span<T, N>> = true;
57#endif
58
59 namespace detail
60 {
61 template<typename T>
62 RANGES_INLINE_VAR constexpr bool _borrowed_range =
63 enable_borrowed_range<uncvref_t<T>>;
64
65 template<typename T>
66 RANGES_INLINE_VAR constexpr bool _borrowed_range<T &> = true;
67
68 template<typename T>
69 T _decay_copy(T) noexcept;
70 } // namespace detail
71
73 namespace _begin_
74 {
75 // Poison pill for std::begin. (See the detailed discussion at
76 // https://github.com/ericniebler/stl2/issues/139)
77 template<typename T>
78 void begin(T &&) = delete;
79
80#ifdef RANGES_WORKAROUND_MSVC_895622
81 void begin();
82#endif
83
84 template<typename T>
85 void begin(std::initializer_list<T>) = delete;
86
87 template(typename I)(
88 requires input_or_output_iterator<I>)
89 void is_iterator(I);
90
91 // clang-format off
94 template<typename T>
95 CPP_requires(has_member_begin_,
96 requires(T & t) //
97 (
98 _begin_::is_iterator(t.begin())
99 ));
102 template<typename T>
103 CPP_concept has_member_begin =
104 CPP_requires_ref(_begin_::has_member_begin_, T);
105
108 template<typename T>
109 CPP_requires(has_non_member_begin_,
110 requires(T & t) //
111 (
112 _begin_::is_iterator(begin(t))
113 ));
116 template<typename T>
117 CPP_concept has_non_member_begin =
118 CPP_requires_ref(_begin_::has_non_member_begin_, T);
119 // clang-format on
120
121 struct fn
122 {
123 private:
124 struct _member_result_
125 {
126 template<typename R>
127 using invoke = decltype(detail::_decay_copy(declval(R &).begin()));
128 };
129 struct _non_member_result_
130 {
131 template<typename R>
132 using invoke = decltype(detail::_decay_copy(begin(declval(R &))));
133 };
134
135 template<typename R>
136 using _result_t =
139 has_member_begin<R>,
140 _member_result_,
141 _non_member_result_>,
142 R>;
143
144 public:
145 template<typename R, std::size_t N>
146 void operator()(R(&&)[N]) const = delete;
147
148 template<typename R, std::size_t N>
149 constexpr R * operator()(R (&array)[N]) const noexcept
150 {
151 return array;
152 }
153
154 template(typename R)(
155 requires detail::_borrowed_range<R> AND has_member_begin<R>)
156 constexpr _result_t<R> operator()(R && r) const //
157 noexcept(noexcept(r.begin()))
158 {
159 return r.begin();
160 }
161
162 template(typename R)(
163 requires detail::_borrowed_range<R> AND (!has_member_begin<R>) AND
164 has_non_member_begin<R>)
165 constexpr _result_t<R> operator()(R && r) const //
166 noexcept(noexcept(begin(r)))
167 {
168 return begin(r);
169 }
170 };
171
172 template<typename R>
173 using _t = decltype(fn{}(declval(R &&)));
174 } // namespace _begin_
176
182 RANGES_DEFINE_CPO(_begin_::fn, begin)
183
184
185 namespace _end_
186 {
187 // Poison pill for std::end. (See the detailed discussion at
188 // https://github.com/ericniebler/stl2/issues/139)
189 template<typename T>
190 void end(T &&) = delete;
191
192#ifdef RANGES_WORKAROUND_MSVC_895622
193 void end();
194#endif
195
196 template<typename T>
197 void end(std::initializer_list<T>) = delete;
198
199 template(typename I, typename S)(
200 requires sentinel_for<S, I>)
201 void _is_sentinel(S, I);
202
203 // clang-format off
206 template<typename T>
207 CPP_requires(has_member_end_,
208 requires(T & t) //
209 (
210 _end_::_is_sentinel(t.end(), ranges::begin(t))
211 ));
214 template<typename T>
215 CPP_concept has_member_end =
216 CPP_requires_ref(_end_::has_member_end_, T);
217
220 template<typename T>
221 CPP_requires(has_non_member_end_,
222 requires(T & t) //
223 (
224 _end_::_is_sentinel(end(t), ranges::begin(t))
225 ));
228 template<typename T>
229 CPP_concept has_non_member_end =
230 CPP_requires_ref(_end_::has_non_member_end_, T);
231 // clang-format on
232
233 struct fn
234 {
235 private:
236 struct _member_result_
237 {
238 template<typename R>
239 using invoke = decltype(detail::_decay_copy(declval(R &).end()));
240 };
241 struct _non_member_result_
242 {
243 template<typename R>
244 using invoke = decltype(detail::_decay_copy(end(declval(R &))));
245 };
246
247 template<typename R>
248 using _result_t =
251 has_member_end<R>,
252 _member_result_,
253 _non_member_result_>,
254 R>;
255
256 template<typename Int>
257 using iter_diff_t =
259 std::make_signed<Int>, //
261
262 public:
263 template<typename R, std::size_t N>
264 void operator()(R(&&)[N]) const = delete;
265
266 template<typename R, std::size_t N>
267 constexpr R * operator()(R (&array)[N]) const noexcept
268 {
269 return array + N;
270 }
271
272 template(typename R)(
273 requires detail::_borrowed_range<R> AND has_member_end<R>)
274 constexpr _result_t<R> operator()(R && r) const //
275 noexcept(noexcept(r.end()))
276 {
277 return r.end();
278 }
279
280 template(typename R)(
281 requires detail::_borrowed_range<R> AND (!has_member_end<R>) AND
282 has_non_member_end<R>)
283 constexpr _result_t<R> operator()(R && r) const //
284 noexcept(noexcept(end(r)))
285 {
286 return end(r);
287 }
288
289 template(typename Int)(
290 requires detail::integer_like_<Int>)
291 auto operator-(Int dist) const
292 -> detail::from_end_<iter_diff_t<Int>>
293 {
294 using SInt = iter_diff_t<Int>;
295 RANGES_EXPECT(0 <= dist);
296 RANGES_EXPECT(dist <=
297 static_cast<Int>((std::numeric_limits<SInt>::max)()));
298 return detail::from_end_<SInt>{-static_cast<SInt>(dist)};
299 }
300 };
301
302 template<typename R>
303 using _t = decltype(fn{}(declval(R &&)));
304 } // namespace _end_
306
313 RANGES_DEFINE_CPO(_end_::fn, end)
314
315
316 namespace _cbegin_
317 {
318 struct fn
319 {
320 template<typename T, std::size_t N>
321 void operator()(T(&&)[N]) const = delete;
322
323 template<typename R>
324 constexpr _begin_::_t<detail::as_const_t<R>> operator()(R && r) const
325 noexcept(noexcept(ranges::begin(detail::as_const(r))))
326 {
327 return ranges::begin(detail::as_const(r));
328 }
329 };
330 } // namespace _cbegin_
332
337 RANGES_INLINE_VARIABLE(_cbegin_::fn, cbegin)
338
339
340 namespace _cend_
341 {
342 struct fn
343 {
344 template<typename T, std::size_t N>
345 void operator()(T(&&)[N]) const = delete;
346
347 template<typename R>
348 constexpr _end_::_t<detail::as_const_t<R>> operator()(R && r) const
349 noexcept(noexcept(ranges::end(detail::as_const(r))))
350 {
351 return ranges::end(detail::as_const(r));
352 }
353 };
354 } // namespace _cend_
356
361 RANGES_INLINE_VARIABLE(_cend_::fn, cend)
362
363
364 namespace _rbegin_
365 {
366 template<typename R>
367 void rbegin(R &&) = delete;
368 // Non-standard, to keep unqualified rbegin(r) from finding std::rbegin
369 // and returning a std::reverse_iterator.
370 template<typename T>
371 void rbegin(std::initializer_list<T>) = delete;
372 template<typename T, std::size_t N>
373 void rbegin(T (&)[N]) = delete;
374
375 // clang-format off
378 template<typename T>
379 CPP_requires(has_member_rbegin_,
380 requires(T & t) //
381 (
382 _begin_::is_iterator(t.rbegin())
383 ));
386 template<typename T>
387 CPP_concept has_member_rbegin =
388 CPP_requires_ref(_rbegin_::has_member_rbegin_, T);
389
392 template<typename T>
393 CPP_requires(has_non_member_rbegin_,
394 requires(T & t) //
395 (
396 _begin_::is_iterator(rbegin(t))
397 ));
400 template<typename T>
401 CPP_concept has_non_member_rbegin =
402 CPP_requires_ref(_rbegin_::has_non_member_rbegin_, T);
403
404 template<typename I>
405 void _same_type(I, I);
406
409 template<typename T>
410 CPP_requires(can_reverse_end_,
411 requires(T & t) //
412 (
413 // make_reverse_iterator is constrained with
414 // bidirectional_iterator.
415 ranges::make_reverse_iterator(ranges::end(t)),
416 _rbegin_::_same_type(ranges::begin(t), ranges::end(t))
417 ));
420 template<typename T>
421 CPP_concept can_reverse_end =
422 CPP_requires_ref(_rbegin_::can_reverse_end_, T);
423 // clang-format on
424
425 struct fn
426 {
427 private:
428 struct _member_result_
429 {
430 template<typename R>
431 using invoke = decltype(detail::_decay_copy(declval(R &).rbegin()));
432 };
433 struct _non_member_result_
434 {
435 template<typename R>
436 using invoke = decltype(detail::_decay_copy(rbegin(declval(R &))));
437 };
438 struct _reverse_result_
439 {
440 template<typename R>
441 using invoke =
442 decltype(ranges::make_reverse_iterator(ranges::end(declval(R &))));
443 };
444 struct _other_result_
445 {
446 template<typename R>
447 using invoke =
450 has_non_member_rbegin<R>,
451 _non_member_result_,
452 _reverse_result_>,
453 R>;
454 };
455
456 template<typename R>
457 using _result_t =
460 has_member_rbegin<R>,
461 _member_result_,
462 _other_result_>,
463 R>;
464
465 public:
466 template(typename R)(
467 requires detail::_borrowed_range<R> AND has_member_rbegin<R>)
468 constexpr auto operator()(R && r) const //
469 noexcept(noexcept(r.rbegin())) //
470 {
471 return r.rbegin();
472 }
473
474 template(typename R)(
475 requires detail::_borrowed_range<R> AND (!has_member_rbegin<R>) AND
476 has_non_member_rbegin<R>)
477 constexpr auto operator()(R && r) const //
478 noexcept(noexcept(rbegin(r))) //
479 {
480 return rbegin(r);
481 }
482
483 template(typename R)(
484 requires detail::_borrowed_range<R> AND (!has_member_rbegin<R>) AND
485 (!has_non_member_rbegin<R>) AND can_reverse_end<R>)
486 constexpr auto operator()(R && r) const //
487 noexcept(noexcept(ranges::make_reverse_iterator(ranges::end(r))))
488 {
489 return ranges::make_reverse_iterator(ranges::end(r));
490 }
491 };
492
493 template<typename R>
494 using _t = decltype(fn{}(declval(R &&)));
495 } // namespace _rbegin_
497
505 RANGES_DEFINE_CPO(_rbegin_::fn, rbegin)
506
507
508 namespace _rend_
509 {
510 template<typename R>
511 void rend(R &&) = delete;
512 // Non-standard, to keep unqualified rend(r) from finding std::rend
513 // and returning a std::reverse_iterator.
514 template<typename T>
515 void rend(std::initializer_list<T>) = delete;
516 template<typename T, std::size_t N>
517 void rend(T (&)[N]) = delete;
518
519 // clang-format off
522 template<typename T>
523 CPP_requires(has_member_rend_,
524 requires(T & t) //
525 (
526 _end_::_is_sentinel(t.rend(), ranges::rbegin(t))
527 ));
530 template<typename T>
531 CPP_concept has_member_rend =
532 CPP_requires_ref(_rend_::has_member_rend_, T);
533
536 template<typename T>
537 CPP_requires(has_non_member_rend_,
538 requires(T & t) //
539 (
540 _end_::_is_sentinel(rend(t), ranges::rbegin(t))
541 ));
544 template<typename T>
545 CPP_concept has_non_member_rend =
546 CPP_requires_ref(_rend_::has_non_member_rend_, T);
547
550 template<typename T>
551 CPP_requires(can_reverse_begin_,
552 requires(T & t) //
553 (
554 // make_reverse_iterator is constrained with
555 // bidirectional_iterator.
556 ranges::make_reverse_iterator(ranges::begin(t)),
557 _rbegin_::_same_type(ranges::begin(t), ranges::end(t))
558 ));
561 template<typename T>
562 CPP_concept can_reverse_begin =
563 CPP_requires_ref(_rend_::can_reverse_begin_, T);
564 // clang-format on
565
566 struct fn
567 {
568 private:
569 struct _member_result_
570 {
571 template<typename R>
572 using invoke = decltype(detail::_decay_copy(declval(R &).rend()));
573 };
574 struct _non_member_result_
575 {
576 template<typename R>
577 using invoke = decltype(detail::_decay_copy(rend(declval(R &))));
578 };
579 struct _reverse_result_
580 {
581 template<typename R>
582 using invoke =
583 decltype(ranges::make_reverse_iterator(ranges::begin(declval(R &))));
584 };
585 struct _other_result_
586 {
587 template<typename R>
588 using invoke =
591 has_non_member_rend<R>,
592 _non_member_result_,
593 _reverse_result_>,
594 R>;
595 };
596
597 template<typename R>
598 using _result_t =
601 has_member_rend<R>,
602 _member_result_,
603 _other_result_>,
604 R>;
605
606 public:
607 template(typename R)(
608 requires detail::_borrowed_range<R> AND has_member_rend<R>)
609 constexpr auto operator()(R && r) const //
610 noexcept(noexcept(r.rend())) //
611 {
612 return r.rend();
613 }
614
615 template(typename R)(
616 requires detail::_borrowed_range<R> AND (!has_member_rend<R>) AND
617 has_non_member_rend<R>)
618 constexpr auto operator()(R && r) const //
619 noexcept(noexcept(rend(r))) //
620 {
621 return rend(r);
622 }
623
624 template(typename R)(
625 requires detail::_borrowed_range<R> AND (!has_member_rend<R>) AND
626 (!has_non_member_rend<R>) AND can_reverse_begin<R>)
627 constexpr auto operator()(R && r) const //
628 noexcept(noexcept(ranges::make_reverse_iterator(ranges::begin(r))))
629 {
630 return ranges::make_reverse_iterator(ranges::begin(r));
631 }
632 };
633
634 template<typename R>
635 using _t = decltype(fn{}(declval(R &&)));
636 } // namespace _rend_
638
647 RANGES_DEFINE_CPO(_rend_::fn, rend)
648
649
650 namespace _crbegin_
651 {
652 struct fn
653 {
654 template<typename T, std::size_t N>
655 void operator()(T(&&)[N]) const = delete;
656
657 template<typename R>
658 constexpr _rbegin_::_t<detail::as_const_t<R>> operator()(R && r) const
659 noexcept(noexcept(ranges::rbegin(detail::as_const(r))))
660 {
661 return ranges::rbegin(detail::as_const(r));
662 }
663 };
664 } // namespace _crbegin_
666
671 RANGES_INLINE_VARIABLE(_crbegin_::fn, crbegin)
672
673
674 namespace _crend_
675 {
676 struct fn
677 {
678 template<typename T, std::size_t N>
679 void operator()(T(&&)[N]) const = delete;
680
681 template<typename R>
682 constexpr _rend_::_t<detail::as_const_t<R>> operator()(R && r) const
683 noexcept(noexcept(ranges::rend(detail::as_const(r))))
684 {
685 return ranges::rend(detail::as_const(r));
686 }
687 };
688 } // namespace _crend_
690
695 RANGES_INLINE_VARIABLE(_crend_::fn, crend)
696
697 template<typename Rng>
698 using iterator_t = decltype(begin(declval(Rng &)));
699
700 template<typename Rng>
701 using sentinel_t = decltype(end(declval(Rng &)));
702
703 namespace cpp20
704 {
705 using ranges::begin;
706 using ranges::cbegin;
707 using ranges::cend;
708 using ranges::crbegin;
709 using ranges::crend;
710 using ranges::end;
711 using ranges::rbegin;
712 using ranges::rend;
713
714 using ranges::iterator_t;
715 using ranges::sentinel_t;
716
717 using ranges::enable_borrowed_range;
718 } // namespace cpp20
719} // namespace ranges
720
721#include <range/v3/detail/epilogue.hpp>
722
723#endif
decltype(begin(declval(Rng &))) iterator_t
Definition access.hpp:698
typename T::type _t
Type alias for T::type.
Definition meta.hpp:141
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition meta.hpp:541
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
@ array
array (ordered collection of values)
Point operator-(const Point &a, const Point &b)
Subtract two points_ component-wise.
Definition shapes.h:244
A trait that always returns its argument T.
Definition meta.hpp:558