1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___RANGES_CONCAT_VIEW_H
11#define _LIBCPP___RANGES_CONCAT_VIEW_H
12
13#include <__assert>
14#include <__concepts/common_reference_with.h>
15#include <__concepts/constructible.h>
16#include <__concepts/convertible_to.h>
17#include <__concepts/copyable.h>
18#include <__concepts/derived_from.h>
19#include <__concepts/equality_comparable.h>
20#include <__concepts/swappable.h>
21#include <__config>
22#include <__iterator/concepts.h>
23#include <__iterator/default_sentinel.h>
24#include <__iterator/distance.h>
25#include <__iterator/incrementable_traits.h>
26#include <__iterator/iter_move.h>
27#include <__iterator/iter_swap.h>
28#include <__iterator/iterator_traits.h>
29#include <__iterator/next.h>
30#include <__ranges/access.h>
31#include <__ranges/all.h>
32#include <__ranges/concepts.h>
33#include <__ranges/movable_box.h>
34#include <__ranges/range_adaptor.h>
35#include <__ranges/size.h>
36#include <__ranges/view_interface.h>
37#include <__tuple/tuple_transform.h>
38#include <__type_traits/conditional.h>
39#include <__type_traits/decay.h>
40#include <__type_traits/is_nothrow_constructible.h>
41#include <__type_traits/make_unsigned.h>
42#include <__type_traits/maybe_const.h>
43#include <__utility/forward.h>
44#include <__utility/in_place.h>
45#include <__utility/move.h>
46#include <tuple>
47#include <variant>
48
49#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
50# pragma GCC system_header
51#endif
52
53_LIBCPP_PUSH_MACROS
54#include <__undef_macros>
55
56_LIBCPP_BEGIN_NAMESPACE_STD
57
58#if _LIBCPP_STD_VER >= 26
59
60namespace ranges {
61
62# ifdef __cpp_pack_indexing
63template <class... _Tp>
64using __extract_last _LIBCPP_NODEBUG = _Tp...[sizeof...(_Tp) - 1];
65# else
66template <class _Tp, class... _Tail>
67struct __extract_last_impl : __extract_last_impl<_Tail...> {};
68template <class _Tp>
69struct __extract_last_impl<_Tp> {
70 using type _LIBCPP_NODEBUG = _Tp;
71};
72
73template <class... _Tp>
74using __extract_last _LIBCPP_NODEBUG = __extract_last_impl<_Tp...>::type;
75# endif
76
77template <bool _Const, class... _Tp>
78struct __all_but_first_model_sized_range;
79
80template <bool _Const, class _Head, class... _Tail>
81struct __all_but_first_model_sized_range<_Const, _Head, _Tail...> {
82 static constexpr bool value = (sized_range<__maybe_const<_Const, _Tail>> && ...);
83};
84
85template <bool _Const, class... _Views>
86concept __all_random_access = (random_access_range<__maybe_const<_Const, _Views>> && ...);
87
88template <bool _Const, class... _Views>
89concept __all_bidirectional = (bidirectional_range<__maybe_const<_Const, _Views>> && ...);
90
91template <bool _Const, class... _Views>
92concept __all_forward = (forward_range<__maybe_const<_Const, _Views>> && ...);
93
94template <bool _Const, class _First, class... _Tail>
95struct __all_common_ignore_last {
96 static constexpr bool value =
97 common_range<__maybe_const<_Const, _First>> && __all_common_ignore_last<_Const, _Tail...>::value;
98};
99
100template <bool _Const, class _Tail>
101struct __all_common_ignore_last<_Const, _Tail> {
102 static constexpr bool value = true;
103};
104
105template <bool _Const, class... _Rs>
106concept __concat_is_random_access =
107 (__all_random_access<_Const, _Rs...>) && (__all_common_ignore_last<_Const, _Rs...>::value);
108
109template <bool _Const, class... _Rs>
110concept __concat_is_bidirectional =
111 (__all_bidirectional<_Const, _Rs...>) && (__all_common_ignore_last<_Const, _Rs...>::value);
112
113template <input_range... _Views>
114 requires((view<_Views> && ...) && (sizeof...(_Views) > 0) && __concatable<_Views...>)
115class concat_view : public view_interface<concat_view<_Views...>> {
116 tuple<_Views...> __views_;
117
118 template <bool _Const>
119 class __iterator;
120
121public:
122 _LIBCPP_HIDE_FROM_ABI constexpr concat_view() = default;
123
124 _LIBCPP_HIDE_FROM_ABI constexpr explicit concat_view(_Views... __views) : __views_(std::move(__views)...) {}
125
126 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator<false> begin()
127 requires(!(__simple_view<_Views> && ...))
128 {
129 __iterator<false> __it(this, in_place_index<0>, ranges::begin(std::get<0>(__views_)));
130 __it.template __satisfy<0>();
131 return __it;
132 }
133
134 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator<true> begin() const
135 requires((range<const _Views> && ...) && __concatable<const _Views...>)
136 {
137 __iterator<true> __it(this, in_place_index<0>, ranges::begin(std::get<0>(__views_)));
138 __it.template __satisfy<0>();
139 return __it;
140 }
141
142 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end()
143 requires(!(__simple_view<_Views> && ...))
144 {
145 if constexpr (__all_forward<false, _Views...> && common_range<__maybe_const<false, __extract_last<_Views...>>>) {
146 constexpr auto __n = sizeof...(_Views);
147 return __iterator<false>(this, in_place_index<__n - 1>, ranges::end(std::get<__n - 1>(__views_)));
148 } else {
149 return default_sentinel;
150 }
151 }
152
153 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
154 requires((range<const _Views> && ...) && __concatable<const _Views...>)
155 {
156 if constexpr (__all_forward<true, _Views...> && common_range<__maybe_const<true, __extract_last<_Views...>>>) {
157 constexpr auto __n = sizeof...(_Views);
158 return __iterator<true>(this, in_place_index<__n - 1>, ranges::end(std::get<__n - 1>(__views_)));
159 } else {
160 return default_sentinel;
161 }
162 }
163
164 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
165 requires(sized_range<_Views> && ...)
166 {
167 return std::apply(
168 [](auto... __sizes) { return (make_unsigned_t<common_type_t<decltype(__sizes)...>>(__sizes) + ...); },
169 std::__tuple_transform(ranges::size, __views_));
170 }
171
172 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
173 requires(sized_range<const _Views> && ...)
174 {
175 return std::apply(
176 [](auto... __sizes) { return (make_unsigned_t<common_type_t<decltype(__sizes)...>>(__sizes) + ...); },
177 std::__tuple_transform(ranges::size, __views_));
178 }
179};
180
181template <class... _Views>
182concat_view(_Views&&...) -> concat_view<views::all_t<_Views>...>;
183
184template <bool _Const, typename... _Views>
185struct __concat_view_iterator_category {};
186
187template <bool _Const, typename... _Views>
188 requires __all_forward<_Const, _Views...>
189struct __concat_view_iterator_category<_Const, _Views...> {
190private:
191 constexpr static bool __derive_pack_random_iterator =
192 (derived_from<typename iterator_traits<iterator_t<__maybe_const<_Const, _Views>>>::iterator_category,
193 random_access_iterator_tag> &&
194 ...);
195 constexpr static bool __derive_pack_bidirectional_iterator =
196 (derived_from<typename iterator_traits<iterator_t<__maybe_const<_Const, _Views>>>::iterator_category,
197 bidirectional_iterator_tag> &&
198 ...);
199 constexpr static bool __derive_pack_forward_iterator =
200 (derived_from<typename iterator_traits< iterator_t<__maybe_const<_Const, _Views>>>::iterator_category,
201 forward_iterator_tag> &&
202 ...);
203
204public:
205 using iterator_category =
206 _If<!is_reference_v<__concat_reference_t<__maybe_const<_Const, _Views>...>>,
207 input_iterator_tag,
208 _If<__derive_pack_random_iterator,
209 random_access_iterator_tag,
210 _If<__derive_pack_bidirectional_iterator,
211 bidirectional_iterator_tag,
212 _If<__derive_pack_forward_iterator, forward_iterator_tag, input_iterator_tag > > > >;
213};
214
215template <input_range... _Views>
216 requires((view<_Views> && ...) && (sizeof...(_Views) > 0) && __concatable<_Views...>)
217template <bool _Const>
218class concat_view<_Views...>::__iterator : public __concat_view_iterator_category<_Const, _Views...> {
219public:
220 using iterator_concept =
221 _If<__concat_is_random_access<_Const, _Views...>,
222 random_access_iterator_tag,
223 _If<__concat_is_bidirectional<_Const, _Views...>,
224 bidirectional_iterator_tag,
225 _If< __all_forward<_Const, _Views...>, forward_iterator_tag, input_iterator_tag > > >;
226 using value_type = __concat_value_t<__maybe_const<_Const, _Views>...>;
227 using difference_type = common_type_t<range_difference_t<__maybe_const<_Const, _Views>>...>;
228
229private:
230 using __base_iter _LIBCPP_NODEBUG = variant<iterator_t<__maybe_const<_Const, _Views>>...>;
231 __base_iter __it_;
232 __maybe_const<_Const, concat_view>* __parent_ = nullptr;
233
234 template <size_t _Idx>
235 _LIBCPP_HIDE_FROM_ABI constexpr void __satisfy() {
236 if constexpr (_Idx < (sizeof...(_Views) - 1)) {
237 if (std::get<_Idx>(__it_) == ranges::end(std::get<_Idx>(__parent_->__views_))) {
238 __it_.template emplace<_Idx + 1>(ranges::begin(std::get<_Idx + 1>(__parent_->__views_)));
239 __satisfy<_Idx + 1>();
240 }
241 }
242 }
243
244 template <size_t _Idx>
245 _LIBCPP_HIDE_FROM_ABI constexpr void __prev() {
246 if constexpr (_Idx == 0) {
247 --std::get<0>(__it_);
248 } else {
249 if (std::get<_Idx>(__it_) == ranges::begin(std::get<_Idx>(__parent_->__views_))) {
250 __it_.template emplace<_Idx - 1>(ranges::end(std::get<_Idx - 1>(__parent_->__views_)));
251 __prev<_Idx - 1>();
252 } else {
253 --std::get<_Idx>(__it_);
254 }
255 }
256 }
257
258 template <size_t _Idx>
259 _LIBCPP_HIDE_FROM_ABI constexpr void __advance_fwd(difference_type __offset, difference_type __steps) {
260 using __underlying_diff_type = iter_difference_t<variant_alternative_t<_Idx, __base_iter>>;
261 if constexpr (_Idx == sizeof...(_Views) - 1) {
262 std::get<_Idx>(__it_) += static_cast<__underlying_diff_type>(__steps);
263 } else {
264 auto __n_size = ranges::distance(std::get<_Idx>(__parent_->__views_));
265 if (__offset + __steps < __n_size) {
266 std::get<_Idx>(__it_) += static_cast<__underlying_diff_type>(__steps);
267 } else {
268 __it_.template emplace<_Idx + 1>(ranges::begin(std::get<_Idx + 1>(__parent_->__views_)));
269 __advance_fwd<_Idx + 1>(0, __offset + __steps - __n_size);
270 }
271 }
272 }
273
274 template <size_t _Idx>
275 _LIBCPP_HIDE_FROM_ABI constexpr void __advance_bwd(difference_type __offset, difference_type __steps) {
276 using __underlying_diff_type = iter_difference_t<variant_alternative_t<_Idx, __base_iter>>;
277 if constexpr (_Idx == 0) {
278 std::get<_Idx>(__it_) -= static_cast<__underlying_diff_type>(__steps);
279 } else {
280 if (__offset >= __steps) {
281 std::get<_Idx>(__it_) -= static_cast<__underlying_diff_type>(__steps);
282 } else {
283 auto __prev_size = ranges::distance(std::get<_Idx - 1>(__parent_->__views_));
284 __it_.template emplace<_Idx - 1>(ranges::end(std::get<_Idx - 1>(__parent_->__views_)));
285 __advance_bwd<_Idx - 1>(__prev_size, __steps - __offset);
286 }
287 }
288 }
289
290 template <typename _Func>
291 _LIBCPP_HIDE_FROM_ABI constexpr auto __invoke_at_index(_Func&& __func) const {
292 // TODO(GCC 16): Just capture `this` when GCC PR113563 and PR121008 are fixed.
293 return [&__func, &__view_iter = *this]<std::size_t _Is>(this auto&& __self) {
294 if (_Is == __view_iter.__it_.index()) {
295 return __func.template operator()<_Is>();
296 }
297 if constexpr (_Is + 1 < sizeof...(_Views)) {
298 return __self.template operator()<_Is + 1>();
299 }
300 __builtin_unreachable();
301 }.template operator()<0>();
302 }
303
304 template <size_t... _Is, typename _Func>
305 _LIBCPP_HIDE_FROM_ABI constexpr void __apply_at_index(size_t __index, _Func&& __func, index_sequence<_Is...>) const {
306 ((__index == _Is ? (static_cast<void>(__func(integral_constant<size_t, _Is>{})), 0) : 0), ...);
307 }
308
309 template <size_t _Idx, typename _Func>
310 _LIBCPP_HIDE_FROM_ABI constexpr void __apply_at_index(size_t __index, _Func&& __func) const {
311 __apply_at_index(__index, std::forward<_Func>(__func), make_index_sequence<_Idx>{});
312 }
313
314 template <class... _Args>
315 _LIBCPP_HIDE_FROM_ABI explicit constexpr __iterator(__maybe_const<_Const, concat_view>* __parent, _Args&&... __args)
316 requires constructible_from<__base_iter, _Args&&...>
317 : __it_(std::forward<_Args>(__args)...), __parent_(__parent) {}
318
319 friend class concat_view;
320 friend class __iterator<!_Const>;
321
322public:
323 _LIBCPP_HIDE_FROM_ABI __iterator() = default;
324
325 _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
326 requires _Const && (convertible_to<iterator_t<_Views>, iterator_t<const _Views>> && ...)
327 : __it_([&__src = __i.__it_]<size_t... _Indices>(size_t __idx, index_sequence<_Indices...>) -> __base_iter {
328 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
329 !__src.valueless_by_exception(), "Trying to convert from a valueless iterator of concat_view.");
330 using __src_lref = decltype((__src));
331 using __construction_fptr = __base_iter (*)(__src_lref);
332 static constexpr __construction_fptr __vtable[]{[](__src_lref __src_var) -> __base_iter {
333 return __base_iter(in_place_index<_Indices>, std::__unchecked_get<_Indices>(std::move(__src_var)));
334 }...};
335 return __vtable[__idx](__src);
336 }(__i.__it_.index(), make_index_sequence<variant_size_v<__base_iter>>{})),
337 __parent_(__i.__parent_) {}
338
339 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const {
340 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
341 !__it_.valueless_by_exception(), "Trying to dereference a valueless iterator of concat_view.");
342 return __variant_detail::__visitation::__variant::__visit_value(
343 [](auto&& __it) -> __concat_reference_t<__maybe_const<_Const, _Views>...> { return *__it; }, __it_);
344 }
345
346 _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
347 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
348 !__it_.valueless_by_exception(), "Trying to increment a valueless iterator of concat_view.");
349 size_t __active_index = __it_.index();
350 __apply_at_index<variant_size_v<decltype(__it_)>>(__active_index, [&](auto __index_constant) {
351 constexpr size_t __i = __index_constant.value;
352 ++std::__unchecked_get<__i>(__it_);
353 __satisfy<__i>();
354 });
355 return *this;
356 }
357
358 _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
359
360 _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
361 requires(__all_forward<_Const, _Views...>)
362 {
363 auto __tmp = *this;
364 ++*this;
365 return __tmp;
366 }
367
368 _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
369 requires __concat_is_bidirectional<_Const, _Views...>
370 {
371 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
372 !__it_.valueless_by_exception(), "Trying to decrement a valueless iterator of concat_view.");
373 size_t __active_index = __it_.index();
374 __apply_at_index<variant_size_v<decltype(__it_)>>(__active_index, [&](auto __index_constant) {
375 constexpr size_t __i = __index_constant.value;
376 __prev<__i>();
377 });
378 return *this;
379 }
380
381 _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
382 requires __concat_is_bidirectional<_Const, _Views...>
383 {
384 auto __tmp = *this;
385 --*this;
386 return __tmp;
387 }
388
389 _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
390 requires(equality_comparable<iterator_t<__maybe_const<_Const, _Views>>> && ...)
391 {
392 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
393 "Trying to compare a valueless iterator of concat_view.");
394 return __x.__it_ == __y.__it_;
395 }
396
397 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const
398 requires __concat_is_random_access<_Const, _Views...>
399 {
400 return *((*this) + __n);
401 }
402
403 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __it, difference_type __n)
404 requires __concat_is_random_access<_Const, _Views...>
405 {
406 auto __temp = __it;
407 __temp += __n;
408 return __temp;
409 }
410
411 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __it)
412 requires __concat_is_random_access<_Const, _Views...>
413 {
414 return __it + __n;
415 }
416
417 _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n)
418 requires __concat_is_random_access<_Const, _Views...>
419 {
420 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
421 !__it_.valueless_by_exception(), "Trying to increment a valueless iterator of concat_view.");
422 size_t __active_index = __it_.index();
423 if (__n > 0) {
424 __apply_at_index<tuple_size_v<decltype(__parent_->__views_)>>(__active_index, [&](auto __index_constant) {
425 constexpr size_t __i = __index_constant.value;
426 auto& __active_view = std::get<__i>(__parent_->__views_);
427 difference_type __idx = std::get<__i>(__it_) - ranges::begin(__active_view);
428 __advance_fwd<__i>(__idx, __n);
429 });
430
431 }
432
433 else if (__n < 0) {
434 __apply_at_index<tuple_size_v<decltype(__parent_->__views_)>>(__active_index, [&](auto __index_constant) {
435 constexpr size_t __i = __index_constant.value;
436 auto& __active_view = std::get<__i>(__parent_->__views_);
437 difference_type __idx = std::get<__i>(__it_) - ranges::begin(__active_view);
438 __advance_bwd<__i>(__idx, -__n);
439 });
440 }
441
442 return *this;
443 }
444
445 _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
446 requires __concat_is_random_access<_Const, _Views...>
447 {
448 *this += -__n;
449 return *this;
450 }
451
452 _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __it, default_sentinel_t) {
453 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
454 !__it.__it_.valueless_by_exception(),
455 "Trying to compare a valueless iterator of concat_view with the default sentinel.");
456 constexpr auto __last_idx = sizeof...(_Views) - 1;
457 return __it.__it_.index() == __last_idx &&
458 std::__unchecked_get<__last_idx>(__it.__it_) == ranges::end(std::get<__last_idx>(__it.__parent_->__views_));
459 }
460
461 _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
462 requires(__all_random_access<_Const, _Views> && ...)
463 {
464 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
465 "Trying to compare a valueless iterator of concat_view.");
466 return __x.__it_ < __y.__it_;
467 }
468
469 _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
470 requires(__all_random_access<_Const, _Views> && ...)
471 {
472 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
473 "Trying to compare a valueless iterator of concat_view.");
474 return __x.__it_ > __y.__it_;
475 }
476
477 _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
478 requires(__all_random_access<_Const, _Views> && ...)
479 {
480 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
481 "Trying to compare a valueless iterator of concat_view.");
482 return __x.__it_ <= __y.__it_;
483 }
484
485 _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
486 requires(__all_random_access<_Const, _Views> && ...)
487 {
488 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
489 "Trying to compare a valueless iterator of concat_view.");
490 return __x.__it_ >= __y.__it_;
491 }
492
493 _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
494 requires((__all_random_access<_Const, _Views> && ...) &&
495 (three_way_comparable<iterator_t<__maybe_const<_Const, _Views>>> && ...))
496 {
497 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
498 "Trying to compare a valueless iterator of concat_view.");
499 return __x.__it_ <=> __y.__it_;
500 }
501
502 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr decltype(auto) iter_move(const __iterator& __it) noexcept(
503
504 ((is_nothrow_invocable_v< decltype(ranges::iter_move), const iterator_t<__maybe_const<_Const, _Views>>& > &&
505 is_nothrow_convertible_v< range_rvalue_reference_t<__maybe_const<_Const, _Views>>,
506 __concat_rvalue_reference_t<__maybe_const<_Const, _Views>...> >) &&
507 ...))
508
509 {
510 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
511 !__it.__it_.valueless_by_exception(), "Trying to apply iter_move to a valueless iterator of concat_view.");
512 return __variant_detail::__visitation::__variant::__visit_value(
513 [](const auto& __i) -> __concat_rvalue_reference_t<__maybe_const<_Const, _Views>...> {
514 return ranges::iter_move(__i);
515 },
516 __it.__it_);
517 }
518
519 _LIBCPP_HIDE_FROM_ABI friend constexpr void iter_swap(const __iterator& __x, const __iterator& __y)
520
521 noexcept((noexcept(ranges::swap(*__x, *__y))) &&
522 (noexcept(ranges::iter_swap(std::declval<const iterator_t<__maybe_const<_Const, _Views>>>(),
523 std::declval<const iterator_t<__maybe_const<_Const, _Views>>>())) &&
524 ...))
525
526 requires swappable_with<iter_reference_t<__iterator>, iter_reference_t<__iterator>> &&
527 (... && indirectly_swappable<iterator_t<__maybe_const<_Const, _Views>>>)
528 {
529 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
530 !__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
531 "Trying to swap iterators of concat_view where at least one iterator is valueless.");
532 __variant_detail::__visitation::__variant::__visit_value(
533 [&](const auto& __it1, const auto& __it2) {
534 if constexpr (is_same_v<decltype(__it1), decltype(__it2)>) {
535 ranges::iter_swap(__it1, __it2);
536 } else {
537 ranges::swap(*__x, *__y);
538 }
539 },
540 __x.__it_,
541 __y.__it_);
542 }
543
544 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
545 operator-(const __iterator& __x, const __iterator& __y)
546 requires __concat_is_random_access<_Const, _Views...>
547 {
548 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
549 !__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
550 "Trying to subtract two iterators of concat_view where at least one iterator is valueless.");
551 return __x.__invoke_at_index([&]<std::size_t __index_x>() -> difference_type {
552 return __y.__invoke_at_index([&]<std::size_t __index_y>() -> difference_type {
553 if constexpr (__index_x > __index_y) {
554 auto __dx = ranges::distance(
555 ranges::begin(std::get<__index_x>(__x.__parent_->__views_)), std::get<__index_x>(__x.__it_));
556 auto __dy = ranges::distance(
557 std::get<__index_y>(__y.__it_), ranges::end(std::get<__index_y>(__y.__parent_->__views_)));
558 difference_type __s = [&]<std::size_t __start, std::size_t __end>(this auto&& __self) -> difference_type {
559 if constexpr (__start < __end) {
560 return ranges::size(std::get<__start>(__x.__parent_->__views_)) +
561 __self.template operator()<__start + 1, __end>();
562 }
563 return 0;
564 }.template operator()<__index_y + 1, __index_x>();
565 return __dy + __s + __dx;
566 } else if constexpr (__index_x < __index_y) {
567 return -(__y - __x);
568 } else {
569 return std::get<__index_x>(__x.__it_) - std::get<__index_y>(__y.__it_);
570 }
571 });
572 });
573 }
574
575 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __it, difference_type __n)
576 requires __concat_is_random_access<_Const, _Views...>
577 {
578 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
579 !__it.__it_.valueless_by_exception(), "Trying to subtract a valuess iterators of concat_view.");
580 auto __temp = __it;
581 __temp -= __n;
582 return __temp;
583 }
584
585 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
586 operator-(const __iterator& __x, default_sentinel_t)
587 requires(sized_sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_Const, _Views>>> &&
588 ...) &&
589 (__all_but_first_model_sized_range<_Const, _Views...>::value)
590 {
591 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
592 !__x.__it_.valueless_by_exception(),
593 "Trying to subtract a valuess iterators of concat_view from the default sentinel.");
594 return __x.__invoke_at_index([&]<std::size_t __index_x>() -> difference_type {
595 auto __dx =
596 ranges::distance(std::get<__index_x>(__x.__it_), ranges::end(std::get<__index_x>(__x.__parent_->__views_)));
597 difference_type __s = [&]<std::size_t __start, std::size_t __end>(this auto&& __self) -> difference_type {
598 if constexpr (__start < __end) {
599 return ranges::size(std::get<__start>(__x.__parent_->__views_)) +
600 __self.template operator()<__start + 1, __end>();
601 }
602 return 0;
603 }.template operator()<__index_x + 1, sizeof...(_Views)>();
604 return -(__dx + __s);
605 });
606 }
607
608 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
609 operator-(default_sentinel_t, const __iterator& __x)
610 requires(sized_sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_Const, _Views>>> &&
611 ...) &&
612 (__all_but_first_model_sized_range<_Const, _Views...>::value)
613 {
614 return -(__x - default_sentinel);
615 }
616};
617
618namespace views {
619namespace __concat {
620struct __fn {
621 template <input_range _Range>
622 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
623 operator()(_Range&& __range) noexcept(noexcept(views::all((std::forward<_Range>(__range)))))
624 -> decltype(views::all((std::forward<_Range>(__range)))) {
625 return views::all(std::forward<_Range>(__range));
626 }
627
628 template <class _FirstRange, class... _TailRanges>
629 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
630 operator()(_FirstRange&& __first, _TailRanges&&... __tail) noexcept(
631 noexcept(concat_view(std::forward<_FirstRange>(__first), std::forward<_TailRanges>(__tail)...)))
632 -> decltype(concat_view(std::forward<_FirstRange>(__first), std::forward<_TailRanges>(__tail)...)) {
633 return concat_view(std::forward<_FirstRange>(__first), std::forward<_TailRanges>(__tail)...);
634 }
635};
636} // namespace __concat
637
638inline namespace __cpo {
639inline constexpr auto concat = __concat::__fn{};
640} // namespace __cpo
641} // namespace views
642
643} // namespace ranges
644
645#endif // _LIBCPP_STD_VER >= 26
646
647_LIBCPP_END_NAMESPACE_STD
648
649_LIBCPP_POP_MACROS
650
651#endif // _LIBCPP___RANGES_CONCAT_VIEW_H
652