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