libstdc++
ranges
Go to the documentation of this file.
1// <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 include/ranges
26 * This is a Standard C++ Library header.
27 * @ingroup concepts
28 */
29
30#ifndef _GLIBCXX_RANGES
31#define _GLIBCXX_RANGES 1
32
33#if __cplusplus > 201703L
34
35#ifdef _GLIBCXX_SYSHDR
36#pragma GCC system_header
37#endif
38
39#include <concepts>
40
41#if __cpp_lib_concepts
42
43#include <compare>
44#include <initializer_list>
45#include <iterator>
46#include <optional>
47#include <span>
48#include <string_view>
49#include <tuple>
50#if __cplusplus > 202002L
51#include <utility>
52#include <variant>
53#endif
54#include <bits/binders.h>
55#include <bits/ranges_util.h>
56#include <bits/refwrap.h>
57
58#define __glibcxx_want_algorithm_default_value_type
59#define __glibcxx_want_ranges
60#define __glibcxx_want_ranges_as_const
61#define __glibcxx_want_ranges_as_rvalue
62#define __glibcxx_want_ranges_cache_latest
63#define __glibcxx_want_ranges_cartesian_product
64#define __glibcxx_want_ranges_concat
65#define __glibcxx_want_ranges_chunk
66#define __glibcxx_want_ranges_chunk_by
67#define __glibcxx_want_ranges_enumerate
68#define __glibcxx_want_ranges_filter
69#define __glibcxx_want_ranges_indices
70#define __glibcxx_want_ranges_join_with
71#define __glibcxx_want_ranges_repeat
72#define __glibcxx_want_ranges_slide
73#define __glibcxx_want_ranges_stride
74#define __glibcxx_want_ranges_to_container
75#define __glibcxx_want_ranges_as_input
76#define __glibcxx_want_ranges_zip
77#include <bits/version.h>
78
79#ifdef __glibcxx_generator // C++ >= 23 && __glibcxx_coroutine
80# include <bits/elements_of.h>
81#endif
82
83/**
84 * @defgroup ranges Ranges
85 *
86 * Components for dealing with ranges of elements.
87 */
88
89namespace std _GLIBCXX_VISIBILITY(default)
90{
91_GLIBCXX_BEGIN_NAMESPACE_VERSION
92namespace ranges
93{
94 // [range.access] customization point objects
95 // [range.req] range and view concepts
96 // [range.dangling] dangling iterator handling
97 // Defined in <bits/ranges_base.h>
98
99 // [view.interface] View interface
100 // [range.subrange] Sub-ranges
101 // Defined in <bits/ranges_util.h>
102
103 // C++20 24.6 [range.factories] Range factories
104
105 /// A view that contains no elements.
106 template<typename _Tp> requires is_object_v<_Tp>
108 : public view_interface<empty_view<_Tp>>
109 {
110 public:
111 static constexpr _Tp* begin() noexcept { return nullptr; }
112 static constexpr _Tp* end() noexcept { return nullptr; }
113 static constexpr _Tp* data() noexcept { return nullptr; }
114 static constexpr size_t size() noexcept { return 0; }
115 static constexpr bool empty() noexcept { return true; }
116 };
117
118 template<typename _Tp>
119 inline constexpr bool enable_borrowed_range<empty_view<_Tp>> = true;
120
121 namespace __detail
122 {
123#if __cpp_lib_ranges >= 202207L // C++ >= 23
124 // P2494R2 Relaxing range adaptors to allow for move only types
125 template<typename _Tp>
126 concept __boxable = move_constructible<_Tp> && is_object_v<_Tp>;
127#else
128 template<typename _Tp>
129 concept __boxable = copy_constructible<_Tp> && is_object_v<_Tp>;
130#endif
131
132 template<__boxable _Tp>
133 struct __box : std::optional<_Tp>
134 {
135 using std::optional<_Tp>::optional;
136
137 constexpr
138 __box()
139 noexcept(is_nothrow_default_constructible_v<_Tp>)
140 requires default_initializable<_Tp>
141 : std::optional<_Tp>{std::in_place}
142 { }
143
144 __box(const __box&) = default;
145 __box(__box&&) = default;
146
147 using std::optional<_Tp>::operator=;
148
149 // _GLIBCXX_RESOLVE_LIB_DEFECTS
150 // 3477. Simplify constraints for semiregular-box
151 // 3572. copyable-box should be fully constexpr
152 constexpr __box&
153 operator=(const __box& __that)
154 noexcept(is_nothrow_copy_constructible_v<_Tp>)
155 requires (!copyable<_Tp>) && copy_constructible<_Tp>
156 {
157 if (this != std::__addressof(__that))
158 {
159 if ((bool)__that)
160 this->emplace(*__that);
161 else
162 this->reset();
163 }
164 return *this;
165 }
166
167 constexpr __box&
168 operator=(__box&& __that)
169 noexcept(is_nothrow_move_constructible_v<_Tp>)
170 requires (!movable<_Tp>)
171 {
172 if (this != std::__addressof(__that))
173 {
174 if ((bool)__that)
175 this->emplace(std::move(*__that));
176 else
177 this->reset();
178 }
179 return *this;
180 }
181 };
182
183 template<typename _Tp>
184 concept __boxable_copyable
185 = copy_constructible<_Tp>
186 && (copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp>
187 && is_nothrow_copy_constructible_v<_Tp>));
188 template<typename _Tp>
189 concept __boxable_movable
190 = (!copy_constructible<_Tp>)
191 && (movable<_Tp> || is_nothrow_move_constructible_v<_Tp>);
192
193 // For types which are already copyable (or since C++23, movable)
194 // this specialization of the box wrapper stores the object directly
195 // without going through std::optional. It provides just the subset of
196 // the primary template's API that we currently use.
197 template<__boxable _Tp>
198 requires __boxable_copyable<_Tp> || __boxable_movable<_Tp>
199 struct __box<_Tp>
200 {
201 private:
202 [[no_unique_address]] _Tp _M_value = _Tp();
203
204 public:
205 __box() requires default_initializable<_Tp> = default;
206
207 constexpr explicit
208 __box(const _Tp& __t)
209 noexcept(is_nothrow_copy_constructible_v<_Tp>)
210 requires copy_constructible<_Tp>
211 : _M_value(__t)
212 { }
213
214 constexpr explicit
215 __box(_Tp&& __t)
216 noexcept(is_nothrow_move_constructible_v<_Tp>)
217 : _M_value(std::move(__t))
218 { }
219
220 template<typename... _Args>
221 requires constructible_from<_Tp, _Args...>
222 constexpr explicit
223 __box(in_place_t, _Args&&... __args)
224 noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
225 : _M_value(std::forward<_Args>(__args)...)
226 { }
227
228 __box(const __box&) = default;
229 __box(__box&&) = default;
230 __box& operator=(const __box&) requires copyable<_Tp> = default;
231 __box& operator=(__box&&) requires movable<_Tp> = default;
232
233 // When _Tp is nothrow_copy_constructible but not copy_assignable,
234 // copy assignment is implemented via destroy-then-copy-construct.
235 constexpr __box&
236 operator=(const __box& __that) noexcept
237 requires (!copyable<_Tp>) && copy_constructible<_Tp>
238 {
239 static_assert(is_nothrow_copy_constructible_v<_Tp>);
240 if (this != std::__addressof(__that))
241 {
242 _M_value.~_Tp();
243 std::construct_at(std::__addressof(_M_value), *__that);
244 }
245 return *this;
246 }
247
248 // Likewise for move assignment.
249 constexpr __box&
250 operator=(__box&& __that) noexcept
251 requires (!movable<_Tp>)
252 {
253 static_assert(is_nothrow_move_constructible_v<_Tp>);
254 if (this != std::__addressof(__that))
255 {
256 _M_value.~_Tp();
257 std::construct_at(std::__addressof(_M_value), std::move(*__that));
258 }
259 return *this;
260 }
261
262 constexpr bool
263 has_value() const noexcept
264 { return true; };
265
266 constexpr _Tp&
267 operator*() & noexcept
268 { return _M_value; }
269
270 constexpr const _Tp&
271 operator*() const & noexcept
272 { return _M_value; }
273
274 constexpr _Tp&&
275 operator*() && noexcept
276 { return std::move(_M_value); }
277
278 constexpr const _Tp&&
279 operator*() const && noexcept
280 { return std::move(_M_value); }
281
282 constexpr _Tp*
283 operator->() noexcept
284 { return std::__addressof(_M_value); }
285
286 constexpr const _Tp*
287 operator->() const noexcept
288 { return std::__addressof(_M_value); }
289 };
290
291 namespace __func_handle
292 {
293 template<typename _Fn>
294 struct _Inplace
295 {
296 _Inplace() = default;
297
298 constexpr explicit
299 _Inplace(_Fn __func) noexcept
300 : _M_fn(__func)
301 { }
302
303 template<typename... _Iters>
304 constexpr decltype(auto)
305 _M_call_deref(const _Iters&... __iters) const
306 noexcept(noexcept(_M_fn(*__iters...)))
307 { return _M_fn(*__iters...); }
308
309 template<typename _DistType, typename... _Iters>
310 constexpr decltype(auto)
311 _M_call_subscript(const _DistType __n, const _Iters&... __iters) const
312 noexcept(noexcept(_M_fn(__iters[iter_difference_t<_Iters>(__n)]...)))
313 { return _M_fn(__iters[iter_difference_t<_Iters>(__n)]...); }
314
315 private:
316 [[no_unique_address]] _Fn _M_fn = _Fn();
317 };
318
319 template<typename _Fn>
320 struct _InplaceMemPtr
321 {
322 _InplaceMemPtr() = default;
323
324 constexpr explicit
325 _InplaceMemPtr(_Fn __func) noexcept
326 : _M_ptr(__func)
327 {}
328
329 template<typename... _Iters>
330 constexpr decltype(auto)
331 _M_call_deref(const _Iters&... __iters) const
332 noexcept(noexcept(std::__invoke(_M_ptr, *__iters...)))
333 { return std::__invoke(_M_ptr, *__iters...); }
334
335 template<typename _DistType, typename... _Iters>
336 constexpr decltype(auto)
337 _M_call_subscript(const _DistType __n, const _Iters&... __iters) const
338 noexcept(noexcept(std::__invoke(_M_ptr, __iters[iter_difference_t<_Iters>(__n)]...)))
339 { return std::__invoke(_M_ptr, __iters[iter_difference_t<_Iters>(__n)]...); }
340
341 private:
342 _Fn _M_ptr = nullptr;
343 };
344
345 template<typename _Fn>
346 struct _ViaPointer
347 {
348 _ViaPointer() = default;
349
350 constexpr explicit
351 _ViaPointer(_Fn& __func) noexcept
352 : _M_ptr(std::addressof(__func))
353 { }
354
355 template<typename _Un>
356 requires (!is_const_v<_Un>) && is_same_v<const _Un, _Fn>
357 constexpr
358 _ViaPointer(_ViaPointer<_Un> __other) noexcept
359 : _M_ptr(__other._M_ptr)
360 { }
361
362 template<typename... _Iters>
363 constexpr decltype(auto)
364 _M_call_deref(const _Iters&... __iters) const
365 noexcept(noexcept((*_M_ptr)(*__iters...)))
366 { return (*_M_ptr)(*__iters...); }
367
368 template<typename _DistType, typename... _Iters>
369 constexpr decltype(auto)
370 _M_call_subscript(const _DistType __n, const _Iters&... __iters) const
371 noexcept(noexcept((*_M_ptr)(__iters[iter_difference_t<_Iters>(__n)]...)))
372 { return (*_M_ptr)(__iters[iter_difference_t<_Iters>(__n)]...); }
373
374 private:
375 _Fn* _M_ptr = nullptr;
376
377 template<typename>
378 friend struct _ViaPointer;
379 };
380
381 template<typename _Fn>
382 struct _StaticCall
383 {
384 _StaticCall() = default;
385
386 constexpr explicit
387 _StaticCall(const _Fn&) noexcept
388 {}
389
390 template<typename... _Iters>
391 static constexpr decltype(auto)
392 _M_call_deref(const _Iters&... __iters)
393 noexcept(noexcept(_Fn::operator()(*__iters...)))
394 { return _Fn::operator()(*__iters...); }
395
396 template<typename _DistType, typename... _Iters>
397 static constexpr decltype(auto)
398 _M_call_subscript(_DistType __n, const _Iters&... __iters)
399 noexcept(noexcept(_Fn::operator()(__iters[iter_difference_t<_Iters>(__n)]...)))
400 { return _Fn::operator()(__iters[iter_difference_t<_Iters>(__n)]...); }
401 };
402
403 template<typename _Fn, typename... _Iters>
404 consteval auto
405 __select()
406 {
407 using _Fd = remove_cv_t<_Fn>;
408 if constexpr (is_member_pointer_v<_Fd>)
409 return __func_handle::_InplaceMemPtr<_Fd>();
410 else if constexpr (is_function_v<remove_pointer_t<_Fd>>)
411 return __func_handle::_Inplace<_Fd>();
412 else if constexpr (__is_std_op_wrapper<_Fd>)
413 return __func_handle::_Inplace<_Fd>();
414 else if constexpr (requires (const _Iters&... __iters)
415 { _Fd::operator()(*__iters...); })
416 return __func_handle::_StaticCall<_Fd>();
417 else
418 return __func_handle::_ViaPointer<_Fn>();
419 };
420 } // __func_handle
421
422 template<typename _Fn, typename... _Iters>
423 using __func_handle_t = decltype(__func_handle::__select<_Fn, _Iters...>());
424 } // namespace __detail
425
426 /// A view that contains exactly one element.
427#if __cpp_lib_ranges >= 202207L // C++ >= 23
428 template<move_constructible _Tp>
429#else
430 template<copy_constructible _Tp>
431#endif
432 requires is_object_v<_Tp>
433 class single_view : public view_interface<single_view<_Tp>>
434 {
435 public:
436 single_view() requires default_initializable<_Tp> = default;
437
438 constexpr explicit
439 single_view(const _Tp& __t)
440 noexcept(is_nothrow_copy_constructible_v<_Tp>)
442 : _M_value(__t)
443 { }
444
445 constexpr explicit
446 single_view(_Tp&& __t)
447 noexcept(is_nothrow_move_constructible_v<_Tp>)
448 : _M_value(std::move(__t))
449 { }
450
451 // _GLIBCXX_RESOLVE_LIB_DEFECTS
452 // 3428. single_view's in place constructor should be explicit
453 template<typename... _Args>
454 requires constructible_from<_Tp, _Args...>
455 constexpr explicit
456 single_view(in_place_t, _Args&&... __args)
457 noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
458 : _M_value{in_place, std::forward<_Args>(__args)...}
459 { }
460
461 constexpr _Tp*
462 begin() noexcept
463 { return data(); }
464
465 constexpr const _Tp*
466 begin() const noexcept
467 { return data(); }
468
469 constexpr _Tp*
470 end() noexcept
471 { return data() + 1; }
472
473 constexpr const _Tp*
474 end() const noexcept
475 { return data() + 1; }
476
477 // _GLIBCXX_RESOLVE_LIB_DEFECTS
478 // 4035. single_view should provide empty
479 static constexpr bool
480 empty() noexcept
481 { return false; }
482
483 static constexpr size_t
484 size() noexcept
485 { return 1; }
486
487 constexpr _Tp*
488 data() noexcept
489 { return _M_value.operator->(); }
490
491 constexpr const _Tp*
492 data() const noexcept
493 { return _M_value.operator->(); }
494
495 private:
496 [[no_unique_address]] __detail::__box<_Tp> _M_value;
497 };
498
499 template<typename _Tp>
501
502 namespace __detail
503 {
504 template<typename _Wp>
505 constexpr auto __to_signed_like(_Wp __w) noexcept
506 {
507 if constexpr (!integral<_Wp>)
508 return iter_difference_t<_Wp>();
509 else if constexpr (sizeof(iter_difference_t<_Wp>) > sizeof(_Wp))
510 return iter_difference_t<_Wp>(__w);
511 else if constexpr (sizeof(ptrdiff_t) > sizeof(_Wp))
512 return ptrdiff_t(__w);
513 else if constexpr (sizeof(long long) > sizeof(_Wp))
514 return (long long)(__w);
515#ifdef __SIZEOF_INT128__
516 else if constexpr (__SIZEOF_INT128__ > sizeof(_Wp))
517 return __int128(__w);
518#endif
519 else
520 return __max_diff_type(__w);
521 }
522
523 template<typename _Wp>
524 using __iota_diff_t = decltype(__to_signed_like(std::declval<_Wp>()));
525
526 template<typename _It>
527 concept __decrementable = incrementable<_It>
528 && requires(_It __i)
529 {
530 { --__i } -> same_as<_It&>;
531 { __i-- } -> same_as<_It>;
532 };
533
534 template<typename _It>
535 concept __advanceable = __decrementable<_It> && totally_ordered<_It>
536 && requires( _It __i, const _It __j, const __iota_diff_t<_It> __n)
537 {
538 { __i += __n } -> same_as<_It&>;
539 { __i -= __n } -> same_as<_It&>;
540 _It(__j + __n);
541 _It(__n + __j);
542 _It(__j - __n);
543 { __j - __j } -> convertible_to<__iota_diff_t<_It>>;
544 };
545
546 template<typename _Winc>
547 struct __iota_view_iter_cat
548 { };
549
550 template<incrementable _Winc>
551 struct __iota_view_iter_cat<_Winc>
552 { using iterator_category = input_iterator_tag; };
553 } // namespace __detail
554
555 template<weakly_incrementable _Winc,
556 semiregular _Bound = unreachable_sentinel_t>
557 requires std::__detail::__weakly_eq_cmp_with<_Winc, _Bound>
558 && copyable<_Winc>
559 class iota_view : public view_interface<iota_view<_Winc, _Bound>>
560 {
561 private:
562 struct _Sentinel;
563
564 struct _Iterator : __detail::__iota_view_iter_cat<_Winc>
565 {
566 private:
567 static auto
568 _S_iter_concept()
569 {
570 using namespace __detail;
571 if constexpr (__advanceable<_Winc>)
572 return random_access_iterator_tag{};
573 else if constexpr (__decrementable<_Winc>)
574 return bidirectional_iterator_tag{};
575 else if constexpr (incrementable<_Winc>)
576 return forward_iterator_tag{};
577 else
578 return input_iterator_tag{};
579 }
580
581 public:
582 using iterator_concept = decltype(_S_iter_concept());
583 // iterator_category defined in __iota_view_iter_cat
584 using value_type = _Winc;
585 using difference_type = __detail::__iota_diff_t<_Winc>;
586
587 _Iterator() requires default_initializable<_Winc> = default;
588
589 constexpr explicit
590 _Iterator(_Winc __value)
591 : _M_value(__value) { }
592
593 constexpr _Winc
594 operator*() const noexcept(is_nothrow_copy_constructible_v<_Winc>)
595 { return _M_value; }
596
597 constexpr _Iterator&
598 operator++()
599 {
600 ++_M_value;
601 return *this;
602 }
603
604 constexpr void
605 operator++(int)
606 { ++*this; }
607
608 constexpr _Iterator
609 operator++(int) requires incrementable<_Winc>
610 {
611 auto __tmp = *this;
612 ++*this;
613 return __tmp;
614 }
615
616 constexpr _Iterator&
617 operator--() requires __detail::__decrementable<_Winc>
618 {
619 --_M_value;
620 return *this;
621 }
622
623 constexpr _Iterator
624 operator--(int) requires __detail::__decrementable<_Winc>
625 {
626 auto __tmp = *this;
627 --*this;
628 return __tmp;
629 }
630
631 constexpr _Iterator&
632 operator+=(difference_type __n) requires __detail::__advanceable<_Winc>
633 {
634 using __detail::__is_integer_like;
635 using __detail::__is_signed_integer_like;
636 if constexpr (__is_integer_like<_Winc>
637 && !__is_signed_integer_like<_Winc>)
638 {
639 if (__n >= difference_type(0))
640 _M_value += static_cast<_Winc>(__n);
641 else
642 _M_value -= static_cast<_Winc>(-__n);
643 }
644 else
645 _M_value += __n;
646 return *this;
647 }
648
649 constexpr _Iterator&
650 operator-=(difference_type __n) requires __detail::__advanceable<_Winc>
651 {
652 using __detail::__is_integer_like;
653 using __detail::__is_signed_integer_like;
654 if constexpr (__is_integer_like<_Winc>
655 && !__is_signed_integer_like<_Winc>)
656 {
657 if (__n >= difference_type(0))
658 _M_value -= static_cast<_Winc>(__n);
659 else
660 _M_value += static_cast<_Winc>(-__n);
661 }
662 else
663 _M_value -= __n;
664 return *this;
665 }
666
667 constexpr _Winc
668 operator[](difference_type __n) const
669 requires __detail::__advanceable<_Winc>
670 { return _Winc(_M_value + __n); }
671
672 friend constexpr bool
673 operator==(const _Iterator& __x, const _Iterator& __y)
674 requires equality_comparable<_Winc>
675 { return __x._M_value == __y._M_value; }
676
677 friend constexpr bool
678 operator<(const _Iterator& __x, const _Iterator& __y)
679 requires totally_ordered<_Winc>
680 { return __x._M_value < __y._M_value; }
681
682 friend constexpr bool
683 operator>(const _Iterator& __x, const _Iterator& __y)
684 requires totally_ordered<_Winc>
685 { return __y < __x; }
686
687 friend constexpr bool
688 operator<=(const _Iterator& __x, const _Iterator& __y)
689 requires totally_ordered<_Winc>
690 { return !(__y < __x); }
691
692 friend constexpr bool
693 operator>=(const _Iterator& __x, const _Iterator& __y)
694 requires totally_ordered<_Winc>
695 { return !(__x < __y); }
696
697#ifdef __cpp_lib_three_way_comparison
698 friend constexpr auto
699 operator<=>(const _Iterator& __x, const _Iterator& __y)
700 requires totally_ordered<_Winc> && three_way_comparable<_Winc>
701 { return __x._M_value <=> __y._M_value; }
702#endif
703
704 friend constexpr _Iterator
705 operator+(_Iterator __i, difference_type __n)
706 requires __detail::__advanceable<_Winc>
707 {
708 __i += __n;
709 return __i;
710 }
711
712 friend constexpr _Iterator
713 operator+(difference_type __n, _Iterator __i)
714 requires __detail::__advanceable<_Winc>
715 { return __i += __n; }
716
717 friend constexpr _Iterator
718 operator-(_Iterator __i, difference_type __n)
719 requires __detail::__advanceable<_Winc>
720 {
721 __i -= __n;
722 return __i;
723 }
724
725 friend constexpr difference_type
726 operator-(const _Iterator& __x, const _Iterator& __y)
727 requires __detail::__advanceable<_Winc>
728 {
729 using __detail::__is_integer_like;
730 using __detail::__is_signed_integer_like;
731 using _Dt = difference_type;
732 if constexpr (__is_integer_like<_Winc>)
733 {
734 if constexpr (__is_signed_integer_like<_Winc>)
735 return _Dt(_Dt(__x._M_value) - _Dt(__y._M_value));
736 else
737 return (__y._M_value > __x._M_value)
738 ? _Dt(-_Dt(__y._M_value - __x._M_value))
739 : _Dt(__x._M_value - __y._M_value);
740 }
741 else
742 return __x._M_value - __y._M_value;
743 }
744
745 private:
746 _Winc _M_value = _Winc();
747
748 friend iota_view;
749 friend _Sentinel;
750 };
751
752 struct _Sentinel
753 {
754 private:
755 _Bound _M_bound = _Bound();
756
757 public:
758 _Sentinel() = default;
759
760 constexpr explicit
761 _Sentinel(_Bound __bound)
762 : _M_bound(__bound) { }
763
764 friend constexpr bool
765 operator==(const _Iterator& __x, const _Sentinel& __y)
766 { return __x._M_value == __y._M_bound; }
767
768 friend constexpr iter_difference_t<_Winc>
769 operator-(const _Iterator& __x, const _Sentinel& __y)
770 requires sized_sentinel_for<_Bound, _Winc>
771 { return -(__y._M_bound - __x._M_value); }
772
773 friend constexpr iter_difference_t<_Winc>
774 operator-(const _Sentinel& __x, const _Iterator& __y)
775 requires sized_sentinel_for<_Bound, _Winc>
776 { return __x._M_bound - __y._M_value; }
777
778 friend iota_view;
779 };
780
781 _Winc _M_value = _Winc();
782 [[no_unique_address]] _Bound _M_bound = _Bound();
783
784 public:
785 iota_view() requires default_initializable<_Winc> = default;
786
787 constexpr explicit
788 iota_view(_Winc __value)
789 : _M_value(__value)
790 { }
791
792 constexpr explicit
793 iota_view(type_identity_t<_Winc> __value,
794 type_identity_t<_Bound> __bound)
795 : _M_value(__value), _M_bound(__bound)
796 {
797 if constexpr (totally_ordered_with<_Winc, _Bound>)
798 __glibcxx_assert( bool(__value <= __bound) );
799 }
800
801 constexpr explicit
802 iota_view(_Iterator __first, _Iterator __last)
803 requires same_as<_Winc, _Bound>
804 : iota_view(__first._M_value, __last._M_value)
805 { }
806
807 constexpr explicit
808 iota_view(_Iterator __first, unreachable_sentinel_t __last)
809 requires same_as<_Bound, unreachable_sentinel_t>
810 : iota_view(__first._M_value, __last)
811 { }
812
813 constexpr explicit
814 iota_view(_Iterator __first, _Sentinel __last)
815 requires (!same_as<_Winc, _Bound>) && (!same_as<_Bound, unreachable_sentinel_t>)
816 : iota_view(__first._M_value, __last._M_bound)
817 { }
818
819 constexpr _Iterator
820 begin() const { return _Iterator{_M_value}; }
821
822 constexpr auto
823 end() const
824 {
825 if constexpr (same_as<_Bound, unreachable_sentinel_t>)
826 return unreachable_sentinel;
827 else
828 return _Sentinel{_M_bound};
829 }
830
831 constexpr _Iterator
832 end() const requires same_as<_Winc, _Bound>
833 { return _Iterator{_M_bound}; }
834
835 // _GLIBCXX_RESOLVE_LIB_DEFECTS
836 // 4001. iota_view should provide empty
837 constexpr bool
838 empty() const
839 { return _M_value == _M_bound; }
840
841 constexpr auto
842 size() const
843 requires (same_as<_Winc, _Bound> && __detail::__advanceable<_Winc>)
844 || (integral<_Winc> && integral<_Bound>)
845 || sized_sentinel_for<_Bound, _Winc>
846 {
847 using __detail::__is_integer_like;
848 using __detail::__to_unsigned_like;
849 if constexpr (integral<_Winc> && integral<_Bound>)
850 {
851 using _Up = make_unsigned_t<decltype(_M_bound - _M_value)>;
852 return _Up(_M_bound) - _Up(_M_value);
853 }
854 else if constexpr (__is_integer_like<_Winc>)
855 return __to_unsigned_like(_M_bound) - __to_unsigned_like(_M_value);
856 else
857 return __to_unsigned_like(_M_bound - _M_value);
858 }
859 };
860
861 template<typename _Winc, typename _Bound>
862 requires (!__detail::__is_integer_like<_Winc>
863 || !__detail::__is_integer_like<_Bound>
864 || (__detail::__is_signed_integer_like<_Winc>
865 == __detail::__is_signed_integer_like<_Bo