3232#include < __ranges/view_interface.h>
3333#include < __type_traits/common_type.h>
3434#include < __type_traits/maybe_const.h>
35+ #include < __utility/as_lvalue.h>
36+ #include < __utility/empty.h>
3537#include < __utility/forward.h>
3638#include < optional>
3739
4143
4244_LIBCPP_BEGIN_NAMESPACE_STD
4345
44- // Note: `join_view` is still marked experimental because there is an ABI-breaking change that affects `join_view` in
45- // the pipeline (https://isocpp.org/files/papers/D2770R0.html).
46- // TODO: make `join_view` non-experimental once D2770 is implemented.
47- #if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
46+ #if _LIBCPP_STD_VER >= 20
4847
4948namespace ranges {
5049 template <class >
@@ -84,11 +83,16 @@ namespace ranges {
8483 template <class >
8584 friend struct std ::__segmented_iterator_traits;
8685
87- static constexpr bool _UseCache = !is_reference_v<_InnerRange>;
88- using _Cache = _If<_UseCache, __non_propagating_cache<remove_cvref_t <_InnerRange>>, __empty_cache>;
89- _LIBCPP_NO_UNIQUE_ADDRESS _Cache __cache_;
9086 _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
9187
88+ static constexpr bool _UseOuterCache = !forward_range<_View>;
89+ using _OuterCache = _If<_UseOuterCache, __non_propagating_cache<iterator_t <_View>>, __empty_cache>;
90+ _LIBCPP_NO_UNIQUE_ADDRESS _OuterCache __outer_;
91+
92+ static constexpr bool _UseInnerCache = !is_reference_v<_InnerRange>;
93+ using _InnerCache = _If<_UseInnerCache, __non_propagating_cache<remove_cvref_t <_InnerRange>>, __empty_cache>;
94+ _LIBCPP_NO_UNIQUE_ADDRESS _InnerCache __inner_;
95+
9296 public:
9397 _LIBCPP_HIDE_FROM_ABI
9498 join_view () requires default_initializable<_View> = default ;
@@ -105,16 +109,22 @@ namespace ranges {
105109
106110 _LIBCPP_HIDE_FROM_ABI
107111 constexpr auto begin () {
108- constexpr bool __use_const = __simple_view<_View> &&
109- is_reference_v<range_reference_t <_View>>;
110- return __iterator<__use_const>{*this , ranges::begin (__base_)};
112+ if constexpr (forward_range<_View>) {
113+ constexpr bool __use_const = __simple_view<_View> &&
114+ is_reference_v<range_reference_t <_View>>;
115+ return __iterator<__use_const>{*this , ranges::begin (__base_)};
116+ } else {
117+ __outer_.__emplace (ranges::begin (__base_));
118+ return __iterator<false >{*this };
119+ }
111120 }
112121
113122 template <class _V2 = _View>
114123 _LIBCPP_HIDE_FROM_ABI
115124 constexpr auto begin () const
116- requires input_range<const _V2> &&
117- is_reference_v<range_reference_t<const _V2>>
125+ requires forward_range<const _V2> &&
126+ is_reference_v<range_reference_t<const _V2>> &&
127+ input_range<range_reference_t<const _V2>>
118128 {
119129 return __iterator<true >{*this , ranges::begin (__base_)};
120130 }
@@ -134,13 +144,12 @@ namespace ranges {
134144 template <class _V2 = _View>
135145 _LIBCPP_HIDE_FROM_ABI
136146 constexpr auto end () const
137- requires input_range<const _V2> &&
138- is_reference_v<range_reference_t<const _V2>>
147+ requires forward_range<const _V2> &&
148+ is_reference_v<range_reference_t<const _V2>> &&
149+ input_range<range_reference_t<const _V2>>
139150 {
140151 using _ConstInnerRange = range_reference_t <const _View>;
141- if constexpr (forward_range<const _View> &&
142- is_reference_v<_ConstInnerRange> &&
143- forward_range<_ConstInnerRange> &&
152+ if constexpr (forward_range<_ConstInnerRange> &&
144153 common_range<const _View> &&
145154 common_range<_ConstInnerRange>) {
146155 return __iterator<true >{*this , ranges::end (__base_)};
@@ -154,12 +163,12 @@ namespace ranges {
154163 requires view<_View> && input_range<range_reference_t <_View>>
155164 template <bool _Const>
156165 struct join_view <_View>::__sentinel {
157- template <bool >
166+ private:
167+ template <bool >
158168 friend struct __sentinel ;
159169
160- private:
161- using _Parent = __maybe_const<_Const, join_view<_View>>;
162- using _Base = __maybe_const<_Const, _View>;
170+ using _Parent = __maybe_const<_Const, join_view>;
171+ using _Base = __maybe_const<_Const, _View>;
163172 sentinel_t <_Base> __end_ = sentinel_t <_Base>();
164173
165174 public:
@@ -179,7 +188,7 @@ namespace ranges {
179188 requires sentinel_for<sentinel_t <_Base>, iterator_t <__maybe_const<_OtherConst, _View>>>
180189 _LIBCPP_HIDE_FROM_ABI
181190 friend constexpr bool operator ==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
182- return __x.__outer_ == __y.__end_ ;
191+ return __x.__get_outer () == __y.__end_ ;
183192 }
184193 };
185194
@@ -191,9 +200,7 @@ namespace ranges {
191200 template <bool _Const>
192201 struct join_view <_View>::__iterator final
193202 : public __join_view_iterator_category<__maybe_const<_Const, _View>> {
194-
195- template <bool >
196- friend struct __iterator ;
203+ friend join_view;
197204
198205 template <class >
199206 friend struct std ::__segmented_iterator_traits;
@@ -207,23 +214,25 @@ namespace ranges {
207214 using _Inner = iterator_t <range_reference_t <_Base>>;
208215 using _InnerRange = range_reference_t <_View>;
209216
217+ static_assert (!_Const || forward_range<_Base>, " Const can only be true when Base models forward_range." );
218+
210219 static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t <_Base>>;
211220
212- public:
213- _Outer __outer_ = _Outer();
221+ static constexpr bool _OuterPresent = forward_range<_Base>;
222+ using _OuterType = _If<_OuterPresent, _Outer, std::__empty>;
223+ _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType();
214224
215- private:
216225 optional<_Inner> __inner_;
217- _Parent * __parent_ = nullptr ;
226+ _Parent* __parent_ = nullptr ;
218227
219228 _LIBCPP_HIDE_FROM_ABI
220229 constexpr void __satisfy () {
221- for (; __outer_ != ranges::end (__parent_->__base_ ); ++__outer_ ) {
222- auto && __inner = [& ]() -> auto && {
230+ for (; __get_outer () != ranges::end (__parent_->__base_ ); ++__get_outer () ) {
231+ auto && __inner = [this ]() -> auto && {
223232 if constexpr (__ref_is_glvalue)
224- return *__outer_ ;
233+ return *__get_outer () ;
225234 else
226- return __parent_->__cache_ .__emplace_from ([&]() -> decltype (auto ) { return *__outer_ ; });
235+ return __parent_->__inner_ .__emplace_from ([&]() -> decltype (auto ) { return *__get_outer () ; });
227236 }();
228237 __inner_ = ranges::begin (__inner);
229238 if (*__inner_ != ranges::end (__inner))
@@ -234,8 +243,37 @@ namespace ranges {
234243 __inner_.reset ();
235244 }
236245
246+ _LIBCPP_HIDE_FROM_ABI constexpr _Outer& __get_outer () {
247+ if constexpr (forward_range<_Base>) {
248+ return __outer_;
249+ } else {
250+ return *__parent_->__outer_ ;
251+ }
252+ }
253+
254+ _LIBCPP_HIDE_FROM_ABI constexpr const _Outer& __get_outer () const {
255+ if constexpr (forward_range<_Base>) {
256+ return __outer_;
257+ } else {
258+ return *__parent_->__outer_ ;
259+ }
260+ }
261+
262+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator (_Parent& __parent, _Outer __outer)
263+ requires forward_range<_Base>
264+ : __outer_(std::move(__outer)), __parent_(std::addressof(__parent)) {
265+ __satisfy ();
266+ }
267+
268+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator (_Parent& __parent)
269+ requires(!forward_range<_Base>)
270+ : __parent_(std::addressof(__parent)) {
271+ __satisfy ();
272+ }
273+
237274 _LIBCPP_HIDE_FROM_ABI constexpr __iterator (_Parent* __parent, _Outer __outer, _Inner __inner)
238- : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
275+ requires forward_range<_Base>
276+ : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
239277
240278 public:
241279 using iterator_concept = _If<
@@ -254,15 +292,7 @@ namespace ranges {
254292 using difference_type = common_type_t <
255293 range_difference_t <_Base>, range_difference_t <range_reference_t <_Base>>>;
256294
257- _LIBCPP_HIDE_FROM_ABI
258- __iterator () requires default_initializable<_Outer> = default ;
259-
260- _LIBCPP_HIDE_FROM_ABI
261- constexpr __iterator (_Parent& __parent, _Outer __outer)
262- : __outer_(std::move(__outer))
263- , __parent_(std::addressof(__parent)) {
264- __satisfy ();
265- }
295+ _LIBCPP_HIDE_FROM_ABI __iterator () = default;
266296
267297 _LIBCPP_HIDE_FROM_ABI
268298 constexpr __iterator (__iterator<!_Const> __i)
@@ -287,14 +317,14 @@ namespace ranges {
287317
288318 _LIBCPP_HIDE_FROM_ABI
289319 constexpr __iterator& operator ++() {
290- auto && __inner = [&]() -> auto && {
320+ auto __get_inner_range = [&]() -> decltype ( auto ) {
291321 if constexpr (__ref_is_glvalue)
292- return *__outer_ ;
322+ return *__get_outer () ;
293323 else
294- return *__parent_->__cache_ ;
295- }() ;
296- if (++*__inner_ == ranges::end (__inner )) {
297- ++__outer_ ;
324+ return *__parent_->__inner_ ;
325+ };
326+ if (++*__inner_ == ranges::end (std::__as_lvalue ( __get_inner_range ()) )) {
327+ ++__get_outer () ;
298328 __satisfy ();
299329 }
300330 return *this ;
@@ -324,11 +354,11 @@ namespace ranges {
324354 common_range<range_reference_t <_Base>>
325355 {
326356 if (__outer_ == ranges::end (__parent_->__base_ ))
327- __inner_ = ranges::end (*--__outer_);
357+ __inner_ = ranges::end (std::__as_lvalue ( *--__outer_) );
328358
329359 // Skip empty inner ranges when going backwards.
330- while (*__inner_ == ranges::begin (*__outer_)) {
331- __inner_ = ranges::end (*--__outer_);
360+ while (*__inner_ == ranges::begin (std::__as_lvalue ( *__outer_) )) {
361+ __inner_ = ranges::end (std::__as_lvalue ( *--__outer_) );
332362 }
333363
334364 --*__inner_;
@@ -350,7 +380,7 @@ namespace ranges {
350380 _LIBCPP_HIDE_FROM_ABI
351381 friend constexpr bool operator ==(const __iterator& __x, const __iterator& __y)
352382 requires __ref_is_glvalue &&
353- equality_comparable< iterator_t < _Base> > &&
383+ forward_range< _Base> &&
354384 equality_comparable<iterator_t <range_reference_t <_Base>>>
355385 {
356386 return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_ ;
@@ -436,7 +466,7 @@ struct __segmented_iterator_traits<_JoinViewIterator> {
436466 }
437467};
438468
439- #endif // #if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
469+ #endif // #if _LIBCPP_STD_VER >= 20
440470
441471_LIBCPP_END_NAMESPACE_STD
442472
0 commit comments