libstdc++
ranges_base.h
Go to the documentation of this file.
1// Core concepts and definitions for <ranges> -*- C++ -*-
2
3// Copyright (C) 2019-2024 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>
37#include <bits/stl_iterator.h>
38#include <ext/numeric_traits.h>
39#include <bits/max_size_type.h>
40#include <bits/version.h>
41
42#ifdef __cpp_lib_concepts
43namespace std _GLIBCXX_VISIBILITY(default)
44{
45_GLIBCXX_BEGIN_NAMESPACE_VERSION
46namespace ranges
47{
48 template<typename>
49 inline constexpr bool disable_sized_range = false;
50
51 template<typename _Tp>
52 inline constexpr bool enable_borrowed_range = false;
53
54 namespace __detail
55 {
56 constexpr __max_size_type
57 __to_unsigned_like(__max_size_type __t) noexcept
58 { return __t; }
59
60 constexpr __max_size_type
61 __to_unsigned_like(__max_diff_type __t) noexcept
62 { return __max_size_type(__t); }
63
64 template<integral _Tp>
65 constexpr auto
66 __to_unsigned_like(_Tp __t) noexcept
67 { return static_cast<make_unsigned_t<_Tp>>(__t); }
68
69#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
70 constexpr unsigned __int128
71 __to_unsigned_like(__int128 __t) noexcept
72 { return __t; }
73
74 constexpr unsigned __int128
75 __to_unsigned_like(unsigned __int128 __t) noexcept
76 { return __t; }
77#endif
78
79 template<typename _Tp>
80 using __make_unsigned_like_t
81 = decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
82
83 // Part of the constraints of ranges::borrowed_range
84 template<typename _Tp>
85 concept __maybe_borrowed_range
86 = is_lvalue_reference_v<_Tp>
87 || enable_borrowed_range<remove_cvref_t<_Tp>>;
88
89 } // namespace __detail
90
91 // Namespace for helpers for the <ranges> customization points.
92 namespace __access
93 {
94 using std::ranges::__detail::__maybe_borrowed_range;
95 using std::__detail::__range_iter_t;
96
97 struct _Begin
98 {
99 private:
100 template<typename _Tp>
101 static constexpr bool
102 _S_noexcept()
103 {
104 if constexpr (is_array_v<remove_reference_t<_Tp>>)
105 return true;
106 else if constexpr (__member_begin<_Tp>)
107 return noexcept(__decay_copy(std::declval<_Tp&>().begin()));
108 else
109 return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
110 }
111
112 public:
113 template<__maybe_borrowed_range _Tp>
114 requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
115 || __adl_begin<_Tp>
116 constexpr auto
117 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
118 {
119 if constexpr (is_array_v<remove_reference_t<_Tp>>)
120 {
121 static_assert(is_lvalue_reference_v<_Tp>);
122 return __t + 0;
123 }
124 else if constexpr (__member_begin<_Tp>)
125 return __t.begin();
126 else
127 return begin(__t);
128 }
129 };
130
131 template<typename _Tp>
132 concept __member_end = requires(_Tp& __t)
133 {
134 { __decay_copy(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>;
135 };
136
137 // Poison pill so that unqualified lookup doesn't find std::end.
138 void end() = delete;
139
140 template<typename _Tp>
141 concept __adl_end = __class_or_enum<remove_reference_t<_Tp>>
142 && requires(_Tp& __t)
143 {
144 { __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
145 };
146
147 struct _End
148 {
149 private:
150 template<typename _Tp>
151 static constexpr bool
152 _S_noexcept()
153 {
154 if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
155 return true;
156 else if constexpr (__member_end<_Tp>)
157 return noexcept(__decay_copy(std::declval<_Tp&>().end()));
158 else
159 return noexcept(__decay_copy(end(std::declval<_Tp&>())));
160 }
161
162 public:
163 template<__maybe_borrowed_range _Tp>
164 requires is_bounded_array_v<remove_reference_t<_Tp>>
165 || __member_end<_Tp> || __adl_end<_Tp>
166 constexpr auto
167 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
168 {
169 if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
170 {
171 static_assert(is_lvalue_reference_v<_Tp>);
172 return __t + extent_v<remove_reference_t<_Tp>>;
173 }
174 else if constexpr (__member_end<_Tp>)
175 return __t.end();
176 else
177 return end(__t);
178 }
179 };
180
181 template<typename _Tp>
182 concept __member_rbegin = requires(_Tp& __t)
183 {
184 { __decay_copy(__t.rbegin()) } -> input_or_output_iterator;
185 };
186
187 void rbegin() = delete;
188
189 template<typename _Tp>
190 concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>>
191 && requires(_Tp& __t)
192 {
193 { __decay_copy(rbegin(__t)) } -> input_or_output_iterator;
194 };
195
196 template<typename _Tp>
197 concept __reversable = requires(_Tp& __t)
198 {
199 { _Begin{}(__t) } -> bidirectional_iterator;
200 { _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>;
201 };
202
203 struct _RBegin
204 {
205 private:
206 template<typename _Tp>
207 static constexpr bool
208 _S_noexcept()
209 {
210 if constexpr (__member_rbegin<_Tp>)
211 return noexcept(__decay_copy(std::declval<_Tp&>().rbegin()));
212 else if constexpr (__adl_rbegin<_Tp>)
213 return noexcept(__decay_copy(rbegin(std::declval<_Tp&>())));
214 else
215 {
216 if constexpr (noexcept(_End{}(std::declval<_Tp&>())))
217 {
218 using _It = decltype(_End{}(std::declval<_Tp&>()));
219 // std::reverse_iterator copy-initializes its member.
220 return is_nothrow_copy_constructible_v<_It>;
221 }
222 else
223 return false;
224 }
225 }
226
227 public:
228 template<__maybe_borrowed_range _Tp>
229 requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
230 constexpr auto
231 operator()[[nodiscard]](_Tp&& __t) const
232 noexcept(_S_noexcept<_Tp&>())
233 {
234 if constexpr (__member_rbegin<_Tp>)
235 return __t.rbegin();
236 else if constexpr (__adl_rbegin<_Tp>)
237 return rbegin(__t);
238 else
239 return std::make_reverse_iterator(_End{}(__t));
240 }
241 };
242
243 template<typename _Tp>
244 concept __member_rend = requires(_Tp& __t)
245 {
246 { __decay_copy(__t.rend()) }
247 -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
248 };
249
250 void rend() = delete;
251
252 template<typename _Tp>
253 concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>>
254 && requires(_Tp& __t)
255 {
256 { __decay_copy(rend(__t)) }
257 -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
258 };
259
260 struct _REnd
261 {
262 private:
263 template<typename _Tp>
264 static constexpr bool
265 _S_noexcept()
266 {
267 if constexpr (__member_rend<_Tp>)
268 return noexcept(__decay_copy(std::declval<_Tp&>().rend()));
269 else if constexpr (__adl_rend<_Tp>)
270 return noexcept(__decay_copy(rend(std::declval<_Tp&>())));
271 else
272 {
273 if constexpr (noexcept(_Begin{}(std::declval<_Tp&>())))
274 {
275 using _It = decltype(_Begin{}(std::declval<_Tp&>()));
276 // std::reverse_iterator copy-initializes its member.
277 return is_nothrow_copy_constructible_v<_It>;
278 }
279 else
280 return false;
281 }
282 }
283
284 public:
285 template<__maybe_borrowed_range _Tp>
286 requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
287 constexpr auto
288 operator()[[nodiscard]](_Tp&& __t) const
289 noexcept(_S_noexcept<_Tp&>())
290 {
291 if constexpr (__member_rend<_Tp>)
292 return __t.rend();
293 else if constexpr (__adl_rend<_Tp>)
294 return rend(__t);
295 else
296 return std::make_reverse_iterator(_Begin{}(__t));
297 }
298 };
299
300 template<typename _Tp>
301 concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
302 && requires(_Tp& __t)
303 {
304 { __decay_copy(__t.size()) } -> __detail::__is_integer_like;
305 };
306
307 void size() = delete;
308
309 template<typename _Tp>
310 concept __adl_size = __class_or_enum<remove_reference_t<_Tp>>
311 && !disable_sized_range<remove_cvref_t<_Tp>>
312 && requires(_Tp& __t)
313 {
314 { __decay_copy(size(__t)) } -> __detail::__is_integer_like;
315 };
316
317 template<typename _Tp>
318 concept __sentinel_size = requires(_Tp& __t)
319 {
320 requires (!is_unbounded_array_v<remove_reference_t<_Tp>>);
321
322 { _Begin{}(__t) } -> forward_iterator;
323
324 { _End{}(__t) } -> sized_sentinel_for<decltype(_Begin{}(__t))>;
325
326 __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
327 };
328
329 struct _Size
330 {
331 private:
332 template<typename _Tp>
333 static constexpr bool
334 _S_noexcept()
335 {
336 if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
337 return true;
338 else if constexpr (__member_size<_Tp>)
339 return noexcept(__decay_copy(std::declval<_Tp&>().size()));
340 else if constexpr (__adl_size<_Tp>)
341 return noexcept(__decay_copy(size(std::declval<_Tp&>())));
342 else if constexpr (__sentinel_size<_Tp>)
343 return noexcept(_End{}(std::declval<_Tp&>())
344 - _Begin{}(std::declval<_Tp&>()));
345 }
346
347 public:
348 template<typename _Tp>
349 requires is_bounded_array_v<remove_reference_t<_Tp>>
350 || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
351 constexpr auto
352 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
353 {
354 if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
355 return extent_v<remove_reference_t<_Tp>>;
356 else if constexpr (__member_size<_Tp>)
357 return __t.size();
358 else if constexpr (__adl_size<_Tp>)
359 return size(__t);
360 else if constexpr (__sentinel_size<_Tp>)
361 return __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
362 }
363 };
364
365 struct _SSize
366 {
367 // _GLIBCXX_RESOLVE_LIB_DEFECTS
368 // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
369 template<typename _Tp>
370 requires requires (_Tp& __t) { _Size{}(__t); }
371 constexpr auto
372 operator()[[nodiscard]](_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
373 {
374 auto __size = _Size{}(__t);
375 using __size_type = decltype(__size);
376 // Return the wider of ptrdiff_t and make-signed-like-t<__size_type>.
377 if constexpr (integral<__size_type>)
378 {
380 if constexpr (__int_traits<__size_type>::__digits
381 < __int_traits<ptrdiff_t>::__digits)
382 return static_cast<ptrdiff_t>(__size);
383 else
384 return static_cast<make_signed_t<__size_type>>(__size);
385 }
386#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
387 // For strict-ansi modes integral<__int128> is false
388 else if constexpr (__detail::__is_int128<__size_type>)
389 return static_cast<__int128>(__size);
390#endif
391 else // Must be one of __max_diff_type or __max_size_type.
392 return __detail::__max_diff_type(__size);
393 }
394 };
395
396 template<typename _Tp>
397 concept __member_empty = requires(_Tp& __t) { bool(__t.empty()); };
398
399 template<typename _Tp>
400 concept __size0_empty = requires(_Tp& __t) { _Size{}(__t) == 0; };
401
402 template<typename _Tp>
403 concept __eq_iter_empty = requires(_Tp& __t)
404 {
405 requires (!is_unbounded_array_v<remove_reference_t<_Tp>>);
406
407 { _Begin{}(__t) } -> forward_iterator;
408
409 bool(_Begin{}(__t) == _End{}(__t));
410 };
411
412 struct _Empty
413 {
414 private:
415 template<typename _Tp>
416 static constexpr bool
417 _S_noexcept()
418 {
419 if constexpr (__member_empty<_Tp>)
420 return noexcept(bool(std::declval<_Tp&>().empty()));
421 else if constexpr (__size0_empty<_Tp>)
422 return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
423 else
424 return noexcept(bool(_Begin{}(std::declval<_Tp&>())
425 == _End{}(std::declval<_Tp&>())));
426 }
427
428 public:
429 template<typename _Tp>
430 requires __member_empty<_Tp> || __size0_empty<_Tp>
431 || __eq_iter_empty<_Tp>
432 constexpr bool
433 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
434 {
435 if constexpr (__member_empty<_Tp>)
436 return bool(__t.empty());
437 else if constexpr (__size0_empty<_Tp>)
438 return _Size{}(__t) == 0;
439 else
440 return bool(_Begin{}(__t) == _End{}(__t));
441 }
442 };
443
444 template<typename _Tp>
445 concept __pointer_to_object = is_pointer_v<_Tp>
446 && is_object_v<remove_pointer_t<_Tp>>;
447
448 template<typename _Tp>
449 concept __member_data = requires(_Tp& __t)
450 {
451 { __decay_copy(__t.data()) } -> __pointer_to_object;
452 };
453
454 template<typename _Tp>
455 concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>;
456
457 struct _Data
458 {
459 private:
460 template<typename _Tp>
461 static constexpr bool
462 _S_noexcept()
463 {
464 if constexpr (__member_data<_Tp>)
465 return noexcept(__decay_copy(std::declval<_Tp&>().data()));
466 else
467 return noexcept(_Begin{}(std::declval<_Tp&>()));
468 }
469
470 public:
471 template<__maybe_borrowed_range _Tp>
472 requires __member_data<_Tp> || __begin_data<_Tp>
473 constexpr auto
474 operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
475 {
476 if constexpr (__member_data<_Tp>)
477 return __t.data();
478 else
479 return std::to_address(_Begin{}(__t));
480 }
481 };
482
483 } // namespace __access
484
485 inline namespace _Cpo
486 {
487 inline constexpr ranges::__access::_Begin begin{};
488 inline constexpr ranges::__access::_End end{};
489 inline constexpr ranges::__access::_RBegin rbegin{};
490 inline constexpr ranges::__access::_REnd rend{};
491 inline constexpr ranges::__access::_Size size{};
492 inline constexpr ranges::__access::_SSize ssize{};
493 inline constexpr ranges::__access::_Empty empty{};
494 inline constexpr ranges::__access::_Data data{};
495 }
496
497 /// [range.range] The range concept.
498 template<typename _Tp>
499 concept range = requires(_Tp& __t)
500 {
501 ranges::begin(__t);
502 ranges::end(__t);
503 };
504
505 /// [range.range] The borrowed_range concept.
506 template<typename _Tp>
507 concept borrowed_range
508 = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
509
510 template<typename _Tp>
511 using iterator_t = std::__detail::__range_iter_t<_Tp>;
512
513 template<range _Range>
514 using sentinel_t = decltype(ranges::end(std::declval<_Range&>()));
515
516#if __glibcxx_ranges_as_const // >= C++23
517 // const_iterator_t and const_sentinel_t defined below.
518
519 template<range _Range>
520 using range_const_reference_t = iter_const_reference_t<iterator_t<_Range>>;
521#endif
522
523 template<range _Range>
524 using range_difference_t = iter_difference_t<iterator_t<_Range>>;
525
526 template<range _Range>
527 using range_value_t = iter_value_t<iterator_t<_Range>>;
528
529 template<range _Range>
530 using range_reference_t = iter_reference_t<iterator_t<_Range>>;
531
532 template<range _Range>
533 using range_rvalue_reference_t
534 = iter_rvalue_reference_t<iterator_t<_Range>>;
535
536 // _GLIBCXX_RESOLVE_LIB_DEFECTS
537 // 3860. range_common_reference_t is missing
538 template<range _Range>
539 using range_common_reference_t
540 = iter_common_reference_t<iterator_t<_Range>>;
541
542 /// [range.sized] The sized_range concept.
543 template<typename _Tp>
544 concept sized_range = range<_Tp>
545 && requires(_Tp& __t) { ranges::size(__t); };
546
547 template<sized_range _Range>
548 using range_size_t = decltype(ranges::size(std::declval<_Range&>()));
549
550 template<typename _Derived>
551 requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
552 class view_interface; // defined in <bits/ranges_util.h>
553
554 namespace __detail
555 {
556 template<typename _Tp, typename _Up>
557 requires (!same_as<_Tp, view_interface<_Up>>)
558 void __is_derived_from_view_interface_fn(const _Tp&,
559 const view_interface<_Up>&); // not defined
560
561 // Returns true iff _Tp has exactly one public base class that's a
562 // specialization of view_interface.
563 template<typename _Tp>
564 concept __is_derived_from_view_interface
565 = requires (_Tp __t) { __is_derived_from_view_interface_fn(__t, __t); };
566 } // namespace __detail
567
568 /// [range.view] The ranges::view_base type.
569 struct view_base { };
570
571 /// [range.view] The ranges::enable_view boolean.
572 template<typename _Tp>
573 inline constexpr bool enable_view = derived_from<_Tp, view_base>
574 || __detail::__is_derived_from_view_interface<_Tp>;
575
576 /// [range.view] The ranges::view concept.
577 template<typename _Tp>
578 concept view
579 = range<_Tp> && movable<_Tp> && enable_view<_Tp>;
580
581 // [range.refinements]
582
583 /// A range for which ranges::begin returns an output iterator.
584 template<typename _Range, typename _Tp>
585 concept output_range
586 = range<_Range> && output_iterator<iterator_t<_Range>, _Tp>;
587
588 /// A range for which ranges::begin returns an input iterator.
589 template<typename _Tp>
590 concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>;
591
592 /// A range for which ranges::begin returns a forward iterator.
593 template<typename _Tp>
594 concept forward_range
595 = input_range<_Tp> && forward_iterator<iterator_t<_Tp>>;
596
597 /// A range for which ranges::begin returns a bidirectional iterator.
598 template<typename _Tp>
599 concept bidirectional_range
600 = forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp>>;
601
602 /// A range for which ranges::begin returns a random access iterator.
603 template<typename _Tp>
604 concept random_access_range
605 = bidirectional_range<_Tp> && random_access_iterator<iterator_t<_Tp>>;
606
607 /// A range for which ranges::begin returns a contiguous iterator.
608 template<typename _Tp>
609 concept contiguous_range
610 = random_access_range<_Tp> && contiguous_iterator<iterator_t<_Tp>>
611 && requires(_Tp& __t)
612 {
613 { ranges::data(__t) } -> same_as<add_pointer_t<range_reference_t<_Tp>>>;
614 };
615
616 /// A range for which ranges::begin and ranges::end return the same type.
617 template<typename _Tp>
618 concept common_range
619 = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>;
620
621#if __glibcxx_ranges_as_const // >= C++23
622 template<typename _Tp>
623 concept constant_range
624 = input_range<_Tp> && std::__detail::__constant_iterator<iterator_t<_Tp>>;
625#endif
626
627 namespace __access
628 {
629#if __glibcxx_ranges_as_const // >= C++23
630 template<input_range _Range>
631 constexpr auto&
632 __possibly_const_range(_Range& __r) noexcept
633 {
634 // _GLIBCXX_RESOLVE_LIB_DEFECTS
635 // 4027. possibly-const-range should prefer returning const R&
636 if constexpr (input_range<const _Range>)
637 return const_cast<const _Range&>(__r);
638 else
639 return __r;
640 }
641#else
642 // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&.
643 template<typename _To, typename _Tp>
644 constexpr decltype(auto)
645 __as_const(_Tp& __t) noexcept
646 {
647 static_assert(std::is_same_v<_To&, _Tp&>);
648
649 if constexpr (is_lvalue_reference_v<_To>)
650 return const_cast<const _Tp&>(__t);
651 else
652 return static_cast<const _Tp&&>(__t);
653 }
654#endif
655
656 struct _CBegin
657 {
658#if __glibcxx_ranges_as_const // >= C++23
659 template<__maybe_borrowed_range _Tp>
660 [[nodiscard]]
661 constexpr auto
662 operator()(_Tp&& __t) const
663 noexcept(noexcept(std::make_const_iterator
664 (ranges::begin(__access::__possibly_const_range(__t)))))
665 requires requires { std::make_const_iterator
666 (ranges::begin(__access::__possibly_const_range(__t))); }
667 {
668 auto& __r = __access::__possibly_const_range(__t);
669 return const_iterator<decltype(ranges::begin(__r))>(ranges::begin(__r));
670 }
671#else
672 template<typename _Tp>
673 [[nodiscard]]
674 constexpr auto
675 operator()(_Tp&& __e) const
676 noexcept(noexcept(_Begin{}(__access::__as_const<_Tp>(__e))))
677 requires requires { _Begin{}(__access::__as_const<_Tp>(__e)); }
678 {
679 return _Begin{}(__access::__as_const<_Tp>(__e));
680 }
681#endif
682 };
683
684 struct _CEnd final
685 {
686#if __glibcxx_ranges_as_const // >= C++23
687 template<__maybe_borrowed_range _Tp>
688 [[nodiscard]]
689 constexpr auto
690 operator()(_Tp&& __t) const
691 noexcept(noexcept(std::make_const_sentinel
692 (ranges::end(__access::__possibly_const_range(__t)))))
693 requires requires { std::make_const_sentinel
694 (ranges::end(__access::__possibly_const_range(__t))); }
695 {
696 auto& __r = __access::__possibly_const_range(__t);
697 return const_sentinel<decltype(ranges::end(__r))>(ranges::end(__r));
698 }
699#else
700 template<typename _Tp>
701 [[nodiscard]]
702 constexpr auto
703 operator()(_Tp&& __e) const
704 noexcept(noexcept(_End{}(__access::__as_const<_Tp>(__e))))
705 requires requires { _End{}(__access::__as_const<_Tp>(__e)); }
706 {
707 return _End{}(__access::__as_const<_Tp>(__e));
708 }
709#endif
710 };
711
712 struct _CRBegin
713 {
714#if __glibcxx_ranges_as_const // >= C++23
715 template<__maybe_borrowed_range _Tp>
716 [[nodiscard]]
717 constexpr auto
718 operator()(_Tp&& __t) const
719 noexcept(noexcept(std::make_const_iterator
720 (ranges::rbegin(__access::__possibly_const_range(__t)))))
721 requires requires { std::make_const_iterator
722 (ranges::rbegin(__access::__possibly_const_range(__t))); }
723 {
724 auto& __r = __access::__possibly_const_range(__t);
725 return const_iterator<decltype(ranges::rbegin(__r))>(ranges::rbegin(__r));
726 }
727#else
728 template<typename _Tp>
729 [[nodiscard]]
730 constexpr auto
731 operator()(_Tp&& __e) const
732 noexcept(noexcept(_RBegin{}(__access::__as_const<_Tp>(__e))))
733 requires requires { _RBegin{}(__access::__as_const<_Tp>(__e)); }
734 {
735 return _RBegin{}(__access::__as_const<_Tp>(__e));
736 }
737#endif
738 };
739
740 struct _CREnd
741 {
742#if __glibcxx_ranges_as_const // >= C++23
743 template<__maybe_borrowed_range _Tp>
744 [[nodiscard]]
745 constexpr auto
746 operator()(_Tp&& __t) const
747 noexcept(noexcept(std::make_const_sentinel
748 (ranges::rend(__access::__possibly_const_range(__t)))))
749 requires requires { std::make_const_sentinel
750 (ranges::rend(__access::__possibly_const_range(__t))); }
751 {
752 auto& __r = __access::__possibly_const_range(__t);
753 return const_sentinel<decltype(ranges::rend(__r))>(ranges::rend(__r));
754 }
755#else
756 template<typename _Tp>
757 [[nodiscard]]
758 constexpr auto
759 operator()(_Tp&& __e) const
760 noexcept(noexcept(_REnd{}(__access::__as_const<_Tp>(__e))))
761 requires requires { _REnd{}(__access::__as_const<_Tp>(__e)); }
762 {
763 return _REnd{}(__access::__as_const<_Tp>(__e));
764 }
765#endif
766 };
767
768 struct _CData
769 {
770#if __glibcxx_ranges_as_const // >= C++23
771 template<__maybe_borrowed_range _Tp>
772 [[nodiscard]]
773 constexpr const auto*
774 operator()(_Tp&& __t) const
775 noexcept(noexcept(ranges::data(__access::__possibly_const_range(__t))))
776 requires requires { ranges::data(__access::__possibly_const_range(__t)); }
777 { return ranges::data(__access::__possibly_const_range(__t)); }
778#else
779 template<typename _Tp>
780 [[nodiscard]]
781 constexpr auto
782 operator()(_Tp&& __e) const
783 noexcept(noexcept(_Data{}(__access::__as_const<_Tp>(__e))))
784 requires requires { _Data{}(__access::__as_const<_Tp>(__e)); }
785 {
786 return _Data{}(__access::__as_const<_Tp>(__e));
787 }
788#endif
789 };
790 } // namespace __access
791
792 inline namespace _Cpo
793 {
794 inline constexpr ranges::__access::_CBegin cbegin{};
795 inline constexpr ranges::__access::_CEnd cend{};
796 inline constexpr ranges::__access::_CRBegin crbegin{};
797 inline constexpr ranges::__access::_CREnd crend{};
798 inline constexpr ranges::__access::_CData cdata{};
799 }
800
801#if __glibcxx_ranges_as_const // >= C++23
802 // _GLIBCXX_RESOLVE_LIB_DEFECTS
803 // 3946. The definition of const_iterator_t should be reworked
804 template<range _Range>
805 using const_iterator_t = decltype(ranges::cbegin(std::declval<_Range&>()));
806
807 template<range _Range>
808 using const_sentinel_t = decltype(ranges::cend(std::declval<_Range&>()));
809#endif
810
811 namespace __detail
812 {
813 template<typename _Tp>
814 inline constexpr bool __is_initializer_list = false;
815
816 template<typename _Tp>
817 inline constexpr bool __is_initializer_list<initializer_list<_Tp>> = true;
818 } // namespace __detail
819
820 /// A range which can be safely converted to a view.
821 template<typename _Tp>
822 concept viewable_range = range<_Tp>
823 && ((view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>)
824 || (!view<remove_cvref_t<_Tp>>
825 && (is_lvalue_reference_v<_Tp>
826 || (movable<remove_reference_t<_Tp>>
827 && !__detail::__is_initializer_list<remove_cvref_t<_Tp>>))));
828
829 // [range.iter.ops] range iterator operations
830
831 struct __advance_fn final
832 {
833 template<input_or_output_iterator _It>
834 constexpr void
835 operator()(_It& __it, iter_difference_t<_It> __n) const
836 {
837 if constexpr (random_access_iterator<_It>)
838 __it += __n;
839 else if constexpr (bidirectional_iterator<_It>)
840 {
841 if (__n > 0)
842 {
843 do
844 {
845 ++__it;
846 }
847 while (--__n);
848 }
849 else if (__n < 0)
850 {
851 do
852 {
853 --__it;
854 }
855 while (++__n);
856 }
857 }
858 else
859 {
860 // cannot decrement a non-bidirectional iterator
861 __glibcxx_assert(__n >= 0);
862 while (__n-- > 0)
863 ++__it;
864 }
865 }
866
867 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
868 constexpr void
869 operator()(_It& __it, _Sent __bound) const
870 {
871 if constexpr (assignable_from<_It&, _Sent>)
872 __it = std::move(__bound);
873 else if constexpr (sized_sentinel_for<_Sent, _It>)
874 (*this)(__it, __bound - __it);
875 else
876 {
877 while (__it != __bound)
878 ++__it;
879 }
880 }
881
882 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
883 constexpr iter_difference_t<_It>
884 operator()(_It& __it, iter_difference_t<_It> __n, _Sent __bound) const
885 {
886 if constexpr (sized_sentinel_for<_Sent, _It>)
887 {
888 const auto __diff = __bound - __it;
889
890 if (__diff == 0)
891 return __n;
892 else if (__diff > 0 ? __n >= __diff : __n <= __diff)
893 {
894 (*this)(__it, __bound);
895 return __n - __diff;
896 }
897 else if (__n != 0) [[likely]]
898 {
899 // n and bound must not lead in opposite directions:
900 __glibcxx_assert((__n < 0) == (__diff < 0));
901
902 (*this)(__it, __n);
903 return 0;
904 }
905 else
906 return 0;
907 }
908 else if (__it == __bound || __n == 0)
909 return __n;
910 else if (__n > 0)
911 {
912 iter_difference_t<_It> __m = 0;
913 do
914 {
915 ++__it;
916 ++__m;
917 }
918 while (__m != __n && __it != __bound);
919 return __n - __m;
920 }
921 else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>)
922 {
923 iter_difference_t<_It> __m = 0;
924 do
925 {
926 --__it;
927 --__m;
928 }
929 while (__m != __n && __it != __bound);
930 return __n - __m;
931 }
932 else
933 {
934 // cannot decrement a non-bidirectional iterator
935 __glibcxx_assert(__n >= 0);
936 return __n;
937 }
938 }
939
940 void operator&() const = delete;
941 };
942
943 inline constexpr __advance_fn advance{};
944
945 struct __distance_fn final
946 {
947 // _GLIBCXX_RESOLVE_LIB_DEFECTS
948 // 3664. LWG 3392 broke std::ranges::distance(a, a+3)
949 template<typename _It, sentinel_for<_It> _Sent>
950 requires (!sized_sentinel_for<_Sent, _It>)
951 constexpr iter_difference_t<_It>
952 operator()[[nodiscard]](_It __first, _Sent __last) const
953 {
954 iter_difference_t<_It> __n = 0;
955 while (__first != __last)
956 {
957 ++__first;
958 ++__n;
959 }
960 return __n;
961 }
962
963 template<typename _It, sized_sentinel_for<decay_t<_It>> _Sent>
964 [[nodiscard]]
965 constexpr iter_difference_t<decay_t<_It>>
966 operator()(_It&& __first, _Sent __last) const
967 { return __last - static_cast<const decay_t<_It>&>(__first); }
968
969 template<range _Range>
970 [[nodiscard]]
971 constexpr range_difference_t<_Range>
972 operator()(_Range&& __r) const
973 {
974 if constexpr (sized_range<_Range>)
975 return static_cast<range_difference_t<_Range>>(ranges::size(__r));
976 else
977 return (*this)(ranges::begin(__r), ranges::end(__r));
978 }
979
980 void operator&() const = delete;
981 };
982
983 inline constexpr __distance_fn distance{};
984
985 struct __next_fn final
986 {
987 template<input_or_output_iterator _It>
988 [[nodiscard]]
989 constexpr _It
990 operator()(_It __x) const
991 {
992 ++__x;
993 return __x;
994 }
995
996 template<input_or_output_iterator _It>
997 [[nodiscard]]
998 constexpr _It
999 operator()(_It __x, iter_difference_t<_It> __n) const
1000 {
1001 ranges::advance(__x, __n);
1002 return __x;
1003 }
1004
1005 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
1006 [[nodiscard]]
1007 constexpr _It
1008 operator()(_It __x, _Sent __bound) const
1009 {
1010 ranges::advance(__x, __bound);
1011 return __x;
1012 }
1013
1014 template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
1015 [[nodiscard]]
1016 constexpr _It
1017 operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const
1018 {
1019 ranges::advance(__x, __n, __bound);
1020 return __x;
1021 }
1022
1023 void operator&() const = delete;
1024 };
1025
1026 inline constexpr __next_fn next{};
1027
1028 struct __prev_fn final
1029 {
1030 template<bidirectional_iterator _It>
1031 [[nodiscard]]
1032 constexpr _It
1033 operator()(_It __x) const
1034 {
1035 --__x;
1036 return __x;
1037 }
1038
1039 template<bidirectional_iterator _It>
1040 [[nodiscard]]
1041 constexpr _It
1042 operator()(_It __x, iter_difference_t<_It> __n) const
1043 {
1044 ranges::advance(__x, -__n);
1045 return __x;
1046 }
1047
1048 template<bidirectional_iterator _It>
1049 [[nodiscard]]
1050 constexpr _It
1051 operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const
1052 {
1053 ranges::advance(__x, -__n, __bound);
1054 return __x;
1055 }
1056
1057 void operator&() const = delete;
1058 };
1059
1060 inline constexpr __prev_fn prev{};
1061
1062 /// Type returned by algorithms instead of a dangling iterator or subrange.
1063 struct dangling
1064 {
1065 constexpr dangling() noexcept = default;
1066 template<typename... _Args>
1067 constexpr dangling(_Args&&...) noexcept { }
1068 };
1069
1070 template<range _Range>
1071 using borrowed_iterator_t = __conditional_t<borrowed_range<_Range>,
1072 iterator_t<_Range>,
1073 dangling>;
1074} // namespace ranges
1075
1076#if __glibcxx_ranges_to_container // C++ >= 23
1077 struct from_range_t { explicit from_range_t() = default; };
1078 inline constexpr from_range_t from_range{};
1079#endif
1080
1081_GLIBCXX_END_NAMESPACE_VERSION
1082} // namespace std
1083#endif // library concepts
1084#endif // C++20
1085#endif // _GLIBCXX_RANGES_BASE_H
constexpr _Tp * to_address(_Tp *__ptr) noexcept
Obtain address referenced by a pointer to an object.
Definition ptr_traits.h:241
typename make_unsigned< _Tp >::type make_unsigned_t
Alias template for make_unsigned.
Definition type_traits:2074
auto declval() noexcept -> decltype(__declval< _Tp >(0))
Definition type_traits:2483
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:137
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:71
_Tp * end(valarray< _Tp > &__va) noexcept
Return an iterator pointing to one past the last element of the valarray.
Definition valarray:1249
_Tp * begin(valarray< _Tp > &__va) noexcept
Return an iterator pointing to the first element of the valarray.
Definition valarray:1227
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.
constexpr auto rend(_Container &__cont) -> decltype(__cont.rend())
Return a reverse iterator pointing one past the first element of the container.
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.
constexpr auto empty(const _Container &__cont) noexcept(noexcept(__cont.empty())) -> decltype(__cont.empty())
Return whether a container is empty.
constexpr auto size(const _Container &__cont) noexcept(noexcept(__cont.size())) -> decltype(__cont.size())
Return the size of a container.
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.
constexpr auto crbegin(const _Container &__cont) -> decltype(std::rbegin(__cont))
Return a reverse iterator pointing to the last element of the const container.
constexpr auto data(_Container &__cont) noexcept(noexcept(__cont.data())) -> decltype(__cont.data())
Return the data pointer of a container.
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.
constexpr bitset< _Nb > operator&(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition bitset:1557
__numeric_traits_integer< _Tp > __int_traits
Convenience alias for __numeric_traits<integer-type>.
The ranges::view_interface class template.
Definition ranges_util.h:64