xref: /openbsd-src/gnu/llvm/libcxx/include/__ranges/join_view.h (revision 4bdff4bed0e3d54e55670334c7d0077db4170f86)
1*4bdff4beSrobert // -*- C++ -*-
2*4bdff4beSrobert //===----------------------------------------------------------------------===//
3*4bdff4beSrobert //
4*4bdff4beSrobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*4bdff4beSrobert // See https://llvm.org/LICENSE.txt for license information.
6*4bdff4beSrobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*4bdff4beSrobert //
8*4bdff4beSrobert //===----------------------------------------------------------------------===//
9*4bdff4beSrobert 
10*4bdff4beSrobert #ifndef _LIBCPP___RANGES_JOIN_VIEW_H
11*4bdff4beSrobert #define _LIBCPP___RANGES_JOIN_VIEW_H
12*4bdff4beSrobert 
13*4bdff4beSrobert #include <__concepts/constructible.h>
14*4bdff4beSrobert #include <__concepts/convertible_to.h>
15*4bdff4beSrobert #include <__concepts/copyable.h>
16*4bdff4beSrobert #include <__concepts/derived_from.h>
17*4bdff4beSrobert #include <__concepts/equality_comparable.h>
18*4bdff4beSrobert #include <__config>
19*4bdff4beSrobert #include <__iterator/concepts.h>
20*4bdff4beSrobert #include <__iterator/iter_move.h>
21*4bdff4beSrobert #include <__iterator/iter_swap.h>
22*4bdff4beSrobert #include <__iterator/iterator_traits.h>
23*4bdff4beSrobert #include <__iterator/iterator_with_data.h>
24*4bdff4beSrobert #include <__iterator/segmented_iterator.h>
25*4bdff4beSrobert #include <__ranges/access.h>
26*4bdff4beSrobert #include <__ranges/all.h>
27*4bdff4beSrobert #include <__ranges/concepts.h>
28*4bdff4beSrobert #include <__ranges/empty.h>
29*4bdff4beSrobert #include <__ranges/non_propagating_cache.h>
30*4bdff4beSrobert #include <__ranges/range_adaptor.h>
31*4bdff4beSrobert #include <__ranges/view_interface.h>
32*4bdff4beSrobert #include <__type_traits/maybe_const.h>
33*4bdff4beSrobert #include <__utility/forward.h>
34*4bdff4beSrobert #include <optional>
35*4bdff4beSrobert #include <type_traits>
36*4bdff4beSrobert 
37*4bdff4beSrobert #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
38*4bdff4beSrobert #  pragma GCC system_header
39*4bdff4beSrobert #endif
40*4bdff4beSrobert 
41*4bdff4beSrobert _LIBCPP_BEGIN_NAMESPACE_STD
42*4bdff4beSrobert 
43*4bdff4beSrobert // Note: `join_view` is still marked experimental because there is an ABI-breaking change that affects `join_view` in
44*4bdff4beSrobert // the pipeline (https://isocpp.org/files/papers/D2770R0.html).
45*4bdff4beSrobert // TODO: make `join_view` non-experimental once D2770 is implemented.
46*4bdff4beSrobert #if _LIBCPP_STD_VER > 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
47*4bdff4beSrobert 
48*4bdff4beSrobert namespace ranges {
49*4bdff4beSrobert   template<class>
50*4bdff4beSrobert   struct __join_view_iterator_category {};
51*4bdff4beSrobert 
52*4bdff4beSrobert   template<class _View>
53*4bdff4beSrobert     requires is_reference_v<range_reference_t<_View>> &&
54*4bdff4beSrobert              forward_range<_View> &&
55*4bdff4beSrobert              forward_range<range_reference_t<_View>>
56*4bdff4beSrobert   struct __join_view_iterator_category<_View> {
57*4bdff4beSrobert     using _OuterC = typename iterator_traits<iterator_t<_View>>::iterator_category;
58*4bdff4beSrobert     using _InnerC = typename iterator_traits<iterator_t<range_reference_t<_View>>>::iterator_category;
59*4bdff4beSrobert 
60*4bdff4beSrobert     using iterator_category = _If<
61*4bdff4beSrobert       derived_from<_OuterC, bidirectional_iterator_tag> && derived_from<_InnerC, bidirectional_iterator_tag> &&
62*4bdff4beSrobert         common_range<range_reference_t<_View>>,
63*4bdff4beSrobert       bidirectional_iterator_tag,
64*4bdff4beSrobert       _If<
65*4bdff4beSrobert         derived_from<_OuterC, forward_iterator_tag> && derived_from<_InnerC, forward_iterator_tag>,
66*4bdff4beSrobert         forward_iterator_tag,
67*4bdff4beSrobert         input_iterator_tag
68*4bdff4beSrobert       >
69*4bdff4beSrobert     >;
70*4bdff4beSrobert   };
71*4bdff4beSrobert 
72*4bdff4beSrobert   template<input_range _View>
73*4bdff4beSrobert     requires view<_View> && input_range<range_reference_t<_View>>
74*4bdff4beSrobert   class join_view
75*4bdff4beSrobert     : public view_interface<join_view<_View>> {
76*4bdff4beSrobert   private:
77*4bdff4beSrobert     using _InnerRange = range_reference_t<_View>;
78*4bdff4beSrobert 
79*4bdff4beSrobert     template<bool> struct __iterator;
80*4bdff4beSrobert 
81*4bdff4beSrobert     template<bool> struct __sentinel;
82*4bdff4beSrobert 
83*4bdff4beSrobert     template <class>
84*4bdff4beSrobert     friend struct std::__segmented_iterator_traits;
85*4bdff4beSrobert 
86*4bdff4beSrobert     static constexpr bool _UseCache = !is_reference_v<_InnerRange>;
87*4bdff4beSrobert     using _Cache = _If<_UseCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>;
88*4bdff4beSrobert     _LIBCPP_NO_UNIQUE_ADDRESS _Cache __cache_;
89*4bdff4beSrobert     _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
90*4bdff4beSrobert 
91*4bdff4beSrobert   public:
92*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
93*4bdff4beSrobert     join_view() requires default_initializable<_View> = default;
94*4bdff4beSrobert 
95*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
96*4bdff4beSrobert     constexpr explicit join_view(_View __base)
97*4bdff4beSrobert       : __base_(std::move(__base)) {}
98*4bdff4beSrobert 
99*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
100*4bdff4beSrobert     constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
101*4bdff4beSrobert 
102*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
103*4bdff4beSrobert     constexpr _View base() && { return std::move(__base_); }
104*4bdff4beSrobert 
105*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
106*4bdff4beSrobert     constexpr auto begin() {
107*4bdff4beSrobert       constexpr bool __use_const = __simple_view<_View> &&
108*4bdff4beSrobert                                    is_reference_v<range_reference_t<_View>>;
109*4bdff4beSrobert       return __iterator<__use_const>{*this, ranges::begin(__base_)};
110*4bdff4beSrobert     }
111*4bdff4beSrobert 
112*4bdff4beSrobert     template<class _V2 = _View>
113*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
114*4bdff4beSrobert     constexpr auto begin() const
115*4bdff4beSrobert       requires input_range<const _V2> &&
116*4bdff4beSrobert                is_reference_v<range_reference_t<const _V2>>
117*4bdff4beSrobert     {
118*4bdff4beSrobert       return __iterator<true>{*this, ranges::begin(__base_)};
119*4bdff4beSrobert     }
120*4bdff4beSrobert 
121*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
122*4bdff4beSrobert     constexpr auto end() {
123*4bdff4beSrobert       if constexpr (forward_range<_View> &&
124*4bdff4beSrobert                     is_reference_v<_InnerRange> &&
125*4bdff4beSrobert                     forward_range<_InnerRange> &&
126*4bdff4beSrobert                     common_range<_View> &&
127*4bdff4beSrobert                     common_range<_InnerRange>)
128*4bdff4beSrobert         return __iterator<__simple_view<_View>>{*this, ranges::end(__base_)};
129*4bdff4beSrobert       else
130*4bdff4beSrobert         return __sentinel<__simple_view<_View>>{*this};
131*4bdff4beSrobert     }
132*4bdff4beSrobert 
133*4bdff4beSrobert     template<class _V2 = _View>
134*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
135*4bdff4beSrobert     constexpr auto end() const
136*4bdff4beSrobert       requires input_range<const _V2> &&
137*4bdff4beSrobert                is_reference_v<range_reference_t<const _V2>>
138*4bdff4beSrobert     {
139*4bdff4beSrobert       using _ConstInnerRange = range_reference_t<const _View>;
140*4bdff4beSrobert       if constexpr (forward_range<const _View> &&
141*4bdff4beSrobert                     is_reference_v<_ConstInnerRange> &&
142*4bdff4beSrobert                     forward_range<_ConstInnerRange> &&
143*4bdff4beSrobert                     common_range<const _View> &&
144*4bdff4beSrobert                     common_range<_ConstInnerRange>) {
145*4bdff4beSrobert         return __iterator<true>{*this, ranges::end(__base_)};
146*4bdff4beSrobert       } else {
147*4bdff4beSrobert         return __sentinel<true>{*this};
148*4bdff4beSrobert       }
149*4bdff4beSrobert     }
150*4bdff4beSrobert   };
151*4bdff4beSrobert 
152*4bdff4beSrobert   template<input_range _View>
153*4bdff4beSrobert     requires view<_View> && input_range<range_reference_t<_View>>
154*4bdff4beSrobert   template<bool _Const>
155*4bdff4beSrobert   struct join_view<_View>::__sentinel {
156*4bdff4beSrobert   template<bool>
157*4bdff4beSrobert     friend struct __sentinel;
158*4bdff4beSrobert 
159*4bdff4beSrobert   private:
160*4bdff4beSrobert     using _Parent = __maybe_const<_Const, join_view<_View>>;
161*4bdff4beSrobert     using _Base = __maybe_const<_Const, _View>;
162*4bdff4beSrobert     sentinel_t<_Base> __end_ = sentinel_t<_Base>();
163*4bdff4beSrobert 
164*4bdff4beSrobert   public:
165*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
166*4bdff4beSrobert     __sentinel() = default;
167*4bdff4beSrobert 
168*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
169*4bdff4beSrobert     constexpr explicit __sentinel(_Parent& __parent)
170*4bdff4beSrobert       : __end_(ranges::end(__parent.__base_)) {}
171*4bdff4beSrobert 
172*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
173*4bdff4beSrobert     constexpr __sentinel(__sentinel<!_Const> __s)
174*4bdff4beSrobert       requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
175*4bdff4beSrobert       : __end_(std::move(__s.__end_)) {}
176*4bdff4beSrobert 
177*4bdff4beSrobert     template<bool _OtherConst>
178*4bdff4beSrobert       requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
179*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
180*4bdff4beSrobert     friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
181*4bdff4beSrobert       return __x.__outer_ == __y.__end_;
182*4bdff4beSrobert     }
183*4bdff4beSrobert   };
184*4bdff4beSrobert 
185*4bdff4beSrobert   // https://reviews.llvm.org/D142811#inline-1383022
186*4bdff4beSrobert   // To simplify the segmented iterator traits specialization,
187*4bdff4beSrobert   // make the iterator `final`
188*4bdff4beSrobert   template<input_range _View>
189*4bdff4beSrobert     requires view<_View> && input_range<range_reference_t<_View>>
190*4bdff4beSrobert   template<bool _Const>
191*4bdff4beSrobert   struct join_view<_View>::__iterator final
192*4bdff4beSrobert     : public __join_view_iterator_category<__maybe_const<_Const, _View>> {
193*4bdff4beSrobert 
194*4bdff4beSrobert     template<bool>
195*4bdff4beSrobert     friend struct __iterator;
196*4bdff4beSrobert 
197*4bdff4beSrobert     template <class>
198*4bdff4beSrobert     friend struct std::__segmented_iterator_traits;
199*4bdff4beSrobert 
200*4bdff4beSrobert     static constexpr bool __is_join_view_iterator = true;
201*4bdff4beSrobert 
202*4bdff4beSrobert   private:
203*4bdff4beSrobert     using _Parent = __maybe_const<_Const, join_view<_View>>;
204*4bdff4beSrobert     using _Base = __maybe_const<_Const, _View>;
205*4bdff4beSrobert     using _Outer = iterator_t<_Base>;
206*4bdff4beSrobert     using _Inner = iterator_t<range_reference_t<_Base>>;
207*4bdff4beSrobert     using _InnerRange = range_reference_t<_View>;
208*4bdff4beSrobert 
209*4bdff4beSrobert     static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>;
210*4bdff4beSrobert 
211*4bdff4beSrobert   public:
212*4bdff4beSrobert     _Outer __outer_ = _Outer();
213*4bdff4beSrobert 
214*4bdff4beSrobert   private:
215*4bdff4beSrobert     optional<_Inner> __inner_;
216*4bdff4beSrobert     _Parent *__parent_ = nullptr;
217*4bdff4beSrobert 
218*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
219*4bdff4beSrobert     constexpr void __satisfy() {
220*4bdff4beSrobert       for (; __outer_ != ranges::end(__parent_->__base_); ++__outer_) {
221*4bdff4beSrobert         auto&& __inner = [&]() -> auto&& {
222*4bdff4beSrobert           if constexpr (__ref_is_glvalue)
223*4bdff4beSrobert             return *__outer_;
224*4bdff4beSrobert           else
225*4bdff4beSrobert             return __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__outer_; });
226*4bdff4beSrobert         }();
227*4bdff4beSrobert         __inner_ = ranges::begin(__inner);
228*4bdff4beSrobert         if (*__inner_ != ranges::end(__inner))
229*4bdff4beSrobert           return;
230*4bdff4beSrobert       }
231*4bdff4beSrobert 
232*4bdff4beSrobert       if constexpr (__ref_is_glvalue)
233*4bdff4beSrobert         __inner_.reset();
234*4bdff4beSrobert     }
235*4bdff4beSrobert 
236*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner)
237*4bdff4beSrobert       : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
238*4bdff4beSrobert 
239*4bdff4beSrobert   public:
240*4bdff4beSrobert     using iterator_concept = _If<
241*4bdff4beSrobert       __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<range_reference_t<_Base>> &&
242*4bdff4beSrobert           common_range<range_reference_t<_Base>>,
243*4bdff4beSrobert       bidirectional_iterator_tag,
244*4bdff4beSrobert       _If<
245*4bdff4beSrobert         __ref_is_glvalue && forward_range<_Base> && forward_range<range_reference_t<_Base>>,
246*4bdff4beSrobert         forward_iterator_tag,
247*4bdff4beSrobert         input_iterator_tag
248*4bdff4beSrobert       >
249*4bdff4beSrobert     >;
250*4bdff4beSrobert 
251*4bdff4beSrobert     using value_type = range_value_t<range_reference_t<_Base>>;
252*4bdff4beSrobert 
253*4bdff4beSrobert     using difference_type = common_type_t<
254*4bdff4beSrobert       range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>;
255*4bdff4beSrobert 
256*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
257*4bdff4beSrobert     __iterator() requires default_initializable<_Outer> = default;
258*4bdff4beSrobert 
259*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
260*4bdff4beSrobert     constexpr __iterator(_Parent& __parent, _Outer __outer)
261*4bdff4beSrobert       : __outer_(std::move(__outer))
262*4bdff4beSrobert       , __parent_(std::addressof(__parent)) {
263*4bdff4beSrobert       __satisfy();
264*4bdff4beSrobert     }
265*4bdff4beSrobert 
266*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
267*4bdff4beSrobert     constexpr __iterator(__iterator<!_Const> __i)
268*4bdff4beSrobert       requires _Const &&
269*4bdff4beSrobert                convertible_to<iterator_t<_View>, _Outer> &&
270*4bdff4beSrobert                convertible_to<iterator_t<_InnerRange>, _Inner>
271*4bdff4beSrobert       : __outer_(std::move(__i.__outer_))
272*4bdff4beSrobert       , __inner_(std::move(__i.__inner_))
273*4bdff4beSrobert       , __parent_(__i.__parent_) {}
274*4bdff4beSrobert 
275*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
276*4bdff4beSrobert     constexpr decltype(auto) operator*() const {
277*4bdff4beSrobert       return **__inner_;
278*4bdff4beSrobert     }
279*4bdff4beSrobert 
280*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
281*4bdff4beSrobert     constexpr _Inner operator->() const
282*4bdff4beSrobert       requires __has_arrow<_Inner> && copyable<_Inner>
283*4bdff4beSrobert     {
284*4bdff4beSrobert       return *__inner_;
285*4bdff4beSrobert     }
286*4bdff4beSrobert 
287*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
288*4bdff4beSrobert     constexpr __iterator& operator++() {
289*4bdff4beSrobert       auto&& __inner = [&]() -> auto&& {
290*4bdff4beSrobert         if constexpr (__ref_is_glvalue)
291*4bdff4beSrobert           return *__outer_;
292*4bdff4beSrobert         else
293*4bdff4beSrobert           return *__parent_->__cache_;
294*4bdff4beSrobert       }();
295*4bdff4beSrobert       if (++*__inner_ == ranges::end(__inner)) {
296*4bdff4beSrobert         ++__outer_;
297*4bdff4beSrobert         __satisfy();
298*4bdff4beSrobert       }
299*4bdff4beSrobert       return *this;
300*4bdff4beSrobert     }
301*4bdff4beSrobert 
302*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
303*4bdff4beSrobert     constexpr void operator++(int) {
304*4bdff4beSrobert       ++*this;
305*4bdff4beSrobert     }
306*4bdff4beSrobert 
307*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
308*4bdff4beSrobert     constexpr __iterator operator++(int)
309*4bdff4beSrobert       requires __ref_is_glvalue &&
310*4bdff4beSrobert                forward_range<_Base> &&
311*4bdff4beSrobert                forward_range<range_reference_t<_Base>>
312*4bdff4beSrobert     {
313*4bdff4beSrobert       auto __tmp = *this;
314*4bdff4beSrobert       ++*this;
315*4bdff4beSrobert       return __tmp;
316*4bdff4beSrobert     }
317*4bdff4beSrobert 
318*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
319*4bdff4beSrobert     constexpr __iterator& operator--()
320*4bdff4beSrobert       requires __ref_is_glvalue &&
321*4bdff4beSrobert                bidirectional_range<_Base> &&
322*4bdff4beSrobert                bidirectional_range<range_reference_t<_Base>> &&
323*4bdff4beSrobert                common_range<range_reference_t<_Base>>
324*4bdff4beSrobert     {
325*4bdff4beSrobert       if (__outer_ == ranges::end(__parent_->__base_))
326*4bdff4beSrobert         __inner_ = ranges::end(*--__outer_);
327*4bdff4beSrobert 
328*4bdff4beSrobert       // Skip empty inner ranges when going backwards.
329*4bdff4beSrobert       while (*__inner_ == ranges::begin(*__outer_)) {
330*4bdff4beSrobert         __inner_ = ranges::end(*--__outer_);
331*4bdff4beSrobert       }
332*4bdff4beSrobert 
333*4bdff4beSrobert       --*__inner_;
334*4bdff4beSrobert       return *this;
335*4bdff4beSrobert     }
336*4bdff4beSrobert 
337*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
338*4bdff4beSrobert     constexpr __iterator operator--(int)
339*4bdff4beSrobert       requires __ref_is_glvalue &&
340*4bdff4beSrobert                bidirectional_range<_Base> &&
341*4bdff4beSrobert                bidirectional_range<range_reference_t<_Base>> &&
342*4bdff4beSrobert                common_range<range_reference_t<_Base>>
343*4bdff4beSrobert     {
344*4bdff4beSrobert       auto __tmp = *this;
345*4bdff4beSrobert       --*this;
346*4bdff4beSrobert       return __tmp;
347*4bdff4beSrobert     }
348*4bdff4beSrobert 
349*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
350*4bdff4beSrobert     friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
351*4bdff4beSrobert       requires __ref_is_glvalue &&
352*4bdff4beSrobert                equality_comparable<iterator_t<_Base>> &&
353*4bdff4beSrobert                equality_comparable<iterator_t<range_reference_t<_Base>>>
354*4bdff4beSrobert     {
355*4bdff4beSrobert       return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_;
356*4bdff4beSrobert     }
357*4bdff4beSrobert 
358*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
359*4bdff4beSrobert     friend constexpr decltype(auto) iter_move(const __iterator& __i)
360*4bdff4beSrobert       noexcept(noexcept(ranges::iter_move(*__i.__inner_)))
361*4bdff4beSrobert     {
362*4bdff4beSrobert       return ranges::iter_move(*__i.__inner_);
363*4bdff4beSrobert     }
364*4bdff4beSrobert 
365*4bdff4beSrobert     _LIBCPP_HIDE_FROM_ABI
366*4bdff4beSrobert     friend constexpr void iter_swap(const __iterator& __x, const __iterator& __y)
367*4bdff4beSrobert       noexcept(noexcept(ranges::iter_swap(*__x.__inner_, *__y.__inner_)))
368*4bdff4beSrobert       requires indirectly_swappable<_Inner>
369*4bdff4beSrobert     {
370*4bdff4beSrobert       return ranges::iter_swap(*__x.__inner_, *__y.__inner_);
371*4bdff4beSrobert     }
372*4bdff4beSrobert   };
373*4bdff4beSrobert 
374*4bdff4beSrobert   template<class _Range>
375*4bdff4beSrobert   explicit join_view(_Range&&) -> join_view<views::all_t<_Range>>;
376*4bdff4beSrobert 
377*4bdff4beSrobert namespace views {
378*4bdff4beSrobert namespace __join_view {
379*4bdff4beSrobert struct __fn : __range_adaptor_closure<__fn> {
380*4bdff4beSrobert   template<class _Range>
381*4bdff4beSrobert   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
382*4bdff4beSrobert   constexpr auto operator()(_Range&& __range) const
383*4bdff4beSrobert     noexcept(noexcept(join_view<all_t<_Range&&>>(std::forward<_Range>(__range))))
384*4bdff4beSrobert     -> decltype(      join_view<all_t<_Range&&>>(std::forward<_Range>(__range)))
385*4bdff4beSrobert     { return          join_view<all_t<_Range&&>>(std::forward<_Range>(__range)); }
386*4bdff4beSrobert };
387*4bdff4beSrobert } // namespace __join_view
388*4bdff4beSrobert inline namespace __cpo {
389*4bdff4beSrobert   inline constexpr auto join = __join_view::__fn{};
390*4bdff4beSrobert } // namespace __cpo
391*4bdff4beSrobert } // namespace views
392*4bdff4beSrobert } // namespace ranges
393*4bdff4beSrobert 
394*4bdff4beSrobert template <class _JoinViewIterator>
395*4bdff4beSrobert   requires(_JoinViewIterator::__is_join_view_iterator &&
396*4bdff4beSrobert            ranges::common_range<typename _JoinViewIterator::_Parent> &&
397*4bdff4beSrobert            __is_cpp17_random_access_iterator<typename _JoinViewIterator::_Outer>::value &&
398*4bdff4beSrobert            __is_cpp17_random_access_iterator<typename _JoinViewIterator::_Inner>::value)
399*4bdff4beSrobert struct __segmented_iterator_traits<_JoinViewIterator> {
400*4bdff4beSrobert 
401*4bdff4beSrobert   using __segment_iterator =
402*4bdff4beSrobert       _LIBCPP_NODEBUG __iterator_with_data<typename _JoinViewIterator::_Outer, typename _JoinViewIterator::_Parent*>;
403*4bdff4beSrobert   using __local_iterator = typename _JoinViewIterator::_Inner;
404*4bdff4beSrobert 
405*4bdff4beSrobert   // TODO: Would it make sense to enable the optimization for other iterator types?
406*4bdff4beSrobert 
407*4bdff4beSrobert   static constexpr _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_JoinViewIterator __iter) {
408*4bdff4beSrobert       if (ranges::empty(__iter.__parent_->__base_))
409*4bdff4beSrobert         return {};
410*4bdff4beSrobert       if (!__iter.__inner_.has_value())
411*4bdff4beSrobert         return __segment_iterator(--__iter.__outer_, __iter.__parent_);
412*4bdff4beSrobert       return __segment_iterator(__iter.__outer_, __iter.__parent_);
413*4bdff4beSrobert   }
414*4bdff4beSrobert 
415*4bdff4beSrobert   static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_JoinViewIterator __iter) {
416*4bdff4beSrobert       if (ranges::empty(__iter.__parent_->__base_))
417*4bdff4beSrobert         return {};
418*4bdff4beSrobert       if (!__iter.__inner_.has_value())
419*4bdff4beSrobert         return ranges::end(*--__iter.__outer_);
420*4bdff4beSrobert       return *__iter.__inner_;
421*4bdff4beSrobert   }
422*4bdff4beSrobert 
423*4bdff4beSrobert   static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __begin(__segment_iterator __iter) {
424*4bdff4beSrobert       return ranges::begin(*__iter.__get_iter());
425*4bdff4beSrobert   }
426*4bdff4beSrobert 
427*4bdff4beSrobert   static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __end(__segment_iterator __iter) {
428*4bdff4beSrobert       return ranges::end(*__iter.__get_iter());
429*4bdff4beSrobert   }
430*4bdff4beSrobert 
431*4bdff4beSrobert   static constexpr _LIBCPP_HIDE_FROM_ABI _JoinViewIterator
432*4bdff4beSrobert   __compose(__segment_iterator __seg_iter, __local_iterator __local_iter) {
433*4bdff4beSrobert       return _JoinViewIterator(
434*4bdff4beSrobert           std::move(__seg_iter).__get_data(), std::move(__seg_iter).__get_iter(), std::move(__local_iter));
435*4bdff4beSrobert   }
436*4bdff4beSrobert };
437*4bdff4beSrobert 
438*4bdff4beSrobert #endif // #if _LIBCPP_STD_VER > 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
439*4bdff4beSrobert 
440*4bdff4beSrobert _LIBCPP_END_NAMESPACE_STD
441*4bdff4beSrobert 
442*4bdff4beSrobert #endif // _LIBCPP___RANGES_JOIN_VIEW_H
443