libstdc++
ranges_base.h
Go to the documentation of this file.
1// Core concepts and definitions for <ranges> -*- C++ -*-
2
3// Copyright (C) 2019-2022 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/ranges_base.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{ranges}
28 */
29
30#ifndef _GLIBCXX_RANGES_BASE_H
31#define _GLIBCXX_RANGES_BASE_H 1
32
33#pragma GCC system_header
34
35#if __cplusplus > 201703L
36#include <initializer_list>
38#include <ext/numeric_traits.h>
39#include <bits/max_size_type.h>
40
41#ifdef __cpp_lib_concepts
42namespace std _GLIBCXX_VISIBILITY(default)
43{
44_GLIBCXX_BEGIN_NAMESPACE_VERSION
45namespace ranges
46{
47 template<typename>
48 inline constexpr bool disable_sized_range = false;
49
50 template<typename _Tp>
51 inline constexpr bool enable_borrowed_range = false;
52
53 namespace __detail
54 {
55 constexpr __max_size_type
56 __to_unsigned_like(__max_size_type __t) noexcept
57 { return __t; }
58
59 constexpr __max_size_type
60 __to_unsigned_like(__max_diff_type __t) noexcept
61 { return __max_size_type(__t); }
62
63 template<integral _Tp>
64 constexpr auto
65 __to_unsigned_like(_Tp __t) noexcept
66 { return static_cast<make_unsigned_t<_Tp>>(__t); }
67
68#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
69 constexpr unsigned __int128
70 __to_unsigned_like(__int128 __t) noexcept
71 { return __t; }
72
73 constexpr unsigned __int128
74 __to_unsigned_like(unsigned __int128 __t) noexcept
75 { return __t; }
76#endif
77
78 template<typename _Tp>
79 using __make_unsigned_like_t
80 = decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
81
82 // Part of the constraints of ranges::borrowed_range
83 template<typename _Tp>
84 concept __maybe_borrowed_range
85 = is_lvalue_reference_v<_Tp>
86 || enable_borrowed_range<remove_cvref_t<_Tp>>;
87
88 } // namespace __detail
89
90 namespace __cust_access
91 {
92 using std::ranges::__detail::__maybe_borrowed_range;
93 using std::__detail::__range_iter_t;
94
95 struct _Begin
96 {
97 private:
98 template<typename _Tp>
99 static constexpr bool
100 _S_noexcept()
101 {
102 if constexpr (is_array_v<remove_reference_t<_Tp>>)
103 return true;
104 else if constexpr (__member_begin<_Tp>)
105 return noexcept(__decay_copy(std::declval<_Tp&>().begin()));
106 else
107 return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
108 }
109
110 public:
111 template<__maybe_borrowed_range _Tp>
112 requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
113 || __adl_begin<_Tp>
114 constexpr auto
115 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
116 {
117 if constexpr (is_array_v<remove_reference_t<_Tp>>)
118 {
119 static_assert(is_lvalue_reference_v<_Tp>);
120 return __t + 0;
121 }
122 else if constexpr (__member_begin<_Tp>)
123 return __t.begin();
124 else
125 return begin(__t);
126 }
127 };
128
129 template<typename _Tp>
130 concept __member_end = requires(_Tp& __t)
131 {
132 { __decay_copy(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>;
133 };
134
135 // Poison pills so that unqualified lookup doesn't find std::end.
136 void end(auto&) = delete;
137 void end(const auto&) = delete;
138
139 template<typename _Tp>
140 concept __adl_end = __class_or_enum<remove_reference_t<_Tp>>
141 && requires(_Tp& __t)
142 {
143 { __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
144 };
145
146 struct _End
147 {
148 private:
149 template<typename _Tp>
150 static constexpr bool
151 _S_noexcept()
152 {
153 if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
154 return true;
155 else if constexpr (__member_end<_Tp>)
156 return noexcept(__decay_copy(std::declval<_Tp&>().end()));
157 else
158 return noexcept(__decay_copy(end(std::declval<_Tp&>())));
159 }
160
161 public:
162 template<__maybe_borrowed_range _Tp>
163 requires is_bounded_array_v<remove_reference_t<_Tp>>
164 || __member_end<_Tp> || __adl_end<_Tp>
165 constexpr auto
166 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
167 {
168 if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
169 {
170 static_assert(is_lvalue_reference_v<_Tp>);
171 return __t + extent_v<remove_reference_t<_Tp>>;
172 }
173 else if constexpr (__member_end<_Tp>)
174 return __t.end();
175 else
176 return end(__t);
177 }
178 };
179
180 // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&.
181 template<typename _To, typename _Tp>
182 constexpr decltype(auto)
183 __as_const(_Tp& __t) noexcept
184 {
185 static_assert(std::is_same_v<_To&, _Tp&>);
186
187 if constexpr (is_lvalue_reference_v<_To>)
188 return const_cast<const _Tp&>(__t);
189 else
190 return static_cast<const _Tp&&>(__t);
191 }
192
193 struct _CBegin
194 {
195 template<typename _Tp>
196 [[nodiscard]]
197 constexpr auto
198 operator()(_Tp&& __e) const
199 noexcept(noexcept(_Begin{}(__cust_access::__as_const<_Tp>(__e))))
200 requires requires { _Begin{}(__cust_access::__as_const<_Tp>(__e)); }
201 {
202 return _Begin{}(__cust_access::__as_const<_Tp>(__e));
203 }
204 };
205
206 struct _CEnd final
207 {
208 template<typename _Tp>
209 [[nodiscard]]
210 constexpr auto
211 operator()(_Tp&& __e) const
212 noexcept(noexcept(_End{}(__cust_access::__as_const<_Tp>(__e))))
213 requires requires { _End{}(__cust_access::__as_const<_Tp>(__e)); }
214 {
215 return _End{}(__cust_access::__as_const<_Tp>(__e));
216 }
217 };
218
219 template<typename _Tp>
220 concept __member_rbegin = requires(_Tp& __t)
221 {
222 { __decay_copy(__t.rbegin()) } -> input_or_output_iterator;
223 };
224
225 void rbegin(auto&) = delete;
226 void rbegin(const auto&) = delete;
227
228 template<typename _Tp>
229 concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>>
230 && requires(_Tp& __t)
231 {
232 { __decay_copy(rbegin(__t)) } -> input_or_output_iterator;
233 };
234
235 template<typename _Tp>
236 concept __reversable = requires(_Tp& __t)
237 {
238 { _Begin{}(__t) } -> bidirectional_iterator;
239 { _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>;
240 };
241
242 struct _RBegin
243 {
244 private:
245 template<typename _Tp>
246 static constexpr bool
247 _S_noexcept()
248 {
249 if constexpr (__member_rbegin<_Tp>)
250 return noexcept(__decay_copy(std::declval<_Tp&>().rbegin()));
251 else if constexpr (__adl_rbegin<_Tp>)
252 return noexcept(__decay_copy(rbegin(std::declval<_Tp&>())));
253 else
254 {
255 if constexpr (noexcept(_End{}(std::declval<_Tp&>())))
256 {
257 using _It = decltype(_End{}(std::declval<_Tp&>()));
258 // std::reverse_iterator copy-initializes its member.
259 return is_nothrow_copy_constructible_v<_It>;
260 }
261 else
262 return false;
263 }
264 }
265
266 public:
267 template<__maybe_borrowed_range _Tp>
268 requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
269 constexpr auto
270 operator()[[nodiscard]](_Tp&& __t) const
271 noexcept(_S_noexcept<_Tp&>())
272 {
273 if constexpr (__member_rbegin<_Tp>)
274 return __t.rbegin();
275 else if constexpr (__adl_rbegin<_Tp>)
276 return rbegin(__t);
277 else
278 return std::make_reverse_iterator(_End{}(__t));
279 }
280 };
281
282 template<typename _Tp>
283 concept __member_rend = requires(_Tp& __t)
284 {
285 { __decay_copy(__t.rend()) }
286 -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
287 };
288
289 void rend(auto&) = delete;
290 void rend(const auto&) = delete;
291
292 template<typename _Tp>
293 concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>>
294 && requires(_Tp& __t)
295 {
296 { __decay_copy(rend(__t)) }
297 -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
298 };
299
300 struct _REnd
301 {
302 private:
303 template<typename _Tp>
304 static constexpr bool
305 _S_noexcept()
306 {
307 if constexpr (__member_rend<_Tp>)
308 return noexcept(__decay_copy(std::declval<_Tp&>().rend()));
309 else if constexpr (__adl_rend<_Tp>)
310 return noexcept(__decay_copy(rend(std::declval<_Tp&>())));
311 else
312 {
313 if constexpr (noexcept(_Begin{}(std::declval<_Tp&>())))
314 {
315 using _It = decltype(_Begin{}(std::declval<_Tp&>()));
316 // std::reverse_iterator copy-initializes its member.
317 return is_nothrow_copy_constructible_v<_It>;
318 }
319 else
320 return false;
321 }
322 }
323
324 public:
325 template<__maybe_borrowed_range _Tp>
326 requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
327 constexpr auto
328 operator()[[nodiscard]](_Tp&& __t) const
329 noexcept(_S_noexcept<_Tp&>())
330 {
331 if constexpr (__member_rend<_Tp>)
332 return __t.rend();
333 else if constexpr (__adl_rend<_Tp>)
334 return rend(__t);
335 else
336 return std::make_reverse_iterator(_Begin{}(__t));
337 }
338 };
339
340 struct _CRBegin
341 {
342 template<typename _Tp>
343 [[nodiscard]]
344 constexpr auto
345 operator()(_Tp&& __e) const
346 noexcept(noexcept(_RBegin{}(__cust_access::__as_const<_Tp>(__e))))
347 requires requires { _RBegin{}(__cust_access::__as_const<_Tp>(__e)); }
348 {
349 return _RBegin{}(__cust_access::__as_const<_Tp>(__e));
350 }
351 };
352
353 struct _CREnd
354 {
355 template<typename _Tp>
356 [[nodiscard]]
357 constexpr auto
358 operator()(_Tp&& __e) const
359 noexcept(noexcept(_REnd{}(__cust_access::__as_const<_Tp>(__e))))
360 requires requires { _REnd{}(__cust_access::__as_const<_Tp>(__e)); }
361 {
362 return _REnd{}(__cust_access::__as_const<_Tp>(__e));
363 }
364 };
365
366 template<typename _Tp>
367 concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
368 && requires(_Tp& __t)
369 {
370 { __decay_copy(__t.size()) } -> __detail::__is_integer_like;
371 };
372
373 void size(auto&) = delete;
374 void size(const auto&) = delete;
375
376 template<typename _Tp>
377 concept __adl_size = __class_or_enum<remove_reference_t<_Tp>>
378 && !disable_sized_range<remove_cvref_t<_Tp>>
379 && requires(_Tp& __t)
380 {
381 { __decay_copy(size(__t)) } -> __detail::__is_integer_like;
382 };
383
384 template<typename _Tp>
385 concept __sentinel_size = requires(_Tp& __t)
386 {
387 requires (!is_unbounded_array_v<remove_reference_t<_Tp>>);
388
389 { _Begin{}(__t) } -> forward_iterator;
390
391 { _End{}(__t) } -> sized_sentinel_for<decltype(_Begin{}(__t))>;
392
393 __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
394 };
395
396 struct _Size
397 {
398 private:
399 template<typename _Tp>
400 static constexpr bool
401 _S_noexcept()
402 {
403 if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
404 return true;
405 else if constexpr (__member_size<_Tp>)
406 return noexcept(__decay_copy(std::declval<_Tp&>().size()));
407 else if constexpr (__adl_size<_Tp>)
408 return noexcept(__decay_copy(size(std::declval<_Tp&>())));
409 else if constexpr (__sentinel_size<_Tp>)
410 return noexcept(_End{}(std::declval<_Tp&>())
411 - _Begin{}(std::declval<_Tp&>()));
412 }
413
414 public:
415 template<typename _Tp>
416 requires is_bounded_array_v<remove_reference_t<_Tp>>
417 || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
418 constexpr auto
419 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
420 {
421 if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
422 return extent_v<remove_reference_t<_Tp>>;
423 else if constexpr (__member_size<_Tp>)
424 return __t.size();
425 else if constexpr (__adl_size<_Tp>)
426 return size(__t);
427 else if constexpr (__sentinel_size<_Tp>)
428 return __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
429 }
430 };
431
432 struct _SSize
433 {
434 // _GLIBCXX_RESOLVE_LIB_DEFECTS
435 // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
436 template<typename _Tp>
437 requires requires (_Tp& __t) { _Size{}(__t); }
438 constexpr auto
439 operator()[[nodiscard]](_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
440 {
441 auto __size = _Size{}(__t);
442 using __size_type = decltype(__size);
443 // Return the wider of ptrdiff_t and make-signed-like-t<__size_type>.
444 if constexpr (integral<__size_type>)
445 {
447 if constexpr (__int_traits<__size_type>::__digits
448 < __int_traits<ptrdiff_t>::__digits)
449 return static_cast<ptrdiff_t>(__size);
450 else
451 return static_cast<make_signed_t<__size_type>>(__size);
452 }
453#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
454 // For strict-ansi modes integral<__int128> is false
455 else if constexpr (__detail::__is_int128<__size_type>)
456 return static_cast<__int128>(__size);
457#endif
458 else // Must be one of __max_diff_type or __max_size_type.
459 return __detail::__max_diff_type(__size);
460 }
461 };
462
463 template<typename _Tp>
464 concept __member_empty = requires(_Tp& __t) { bool(__t.empty()); };
465
466 template<typename _Tp>
467 concept __size0_empty = requires(_Tp& __t) { _Size{}(__t) == 0; };
468
469 template<typename _Tp>
470 concept __eq_iter_empty = requires(_Tp& __t)
471 {
472 requires (!is_unbounded_array_v<remove_reference_t<_Tp>>);
473
474 { _Begin{}(__t) } -> forward_iterator;
475
476 bool(_Begin{}(__t) == _End{}(__t));
477 };
478
479 struct _Empty
480 {
481 private:
482 template<typename _Tp>
483 static constexpr bool
484 _S_noexcept()
485 {
486 if constexpr (__member_empty<_Tp>)
487 return noexcept(bool(std::declval<_Tp&>().empty()));
488 else if constexpr (__size0_empty<_Tp>)
489 return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
490 else
491 return noexcept(bool(_Begin{}(std::declval<_Tp&>())
492 == _End{}(std::declval<_Tp&>())));
493 }
494
495 public:
496 template<typename _Tp>
497 requires __member_empty<_Tp> || __size0_empty<_Tp>
498 || __eq_iter_empty<_Tp>
499 constexpr bool
500 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
501 {
502 if constexpr (__member_empty<_Tp>)
503 return bool(__t.empty());
504 else if constexpr (__size0_empty<_Tp>)
505 return _Size{}(__t) == 0;
506 else
507 return bool(_Begin{}(__t) == _End{}(__t));
508 }
509 };
510
511 template<typename _Tp>
512 concept __pointer_to_object = is_pointer_v<_Tp>
513 && is_object_v<remove_pointer_t<_Tp>>;
514
515 template<typename _Tp>
516 concept __member_data = requires(_Tp& __t)
517 {
518 { __decay_copy(__t.data()) } -> __pointer_to_object;
519 };
520
521 template<typename _Tp>
522 concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>;
523
524 struct _Data
525 {
526 private:
527 template<typename _Tp>
528 static constexpr bool
529 _S_noexcept()
530 {
531 if constexpr (__member_data<_Tp>)
532 return noexcept(__decay_copy(std::declval<_Tp&>().data()));
533 else
534 return noexcept(_Begin{}(std::declval<_Tp&>()));
535 }
536
537 public:
538 template<__maybe_borrowed_range _Tp>
539 requires __member_data<_Tp> || __begin_data<_Tp>
540 constexpr auto
541 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
542 {
543 if constexpr (__member_data<_Tp>)
544 return __t.data();
545 else
546 return std::to_address(_Begin{}(__t));
547 }
548 };
549
550 struct _CData
551 {
552 template<typename _Tp>
553 [[nodiscard]]
554 constexpr auto
555 operator()(_Tp&& __e) const
556 noexcept(noexcept(_Data{}(__cust_access::__as_const<_Tp>(__e))))
557 requires requires { _Data{}(__cust_access::__as_const<_Tp>(__e)); }
558 {
559 return _Data{}(__cust_access::__as_const<_Tp>(__e));
560 }
561 };
562
563 } // namespace __cust_access
564
565 inline namespace __cust
566 {
567 inline constexpr __cust_access::_Begin begin{};
568 inline constexpr __cust_access::_End end{};
569 inline constexpr __cust_access::_CBegin cbegin{};
570 inline constexpr __cust_access::_CEnd cend{};
571 inline constexpr __cust_access::_RBegin rbegin{};
572 inline constexpr __cust_access::_REnd rend{};
573 inline constexpr __cust_access::_CRBegin crbegin{};
574 inline constexpr __cust_access::_CREnd crend{};
575 inline constexpr __cust_access::_Size size{};
576 inline constexpr __cust_access::_SSize ssize{};
577 inline constexpr __cust_access::_Empty empty{};
578 inline constexpr __cust_access::_Data data{};
579 inline constexpr __cust_access::_CData cdata{};
580 }
581
582 /// [range.range] The range concept.
583 template<typename _Tp>
584 concept range = requires(_Tp& __t)
585 {
586 ranges::begin(__t);
587 ranges::end(__t);
588 };
589
590 /// [range.range] The borrowed_range concept.
591 template<typename _Tp>
593 = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
594
595 template<typename _Tp>
596 using iterator_t = std::__detail::__range_iter_t<_Tp>;
597
598 template<range _Range>
599 using sentinel_t = decltype(ranges::end(std::declval<_Range&>()));
600
601 template<range _Range>
602 using range_difference_t = iter_difference_t<iterator_t<_Range>>;
603
604 template<range _Range>
605 using range_value_t = iter_value_t<iterator_t<_Range>>;
606
607 template<range _Range>
608 using range_reference_t = iter_reference_t<iterator_t<_Range>>;
609
610 template<range _Range>
611 using range_rvalue_reference_t
612 = iter_rvalue_reference_t<iterator_t<_Range>>;
613
614 /// [range.sized] The sized_range concept.
615 template<typename _Tp>
617 && requires(_Tp& __t) { ranges::size(__t); };
618
619 template<sized_range _Range>
620 using range_size_t = decltype(ranges::size(std::declval<_Range&>()));
621
622 template<typename _Derived>
623 requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
624 class view_interface; // defined in <bits/ranges_util.h>
625
626 namespace __detail
627 {
628 template<typename _Tp, typename _Up>
630 void __is_derived_from_view_interface_fn(const _Tp&,
631 const view_interface<_Up>&); // not defined
632
633 // Returns true iff _Tp has exactly one public base class that's a
634 // specialization of view_interface.
635 template<typename _Tp>
636 concept __is_derived_from_view_interface
637 = requires (_Tp __t) { __is_derived_from_view_interface_fn(__t, __t); };
638 } // namespace __detail
639
640 /// [range.view] The ranges::view_base type.
641 struct view_base { };
642
643 /// [range.view] The ranges::enable_view boolean.
644 template<typename _Tp>
646 || __detail::__is_derived_from_view_interface<_Tp>;
647
648 /// [range.view] The ranges::view concept.
649 template<typename _Tp>
650 concept view
651 = range<_Tp> && movable<_Tp> && enable_view<_Tp>;
652
653 // [range.refinements]
654
655 /// A range for which ranges::begin returns an output iterator.
656 template<typename _Range, typename _Tp>
658 = range<_Range> && output_iterator<iterator_t<_Range>, _Tp>;
659
660 /// A range for which ranges::begin returns an input iterator.
661 template<typename _Tp>
662 concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>;
663
664 /// A range for which ranges::begin returns a forward iterator.
665 template<typename _Tp>
667 = input_range<_Tp> && forward_iterator<iterator_t<_Tp>>;
668
669 /// A range for which ranges::begin returns a bidirectional iterator.
670 template<typename _Tp>
672 = forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp>>;
673
674 /// A range for which ranges::begin returns a random access iterator.
675 template<typename _Tp>
677 = bidirectional_range<_Tp> && random_access_iterator<iterator_t<_Tp>>;
678
679 /// A range for which ranges::begin returns a contiguous iterator.
680 template<typename _Tp>
682 = random_access_range<_Tp> && contiguous_iterator<iterator_t<_Tp>>
683 && requires(_Tp& __t)
684 {
685 { ranges::data(__t) } -> same_as<add_pointer_t<range_reference_t<_Tp>>>;
686 };
687
688 /// A range for which ranges::begin and ranges::end return the same type.
689 template<typename _Tp>
691 = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>;
692
693 namespace __detail
694 {
695 template<typename _Tp>
696 inline constexpr bool __is_initializer_list = false;
697
698 template<typename _Tp>
699 inline constexpr bool __is_initializer_list<initializer_list<_Tp>> = true;
700 } // namespace __detail
701
702 /// A range which can be safely converted to a view.
703 template<typename _Tp>
706 || (!view<remove_cvref_t<_Tp>>
707 && (is_lvalue_reference_v<_Tp>
708 || (movable<remove_reference_t<_Tp>>
709 && !__detail::__is_initializer_list<remove_cvref_t<_Tp>>))));
710
711 // [range.iter.ops] range iterator operations
712
713 struct __advance_fn final
714 {
715 template<input_or_output_iterator _It>
716 constexpr void
717 operator()(_It& __it, iter_difference_t<_It> __n) const
718 {
719 if constexpr (random_access_iterator<_It>)
720 __it += __n;
721 else if constexpr (bidirectional_iterator<_It>)
722 {
723 if (__n > 0)
724 {
725 do
726 {
727 ++__it;
728 }
729 while (--__n);
730 }
731 else if (__n < 0)
732 {
733 do
734 {
735 --__it;
736 }
737 while (++__n);
738 }
739 }
740 else
741 {
742 // cannot decrement a non-bidirectional iterator
743 __glibcxx_assert(__n >= 0);
744 while (__n-- > 0)
745 ++__it;
746 }
747 }
748
749 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
750 constexpr void
751 operator()(_It& __it, _Sent __bound) const
752 {
753 if constexpr (assignable_from<_It&, _Sent>)
754 __it = std::move(__bound);
755 else if constexpr (sized_sentinel_for<_Sent, _It>)
756 (*this)(__it, __bound - __it);
757 else
758 {
759 while (__it != __bound)
760 ++__it;
761 }
762 }
763
764 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
765 constexpr iter_difference_t<_It>
766 operator()(_It& __it, iter_difference_t<_It> __n, _Sent __bound) const
767 {
768 if constexpr (sized_sentinel_for<_Sent, _It>)
769 {
770 const auto __diff = __bound - __it;
771
772 if (__diff == 0)
773 return __n;
774 else if (__diff > 0 ? __n >= __diff : __n <= __diff)
775 {
776 (*this)(__it, __bound);
777 return __n - __diff;
778 }
779 else if (__n != 0) [[likely]]
780 {
781 // n and bound must not lead in opposite directions:
782 __glibcxx_assert((__n < 0) == (__diff < 0));
783
784 (*this)(__it, __n);
785 return 0;
786 }
787 else
788 return 0;
789 }
790 else if (__it == __bound || __n == 0)
791 return __n;
792 else if (__n > 0)
793 {
794 iter_difference_t<_It> __m = 0;
795 do
796 {
797 ++__it;
798 ++__m;
799 }
800 while (__m != __n && __it != __bound);
801 return __n - __m;
802 }
803 else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>)
804 {
805 iter_difference_t<_It> __m = 0;
806 do
807 {
808 --__it;
809 --__m;
810 }
811 while (__m != __n && __it != __bound);
812 return __n - __m;
813 }
814 else
815 {
816 // cannot decrement a non-bidirectional iterator
817 __glibcxx_assert(__n >= 0);
818 return __n;
819 }
820 }
821
822 void operator&() const = delete;
823 };
824
825 inline constexpr __advance_fn advance{};
826
827 struct __distance_fn final
828 {
829 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
830 requires (!sized_sentinel_for<_Sent, _It>)
831 constexpr iter_difference_t<_It>
832 operator()[[nodiscard]](_It __first, _Sent __last) const
833 {
834 iter_difference_t<_It> __n = 0;
835 while (__first != __last)
836 {
837 ++__first;
838 ++__n;
839 }
840 return __n;
841 }
842
843 template<input_or_output_iterator _It, sized_sentinel_for<_It> _Sent>
844 [[nodiscard]]
845 constexpr iter_difference_t<_It>
846 operator()(const _It& __first, const _Sent& __last) const
847 {
848 return __last - __first;
849 }
850
851 template<range _Range>
852 [[nodiscard]]
853 constexpr range_difference_t<_Range>
854 operator()(_Range&& __r) const
855 {
856 if constexpr (sized_range<_Range>)
857 return static_cast<range_difference_t<_Range>>(ranges::size(__r));
858 else
859 return (*this)(ranges::begin(__r), ranges::end(__r));
860 }
861
862 void operator&() const = delete;
863 };
864
865 inline constexpr __distance_fn distance{};
866
867 struct __next_fn final
868 {
869 template<input_or_output_iterator _It>
870 [[nodiscard]]
871 constexpr _It
872 operator()(_It __x) const
873 {
874 ++__x;
875 return __x;
876 }
877
878 template<input_or_output_iterator _It>
879 [[nodiscard]]
880 constexpr _It
881 operator()(_It __x, iter_difference_t<_It> __n) const
882 {
883 ranges::advance(__x, __n);
884 return __x;
885 }
886
887 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
888 [[nodiscard]]
889 constexpr _It
890 operator()(_It __x, _Sent __bound) const
891 {
892 ranges::advance(__x, __bound);
893 return __x;
894 }
895
896 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
897 [[nodiscard]]
898 constexpr _It
899 operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const
900 {
901 ranges::advance(__x, __n, __bound);
902 return __x;
903 }
904
905 void operator&() const = delete;
906 };
907
908 inline constexpr __next_fn next{};
909
910 struct __prev_fn final
911 {
912 template<bidirectional_iterator _It>
913 [[nodiscard]]
914 constexpr _It
915 operator()(_It __x) const
916 {
917 --__x;
918 return __x;
919 }
920
921 template<bidirectional_iterator _It>
922 [[nodiscard]]
923 constexpr _It
924 operator()(_It __x, iter_difference_t<_It> __n) const
925 {
926 ranges::advance(__x, -__n);
927 return __x;
928 }
929
930 template<bidirectional_iterator _It>
931 [[nodiscard]]
932 constexpr _It
933 operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const
934 {
935 ranges::advance(__x, -__n, __bound);
936 return __x;
937 }
938
939 void operator&() const = delete;
940 };
941
942 inline constexpr __prev_fn prev{};
943
944 /// Type returned by algorithms instead of a dangling iterator or subrange.
945 struct dangling
946 {
947 constexpr dangling() noexcept = default;
948 template<typename... _Args>
949 constexpr dangling(_Args&&...) noexcept { }
950 };
951
952 template<range _Range>
953 using borrowed_iterator_t = __conditional_t<borrowed_range<_Range>,
954 iterator_t<_Range>,
955 dangling>;
956
957} // namespace ranges
958_GLIBCXX_END_NAMESPACE_VERSION
959} // namespace std
960#endif // library concepts
961#endif // C++20
962#endif // _GLIBCXX_RANGES_BASE_H
constexpr bool enable_view
[range.view] The ranges::enable_view boolean.
Definition: ranges_base.h:645
constexpr _Tp * to_address(_Tp *__ptr) noexcept
Obtain address referenced by a pointer to an object.
Definition: ptr_traits.h:247
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:104
_Tp * end(valarray< _Tp > &__va) noexcept
Return an iterator pointing to one past the last element of the valarray.
Definition: valarray:1239
_Tp * begin(valarray< _Tp > &__va) noexcept
Return an iterator pointing to the first element of the valarray.
Definition: valarray:1217
constexpr reverse_iterator< _Iterator > make_reverse_iterator(_Iterator __i)
Generator function for reverse_iterator.
ISO C++ entities toplevel namespace is std.
constexpr auto crend(const _Container &__cont) -> decltype(std::rend(__cont))
Return a reverse iterator pointing one past the first element of the const container.
Definition: range_access.h:249
constexpr auto rend(_Container &__cont) -> decltype(__cont.rend())
Return a reverse iterator pointing one past the first element of the container.
Definition: range_access.h:172
constexpr iterator_traits< _InputIterator >::difference_type distance(_InputIterator __first, _InputIterator __last)
A generalization of pointer arithmetic.
constexpr auto cend(const _Container &__cont) noexcept(noexcept(std::end(__cont))) -> decltype(std::end(__cont))
Return an iterator pointing to one past the last element of the const container.
Definition: range_access.h:138
constexpr auto empty(const _Container &__cont) noexcept(noexcept(__cont.empty())) -> decltype(__cont.empty())
Return whether a container is empty.
Definition: range_access.h:283
constexpr auto size(const _Container &__cont) noexcept(noexcept(__cont.size())) -> decltype(__cont.size())
Return the size of a container.
Definition: range_access.h:264
constexpr void advance(_InputIterator &__i, _Distance __n)
A generalization of pointer arithmetic.
constexpr auto rbegin(_Container &__cont) -> decltype(__cont.rbegin())
Return a reverse iterator pointing to the last element of the container.
Definition: range_access.h:150
constexpr auto crbegin(const _Container &__cont) -> decltype(std::rbegin(__cont))
Return a reverse iterator pointing to the last element of the const container.
Definition: range_access.h:238
constexpr auto data(_Container &__cont) noexcept(noexcept(__cont.data())) -> decltype(__cont.data())
Return the data pointer of a container.
Definition: range_access.h:311
constexpr auto cbegin(const _Container &__cont) noexcept(noexcept(std::begin(__cont))) -> decltype(std::begin(__cont))
Return an iterator pointing to the first element of the const container.
Definition: range_access.h:126
constexpr bitset< _Nb > operator&(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition: bitset:1559
__numeric_traits_integer< _Tp > __int_traits
Convenience alias for __numeric_traits<integer-type>.
The ranges::view_interface class template.
Definition: ranges_util.h:65
[range.view] The ranges::view_base type.
Definition: ranges_base.h:641
Type returned by algorithms instead of a dangling iterator or subrange.
Definition: ranges_base.h:946
[concept.same], concept same_as
Definition: concepts:63
[concept.derived], concept derived_from
Definition: concepts:67
[concept.constructible], concept constructible_from
Definition: concepts:137
[range.range] The range concept.
Definition: ranges_base.h:584
[range.range] The borrowed_range concept.
Definition: ranges_base.h:593
[range.sized] The sized_range concept.
Definition: ranges_base.h:616
[range.view] The ranges::view concept.
Definition: ranges_base.h:651
A range for which ranges::begin returns an output iterator.
Definition: ranges_base.h:658
A range for which ranges::begin returns an input iterator.
Definition: ranges_base.h:662
A range for which ranges::begin returns a forward iterator.
Definition: ranges_base.h:667
A range for which ranges::begin returns a bidirectional iterator.
Definition: ranges_base.h:672
A range for which ranges::begin returns a random access iterator.
Definition: ranges_base.h:677
A range for which ranges::begin returns a contiguous iterator.
Definition: ranges_base.h:682
A range for which ranges::begin and ranges::end return the same type.
Definition: ranges_base.h:691
A range which can be safely converted to a view.
Definition: ranges_base.h:704