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