xref: /freebsd/contrib/llvm-project/libcxx/include/__ranges/join_view.h (revision b3edf4467982447620505a28fc82e38a414c07dc)
1349cc55cSDimitry Andric // -*- C++ -*-
2349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
3349cc55cSDimitry Andric //
4349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7349cc55cSDimitry Andric //
8349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
9bdd1243dSDimitry Andric 
10349cc55cSDimitry Andric #ifndef _LIBCPP___RANGES_JOIN_VIEW_H
11349cc55cSDimitry Andric #define _LIBCPP___RANGES_JOIN_VIEW_H
12349cc55cSDimitry Andric 
1381ad6265SDimitry Andric #include <__concepts/constructible.h>
1481ad6265SDimitry Andric #include <__concepts/convertible_to.h>
1581ad6265SDimitry Andric #include <__concepts/copyable.h>
1681ad6265SDimitry Andric #include <__concepts/derived_from.h>
1781ad6265SDimitry Andric #include <__concepts/equality_comparable.h>
18349cc55cSDimitry Andric #include <__config>
19349cc55cSDimitry Andric #include <__iterator/concepts.h>
2081ad6265SDimitry Andric #include <__iterator/iter_move.h>
2181ad6265SDimitry Andric #include <__iterator/iter_swap.h>
22349cc55cSDimitry Andric #include <__iterator/iterator_traits.h>
23bdd1243dSDimitry Andric #include <__iterator/iterator_with_data.h>
24bdd1243dSDimitry Andric #include <__iterator/segmented_iterator.h>
2506c3fb27SDimitry Andric #include <__memory/addressof.h>
26349cc55cSDimitry Andric #include <__ranges/access.h>
27349cc55cSDimitry Andric #include <__ranges/all.h>
28349cc55cSDimitry Andric #include <__ranges/concepts.h>
29bdd1243dSDimitry Andric #include <__ranges/empty.h>
30349cc55cSDimitry Andric #include <__ranges/non_propagating_cache.h>
3181ad6265SDimitry Andric #include <__ranges/range_adaptor.h>
32349cc55cSDimitry Andric #include <__ranges/view_interface.h>
3306c3fb27SDimitry Andric #include <__type_traits/common_type.h>
34bdd1243dSDimitry Andric #include <__type_traits/maybe_const.h>
355f757f3fSDimitry Andric #include <__utility/as_lvalue.h>
365f757f3fSDimitry Andric #include <__utility/empty.h>
37349cc55cSDimitry Andric #include <__utility/forward.h>
38349cc55cSDimitry Andric #include <optional>
39349cc55cSDimitry Andric 
40349cc55cSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
41349cc55cSDimitry Andric #  pragma GCC system_header
42349cc55cSDimitry Andric #endif
43349cc55cSDimitry Andric 
44*b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS
45*b3edf446SDimitry Andric #include <__undef_macros>
46*b3edf446SDimitry Andric 
47349cc55cSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
48349cc55cSDimitry Andric 
495f757f3fSDimitry Andric #if _LIBCPP_STD_VER >= 20
50349cc55cSDimitry Andric 
51349cc55cSDimitry Andric namespace ranges {
52349cc55cSDimitry Andric template <class>
53349cc55cSDimitry Andric struct __join_view_iterator_category {};
54349cc55cSDimitry Andric 
55349cc55cSDimitry Andric template <class _View>
56cb14a3feSDimitry Andric   requires is_reference_v<range_reference_t<_View>> && forward_range<_View> && forward_range<range_reference_t<_View>>
57349cc55cSDimitry Andric struct __join_view_iterator_category<_View> {
58349cc55cSDimitry Andric   using _OuterC = typename iterator_traits<iterator_t<_View>>::iterator_category;
59349cc55cSDimitry Andric   using _InnerC = typename iterator_traits<iterator_t<range_reference_t<_View>>>::iterator_category;
60349cc55cSDimitry Andric 
61cb14a3feSDimitry Andric   using iterator_category =
62cb14a3feSDimitry Andric       _If< derived_from<_OuterC, bidirectional_iterator_tag> && derived_from<_InnerC, bidirectional_iterator_tag> &&
6381ad6265SDimitry Andric                common_range<range_reference_t<_View>>,
64349cc55cSDimitry Andric            bidirectional_iterator_tag,
65cb14a3feSDimitry Andric            _If< derived_from<_OuterC, forward_iterator_tag> && derived_from<_InnerC, forward_iterator_tag>,
66349cc55cSDimitry Andric                 forward_iterator_tag,
67cb14a3feSDimitry Andric                 input_iterator_tag > >;
68349cc55cSDimitry Andric };
69349cc55cSDimitry Andric 
70349cc55cSDimitry Andric template <input_range _View>
71349cc55cSDimitry Andric   requires view<_View> && input_range<range_reference_t<_View>>
72cb14a3feSDimitry Andric class join_view : public view_interface<join_view<_View>> {
73349cc55cSDimitry Andric private:
74349cc55cSDimitry Andric   using _InnerRange = range_reference_t<_View>;
75349cc55cSDimitry Andric 
76cb14a3feSDimitry Andric   template <bool>
77cb14a3feSDimitry Andric   struct __iterator;
78bdd1243dSDimitry Andric 
79cb14a3feSDimitry Andric   template <bool>
80cb14a3feSDimitry Andric   struct __sentinel;
81bdd1243dSDimitry Andric 
82bdd1243dSDimitry Andric   template <class>
83bdd1243dSDimitry Andric   friend struct std::__segmented_iterator_traits;
84349cc55cSDimitry Andric 
8581ad6265SDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
86349cc55cSDimitry Andric 
875f757f3fSDimitry Andric   static constexpr bool _UseOuterCache = !forward_range<_View>;
885f757f3fSDimitry Andric   using _OuterCache                    = _If<_UseOuterCache, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
895f757f3fSDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _OuterCache __outer_;
905f757f3fSDimitry Andric 
915f757f3fSDimitry Andric   static constexpr bool _UseInnerCache = !is_reference_v<_InnerRange>;
925f757f3fSDimitry Andric   using _InnerCache = _If<_UseInnerCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>;
935f757f3fSDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _InnerCache __inner_;
945f757f3fSDimitry Andric 
95349cc55cSDimitry Andric public:
96cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI join_view()
97cb14a3feSDimitry Andric     requires default_initializable<_View>
98cb14a3feSDimitry Andric   = default;
99349cc55cSDimitry Andric 
100cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr explicit join_view(_View __base) : __base_(std::move(__base)) {}
101349cc55cSDimitry Andric 
102cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
103cb14a3feSDimitry Andric     requires copy_constructible<_View>
104cb14a3feSDimitry Andric   {
105cb14a3feSDimitry Andric     return __base_;
106cb14a3feSDimitry Andric   }
107349cc55cSDimitry Andric 
108cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
109349cc55cSDimitry Andric 
110cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr auto begin() {
1115f757f3fSDimitry Andric     if constexpr (forward_range<_View>) {
112cb14a3feSDimitry Andric       constexpr bool __use_const = __simple_view<_View> && is_reference_v<range_reference_t<_View>>;
113349cc55cSDimitry Andric       return __iterator<__use_const>{*this, ranges::begin(__base_)};
1145f757f3fSDimitry Andric     } else {
1155f757f3fSDimitry Andric       __outer_.__emplace(ranges::begin(__base_));
1165f757f3fSDimitry Andric       return __iterator<false>{*this};
1175f757f3fSDimitry Andric     }
118349cc55cSDimitry Andric   }
119349cc55cSDimitry Andric 
120349cc55cSDimitry Andric   template <class _V2 = _View>
121cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
122cb14a3feSDimitry Andric     requires forward_range<const _V2> && is_reference_v<range_reference_t<const _V2>> &&
1235f757f3fSDimitry Andric              input_range<range_reference_t<const _V2>>
124349cc55cSDimitry Andric   {
125349cc55cSDimitry Andric     return __iterator<true>{*this, ranges::begin(__base_)};
126349cc55cSDimitry Andric   }
127349cc55cSDimitry Andric 
128cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr auto end() {
129cb14a3feSDimitry Andric     if constexpr (forward_range<_View> && is_reference_v<_InnerRange> && forward_range<_InnerRange> &&
130cb14a3feSDimitry Andric                   common_range<_View> && common_range<_InnerRange>)
131349cc55cSDimitry Andric       return __iterator<__simple_view<_View>>{*this, ranges::end(__base_)};
132349cc55cSDimitry Andric     else
133349cc55cSDimitry Andric       return __sentinel<__simple_view<_View>>{*this};
134349cc55cSDimitry Andric   }
135349cc55cSDimitry Andric 
136349cc55cSDimitry Andric   template <class _V2 = _View>
137cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
138cb14a3feSDimitry Andric     requires forward_range<const _V2> && is_reference_v<range_reference_t<const _V2>> &&
1395f757f3fSDimitry Andric              input_range<range_reference_t<const _V2>>
140349cc55cSDimitry Andric   {
141349cc55cSDimitry Andric     using _ConstInnerRange = range_reference_t<const _View>;
142cb14a3feSDimitry Andric     if constexpr (forward_range<_ConstInnerRange> && common_range<const _View> && common_range<_ConstInnerRange>) {
143349cc55cSDimitry Andric       return __iterator<true>{*this, ranges::end(__base_)};
144349cc55cSDimitry Andric     } else {
145349cc55cSDimitry Andric       return __sentinel<true>{*this};
146349cc55cSDimitry Andric     }
147349cc55cSDimitry Andric   }
148349cc55cSDimitry Andric };
149349cc55cSDimitry Andric 
1501ac55f4cSDimitry Andric template <input_range _View>
151349cc55cSDimitry Andric   requires view<_View> && input_range<range_reference_t<_View>>
1521ac55f4cSDimitry Andric template <bool _Const>
1531ac55f4cSDimitry Andric struct join_view<_View>::__sentinel {
1545f757f3fSDimitry Andric private:
1551ac55f4cSDimitry Andric   template <bool>
1561ac55f4cSDimitry Andric   friend struct __sentinel;
157349cc55cSDimitry Andric 
1585f757f3fSDimitry Andric   using _Parent            = __maybe_const<_Const, join_view>;
159349cc55cSDimitry Andric   using _Base              = __maybe_const<_Const, _View>;
160349cc55cSDimitry Andric   sentinel_t<_Base> __end_ = sentinel_t<_Base>();
161349cc55cSDimitry Andric 
162349cc55cSDimitry Andric public:
163cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI __sentinel() = default;
164349cc55cSDimitry Andric 
165cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(_Parent& __parent) : __end_(ranges::end(__parent.__base_)) {}
166349cc55cSDimitry Andric 
167cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __s)
168349cc55cSDimitry Andric     requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
16981ad6265SDimitry Andric       : __end_(std::move(__s.__end_)) {}
170349cc55cSDimitry Andric 
171349cc55cSDimitry Andric   template <bool _OtherConst>
172349cc55cSDimitry Andric     requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
173cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
1745f757f3fSDimitry Andric     return __x.__get_outer() == __y.__end_;
175349cc55cSDimitry Andric   }
176349cc55cSDimitry Andric };
177349cc55cSDimitry Andric 
1781ac55f4cSDimitry Andric // https://reviews.llvm.org/D142811#inline-1383022
1791ac55f4cSDimitry Andric // To simplify the segmented iterator traits specialization,
1801ac55f4cSDimitry Andric // make the iterator `final`
1811ac55f4cSDimitry Andric template <input_range _View>
182349cc55cSDimitry Andric   requires view<_View> && input_range<range_reference_t<_View>>
1831ac55f4cSDimitry Andric template <bool _Const>
184cb14a3feSDimitry Andric struct join_view<_View>::__iterator final : public __join_view_iterator_category<__maybe_const<_Const, _View>> {
1855f757f3fSDimitry Andric   friend join_view;
186bdd1243dSDimitry Andric 
187bdd1243dSDimitry Andric   template <class>
188bdd1243dSDimitry Andric   friend struct std::__segmented_iterator_traits;
189349cc55cSDimitry Andric 
1901ac55f4cSDimitry Andric   static constexpr bool __is_join_view_iterator = true;
1911ac55f4cSDimitry Andric 
192349cc55cSDimitry Andric private:
193bdd1243dSDimitry Andric   using _Parent     = __maybe_const<_Const, join_view<_View>>;
194349cc55cSDimitry Andric   using _Base       = __maybe_const<_Const, _View>;
195349cc55cSDimitry Andric   using _Outer      = iterator_t<_Base>;
196349cc55cSDimitry Andric   using _Inner      = iterator_t<range_reference_t<_Base>>;
197bdd1243dSDimitry Andric   using _InnerRange = range_reference_t<_View>;
198349cc55cSDimitry Andric 
1995f757f3fSDimitry Andric   static_assert(!_Const || forward_range<_Base>, "Const can only be true when Base models forward_range.");
2005f757f3fSDimitry Andric 
201349cc55cSDimitry Andric   static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>;
202349cc55cSDimitry Andric 
2035f757f3fSDimitry Andric   static constexpr bool _OuterPresent           = forward_range<_Base>;
2045f757f3fSDimitry Andric   using _OuterType                              = _If<_OuterPresent, _Outer, std::__empty>;
2055f757f3fSDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType();
206349cc55cSDimitry Andric 
207349cc55cSDimitry Andric   optional<_Inner> __inner_;
208349cc55cSDimitry Andric   _Parent* __parent_ = nullptr;
209349cc55cSDimitry Andric 
210cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr void __satisfy() {
2115f757f3fSDimitry Andric     for (; __get_outer() != ranges::end(__parent_->__base_); ++__get_outer()) {
2125f757f3fSDimitry Andric       auto&& __inner = [this]() -> auto&& {
213349cc55cSDimitry Andric         if constexpr (__ref_is_glvalue)
2145f757f3fSDimitry Andric           return *__get_outer();
215349cc55cSDimitry Andric         else
2165f757f3fSDimitry Andric           return __parent_->__inner_.__emplace_from([&]() -> decltype(auto) { return *__get_outer(); });
217349cc55cSDimitry Andric       }();
218349cc55cSDimitry Andric       __inner_ = ranges::begin(__inner);
219349cc55cSDimitry Andric       if (*__inner_ != ranges::end(__inner))
220349cc55cSDimitry Andric         return;
221349cc55cSDimitry Andric     }
222349cc55cSDimitry Andric 
223349cc55cSDimitry Andric     if constexpr (__ref_is_glvalue)
224349cc55cSDimitry Andric       __inner_.reset();
225349cc55cSDimitry Andric   }
226349cc55cSDimitry Andric 
2275f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _Outer& __get_outer() {
2285f757f3fSDimitry Andric     if constexpr (forward_range<_Base>) {
2295f757f3fSDimitry Andric       return __outer_;
2305f757f3fSDimitry Andric     } else {
2315f757f3fSDimitry Andric       return *__parent_->__outer_;
2325f757f3fSDimitry Andric     }
2335f757f3fSDimitry Andric   }
2345f757f3fSDimitry Andric 
2355f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr const _Outer& __get_outer() const {
2365f757f3fSDimitry Andric     if constexpr (forward_range<_Base>) {
2375f757f3fSDimitry Andric       return __outer_;
2385f757f3fSDimitry Andric     } else {
2395f757f3fSDimitry Andric       return *__parent_->__outer_;
2405f757f3fSDimitry Andric     }
2415f757f3fSDimitry Andric   }
2425f757f3fSDimitry Andric 
2435f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, _Outer __outer)
2445f757f3fSDimitry Andric     requires forward_range<_Base>
2455f757f3fSDimitry Andric       : __outer_(std::move(__outer)), __parent_(std::addressof(__parent)) {
2465f757f3fSDimitry Andric     __satisfy();
2475f757f3fSDimitry Andric   }
2485f757f3fSDimitry Andric 
2495f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Parent& __parent)
2505f757f3fSDimitry Andric     requires(!forward_range<_Base>)
2515f757f3fSDimitry Andric       : __parent_(std::addressof(__parent)) {
2525f757f3fSDimitry Andric     __satisfy();
2535f757f3fSDimitry Andric   }
2545f757f3fSDimitry Andric 
2551ac55f4cSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner)
2565f757f3fSDimitry Andric     requires forward_range<_Base>
257bdd1243dSDimitry Andric       : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
258bdd1243dSDimitry Andric 
259349cc55cSDimitry Andric public:
260cb14a3feSDimitry Andric   using iterator_concept =
261cb14a3feSDimitry Andric       _If< __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<range_reference_t<_Base>> &&
26281ad6265SDimitry Andric                common_range<range_reference_t<_Base>>,
263349cc55cSDimitry Andric            bidirectional_iterator_tag,
264cb14a3feSDimitry Andric            _If< __ref_is_glvalue && forward_range<_Base> && forward_range<range_reference_t<_Base>>,
265349cc55cSDimitry Andric                 forward_iterator_tag,
266cb14a3feSDimitry Andric                 input_iterator_tag > >;
267349cc55cSDimitry Andric 
268349cc55cSDimitry Andric   using value_type = range_value_t<range_reference_t<_Base>>;
269349cc55cSDimitry Andric 
270cb14a3feSDimitry Andric   using difference_type = common_type_t< range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>;
271349cc55cSDimitry Andric 
2725f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI __iterator() = default;
273349cc55cSDimitry Andric 
274cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
275cb14a3feSDimitry Andric     requires _Const && convertible_to<iterator_t<_View>, _Outer> && convertible_to<iterator_t<_InnerRange>, _Inner>
276cb14a3feSDimitry Andric       : __outer_(std::move(__i.__outer_)), __inner_(std::move(__i.__inner_)), __parent_(__i.__parent_) {}
277349cc55cSDimitry Andric 
278cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return **__inner_; }
279349cc55cSDimitry Andric 
280cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr _Inner operator->() const
281349cc55cSDimitry Andric     requires __has_arrow<_Inner> && copyable<_Inner>
282349cc55cSDimitry Andric   {
283349cc55cSDimitry Andric     return *__inner_;
284349cc55cSDimitry Andric   }
285349cc55cSDimitry Andric 
286cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
2875f757f3fSDimitry Andric     auto __get_inner_range = [&]() -> decltype(auto) {
288349cc55cSDimitry Andric       if constexpr (__ref_is_glvalue)
2895f757f3fSDimitry Andric         return *__get_outer();
290349cc55cSDimitry Andric       else
2915f757f3fSDimitry Andric         return *__parent_->__inner_;
2925f757f3fSDimitry Andric     };
2935f757f3fSDimitry Andric     if (++*__inner_ == ranges::end(std::__as_lvalue(__get_inner_range()))) {
2945f757f3fSDimitry Andric       ++__get_outer();
295349cc55cSDimitry Andric       __satisfy();
296349cc55cSDimitry Andric     }
297349cc55cSDimitry Andric     return *this;
298349cc55cSDimitry Andric   }
299349cc55cSDimitry Andric 
300cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
301349cc55cSDimitry Andric 
302cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
303cb14a3feSDimitry Andric     requires __ref_is_glvalue && forward_range<_Base> && forward_range<range_reference_t<_Base>>
304349cc55cSDimitry Andric   {
305349cc55cSDimitry Andric     auto __tmp = *this;
306349cc55cSDimitry Andric     ++*this;
307349cc55cSDimitry Andric     return __tmp;
308349cc55cSDimitry Andric   }
309349cc55cSDimitry Andric 
310cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
311cb14a3feSDimitry Andric     requires __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<range_reference_t<_Base>> &&
312349cc55cSDimitry Andric              common_range<range_reference_t<_Base>>
313349cc55cSDimitry Andric   {
314349cc55cSDimitry Andric     if (__outer_ == ranges::end(__parent_->__base_))
3155f757f3fSDimitry Andric       __inner_ = ranges::end(std::__as_lvalue(*--__outer_));
316349cc55cSDimitry Andric 
317349cc55cSDimitry Andric     // Skip empty inner ranges when going backwards.
3185f757f3fSDimitry Andric     while (*__inner_ == ranges::begin(std::__as_lvalue(*__outer_))) {
3195f757f3fSDimitry Andric       __inner_ = ranges::end(std::__as_lvalue(*--__outer_));
320349cc55cSDimitry Andric     }
321349cc55cSDimitry Andric 
322349cc55cSDimitry Andric     --*__inner_;
323349cc55cSDimitry Andric     return *this;
324349cc55cSDimitry Andric   }
325349cc55cSDimitry Andric 
326cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
327cb14a3feSDimitry Andric     requires __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<range_reference_t<_Base>> &&
328349cc55cSDimitry Andric              common_range<range_reference_t<_Base>>
329349cc55cSDimitry Andric   {
330349cc55cSDimitry Andric     auto __tmp = *this;
331349cc55cSDimitry Andric     --*this;
332349cc55cSDimitry Andric     return __tmp;
333349cc55cSDimitry Andric   }
334349cc55cSDimitry Andric 
335cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
336cb14a3feSDimitry Andric     requires __ref_is_glvalue && forward_range<_Base> && equality_comparable<iterator_t<range_reference_t<_Base>>>
337349cc55cSDimitry Andric   {
338349cc55cSDimitry Andric     return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_;
339349cc55cSDimitry Andric   }
340349cc55cSDimitry Andric 
341cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI friend constexpr decltype(auto)
342cb14a3feSDimitry Andric   iter_move(const __iterator& __i) noexcept(noexcept(ranges::iter_move(*__i.__inner_))) {
343349cc55cSDimitry Andric     return ranges::iter_move(*__i.__inner_);
344349cc55cSDimitry Andric   }
345349cc55cSDimitry Andric 
346cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI friend constexpr void
347cb14a3feSDimitry Andric   iter_swap(const __iterator& __x,
348cb14a3feSDimitry Andric             const __iterator& __y) noexcept(noexcept(ranges::iter_swap(*__x.__inner_, *__y.__inner_)))
349349cc55cSDimitry Andric     requires indirectly_swappable<_Inner>
350349cc55cSDimitry Andric   {
351349cc55cSDimitry Andric     return ranges::iter_swap(*__x.__inner_, *__y.__inner_);
352349cc55cSDimitry Andric   }
353349cc55cSDimitry Andric };
354349cc55cSDimitry Andric 
355349cc55cSDimitry Andric template <class _Range>
356349cc55cSDimitry Andric explicit join_view(_Range&&) -> join_view<views::all_t<_Range>>;
357349cc55cSDimitry Andric 
35881ad6265SDimitry Andric namespace views {
35981ad6265SDimitry Andric namespace __join_view {
36081ad6265SDimitry Andric struct __fn : __range_adaptor_closure<__fn> {
36181ad6265SDimitry Andric   template <class _Range>
362cb14a3feSDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
36381ad6265SDimitry Andric       noexcept(noexcept(join_view<all_t<_Range&&>>(std::forward<_Range>(__range))))
364cb14a3feSDimitry Andric           -> decltype(join_view<all_t<_Range&&>>(std::forward<_Range>(__range))) {
365cb14a3feSDimitry Andric     return join_view<all_t<_Range&&>>(std::forward<_Range>(__range));
366cb14a3feSDimitry Andric   }
36781ad6265SDimitry Andric };
36881ad6265SDimitry Andric } // namespace __join_view
36981ad6265SDimitry Andric inline namespace __cpo {
37081ad6265SDimitry Andric inline constexpr auto join = __join_view::__fn{};
37181ad6265SDimitry Andric } // namespace __cpo
37281ad6265SDimitry Andric } // namespace views
373349cc55cSDimitry Andric } // namespace ranges
374349cc55cSDimitry Andric 
3751ac55f4cSDimitry Andric template <class _JoinViewIterator>
376cb14a3feSDimitry Andric   requires(_JoinViewIterator::__is_join_view_iterator && ranges::common_range<typename _JoinViewIterator::_Parent> &&
37706c3fb27SDimitry Andric            __has_random_access_iterator_category<typename _JoinViewIterator::_Outer>::value &&
37806c3fb27SDimitry Andric            __has_random_access_iterator_category<typename _JoinViewIterator::_Inner>::value)
3791ac55f4cSDimitry Andric struct __segmented_iterator_traits<_JoinViewIterator> {
380bdd1243dSDimitry Andric   using __segment_iterator =
381bdd1243dSDimitry Andric       _LIBCPP_NODEBUG __iterator_with_data<typename _JoinViewIterator::_Outer, typename _JoinViewIterator::_Parent*>;
382bdd1243dSDimitry Andric   using __local_iterator = typename _JoinViewIterator::_Inner;
383bdd1243dSDimitry Andric 
384bdd1243dSDimitry Andric   // TODO: Would it make sense to enable the optimization for other iterator types?
385bdd1243dSDimitry Andric 
386bdd1243dSDimitry Andric   static constexpr _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_JoinViewIterator __iter) {
387bdd1243dSDimitry Andric     if (ranges::empty(__iter.__parent_->__base_))
388bdd1243dSDimitry Andric       return {};
389bdd1243dSDimitry Andric     if (!__iter.__inner_.has_value())
390bdd1243dSDimitry Andric       return __segment_iterator(--__iter.__outer_, __iter.__parent_);
391bdd1243dSDimitry Andric     return __segment_iterator(__iter.__outer_, __iter.__parent_);
392bdd1243dSDimitry Andric   }
393bdd1243dSDimitry Andric 
394bdd1243dSDimitry Andric   static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_JoinViewIterator __iter) {
395bdd1243dSDimitry Andric     if (ranges::empty(__iter.__parent_->__base_))
396bdd1243dSDimitry Andric       return {};
397bdd1243dSDimitry Andric     if (!__iter.__inner_.has_value())
398bdd1243dSDimitry Andric       return ranges::end(*--__iter.__outer_);
399bdd1243dSDimitry Andric     return *__iter.__inner_;
400bdd1243dSDimitry Andric   }
401bdd1243dSDimitry Andric 
402bdd1243dSDimitry Andric   static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __begin(__segment_iterator __iter) {
403bdd1243dSDimitry Andric     return ranges::begin(*__iter.__get_iter());
404bdd1243dSDimitry Andric   }
405bdd1243dSDimitry Andric 
406bdd1243dSDimitry Andric   static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __end(__segment_iterator __iter) {
407bdd1243dSDimitry Andric     return ranges::end(*__iter.__get_iter());
408bdd1243dSDimitry Andric   }
409bdd1243dSDimitry Andric 
410bdd1243dSDimitry Andric   static constexpr _LIBCPP_HIDE_FROM_ABI _JoinViewIterator
411bdd1243dSDimitry Andric   __compose(__segment_iterator __seg_iter, __local_iterator __local_iter) {
412bdd1243dSDimitry Andric     return _JoinViewIterator(
413bdd1243dSDimitry Andric         std::move(__seg_iter).__get_data(), std::move(__seg_iter).__get_iter(), std::move(__local_iter));
414bdd1243dSDimitry Andric   }
415bdd1243dSDimitry Andric };
416bdd1243dSDimitry Andric 
4175f757f3fSDimitry Andric #endif // #if _LIBCPP_STD_VER >= 20
418349cc55cSDimitry Andric 
419349cc55cSDimitry Andric _LIBCPP_END_NAMESPACE_STD
420349cc55cSDimitry Andric 
421*b3edf446SDimitry Andric _LIBCPP_POP_MACROS
422*b3edf446SDimitry Andric 
423349cc55cSDimitry Andric #endif // _LIBCPP___RANGES_JOIN_VIEW_H
424