libstdc++: ranges_base.h Source File

libstdc++

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