27
27
#include < __ranges/all.h>
28
28
#include < __ranges/concepts.h>
29
29
#include < __ranges/empty.h>
30
+ #include < __ranges/helpers.h>
30
31
#include < __ranges/non_propagating_cache.h>
31
32
#include < __ranges/range_adaptor.h>
32
33
#include < __ranges/view_interface.h>
41
42
42
43
_LIBCPP_BEGIN_NAMESPACE_STD
43
44
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)
45
+ #if _LIBCPP_STD_VER >= 20
48
46
49
47
namespace ranges {
50
48
template <class >
@@ -84,11 +82,16 @@ namespace ranges {
84
82
template <class >
85
83
friend struct std ::__segmented_iterator_traits;
86
84
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_;
90
85
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
91
86
87
+ static constexpr bool _UseOuterCache = !forward_range<_View>;
88
+ using _OuterCache = _If<_UseOuterCache, __non_propagating_cache<iterator_t <_View>>, __empty_cache>;
89
+ _LIBCPP_NO_UNIQUE_ADDRESS _OuterCache __outer_;
90
+
91
+ static constexpr bool _UseInnerCache = !is_reference_v<_InnerRange>;
92
+ using _InnerCache = _If<_UseInnerCache, __non_propagating_cache<remove_cvref_t <_InnerRange>>, __empty_cache>;
93
+ _LIBCPP_NO_UNIQUE_ADDRESS _InnerCache __inner_;
94
+
92
95
public:
93
96
_LIBCPP_HIDE_FROM_ABI
94
97
join_view () requires default_initializable<_View> = default ;
@@ -105,16 +108,22 @@ namespace ranges {
105
108
106
109
_LIBCPP_HIDE_FROM_ABI
107
110
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_)};
111
+ if constexpr (forward_range<_View>) {
112
+ constexpr bool __use_const = __simple_view<_View> &&
113
+ is_reference_v<range_reference_t <_View>>;
114
+ return __iterator<__use_const>{*this , ranges::begin (__base_)};
115
+ } else {
116
+ __outer_.__emplace (ranges::begin (__base_));
117
+ return __iterator<false >{*this };
118
+ }
111
119
}
112
120
113
121
template <class _V2 = _View>
114
122
_LIBCPP_HIDE_FROM_ABI
115
123
constexpr auto begin () const
116
- requires input_range<const _V2> &&
117
- is_reference_v<range_reference_t<const _V2>>
124
+ requires forward_range<const _V2> &&
125
+ is_reference_v<range_reference_t<const _V2>> &&
126
+ input_range<range_reference_t<const _V2>>
118
127
{
119
128
return __iterator<true >{*this , ranges::begin (__base_)};
120
129
}
@@ -134,13 +143,12 @@ namespace ranges {
134
143
template <class _V2 = _View>
135
144
_LIBCPP_HIDE_FROM_ABI
136
145
constexpr auto end () const
137
- requires input_range<const _V2> &&
138
- is_reference_v<range_reference_t<const _V2>>
146
+ requires forward_range<const _V2> &&
147
+ is_reference_v<range_reference_t<const _V2>> &&
148
+ input_range<range_reference_t<const _V2>>
139
149
{
140
150
using _ConstInnerRange = range_reference_t <const _View>;
141
- if constexpr (forward_range<const _View> &&
142
- is_reference_v<_ConstInnerRange> &&
143
- forward_range<_ConstInnerRange> &&
151
+ if constexpr (forward_range<_ConstInnerRange> &&
144
152
common_range<const _View> &&
145
153
common_range<_ConstInnerRange>) {
146
154
return __iterator<true >{*this , ranges::end (__base_)};
@@ -154,11 +162,10 @@ namespace ranges {
154
162
requires view<_View> && input_range<range_reference_t <_View>>
155
163
template <bool _Const>
156
164
struct join_view <_View>::__sentinel {
157
- template <bool >
158
- friend struct __sentinel ;
159
-
160
165
private:
161
- using _Parent = __maybe_const<_Const, join_view<_View>>;
166
+ friend join_view;
167
+
168
+ using _Parent = __maybe_const<_Const, join_view>;
162
169
using _Base = __maybe_const<_Const, _View>;
163
170
sentinel_t <_Base> __end_ = sentinel_t <_Base>();
164
171
@@ -179,7 +186,7 @@ namespace ranges {
179
186
requires sentinel_for<sentinel_t <_Base>, iterator_t <__maybe_const<_OtherConst, _View>>>
180
187
_LIBCPP_HIDE_FROM_ABI
181
188
friend constexpr bool operator ==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
182
- return __x.__outer_ == __y.__end_ ;
189
+ return __x.__get_outer () == __y.__end_ ;
183
190
}
184
191
};
185
192
@@ -191,9 +198,7 @@ namespace ranges {
191
198
template <bool _Const>
192
199
struct join_view <_View>::__iterator final
193
200
: public __join_view_iterator_category<__maybe_const<_Const, _View>> {
194
-
195
- template <bool >
196
- friend struct __iterator ;
201
+ friend join_view;
197
202
198
203
template <class >
199
204
friend struct std ::__segmented_iterator_traits;
@@ -209,21 +214,24 @@ namespace ranges {
209
214
210
215
static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t <_Base>>;
211
216
217
+ static constexpr bool _OuterPresent = forward_range<_Base>;
218
+ using _OuterType = _If<_OuterPresent, _Outer, __empty_cache>; // TODO Use `__empty` from D154238
219
+
212
220
public:
213
- _Outer __outer_ = _Outer ();
221
+ _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType ();
214
222
215
223
private:
216
224
optional<_Inner> __inner_;
217
225
_Parent *__parent_ = nullptr ;
218
226
219
227
_LIBCPP_HIDE_FROM_ABI
220
228
constexpr void __satisfy () {
221
- for (; __outer_ != ranges::end (__parent_->__base_ ); ++__outer_ ) {
222
- auto && __inner = [& ]() -> auto && {
229
+ for (; __get_outer () != ranges::end (__parent_->__base_ ); ++__get_outer () ) {
230
+ auto && __inner = [this ]() -> auto && {
223
231
if constexpr (__ref_is_glvalue)
224
- return *__outer_ ;
232
+ return *__get_outer () ;
225
233
else
226
- return __parent_->__cache_ .__emplace_from ([&]() -> decltype (auto ) { return *__outer_ ; });
234
+ return __parent_->__inner_ .__emplace_from ([&]() -> decltype (auto ) { return *__get_outer () ; });
227
235
}();
228
236
__inner_ = ranges::begin (__inner);
229
237
if (*__inner_ != ranges::end (__inner))
@@ -234,8 +242,37 @@ namespace ranges {
234
242
__inner_.reset ();
235
243
}
236
244
245
+ _LIBCPP_HIDE_FROM_ABI constexpr _Outer& __get_outer () {
246
+ if constexpr (forward_range<_Base>) {
247
+ return __outer_;
248
+ } else {
249
+ return *__parent_->__outer_ ;
250
+ }
251
+ }
252
+
253
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Outer& __get_outer () const {
254
+ if constexpr (forward_range<_Base>) {
255
+ return __outer_;
256
+ } else {
257
+ return *__parent_->__outer_ ;
258
+ }
259
+ }
260
+
261
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator (_Parent& __parent, _Outer __outer)
262
+ requires forward_range<_Base>
263
+ : __outer_(std::move(__outer)), __parent_(std::addressof(__parent)) {
264
+ __satisfy ();
265
+ }
266
+
267
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator (_Parent& __parent)
268
+ requires(!forward_range<_Base>)
269
+ : __parent_(std::addressof(__parent)) {
270
+ __satisfy ();
271
+ }
272
+
237
273
_LIBCPP_HIDE_FROM_ABI constexpr __iterator (_Parent* __parent, _Outer __outer, _Inner __inner)
238
- : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
274
+ requires forward_range<_Base>
275
+ : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
239
276
240
277
public:
241
278
using iterator_concept = _If<
@@ -254,15 +291,7 @@ namespace ranges {
254
291
using difference_type = common_type_t <
255
292
range_difference_t <_Base>, range_difference_t <range_reference_t <_Base>>>;
256
293
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
- }
294
+ _LIBCPP_HIDE_FROM_ABI __iterator () = default;
266
295
267
296
_LIBCPP_HIDE_FROM_ABI
268
297
constexpr __iterator (__iterator<!_Const> __i)
@@ -287,14 +316,14 @@ namespace ranges {
287
316
288
317
_LIBCPP_HIDE_FROM_ABI
289
318
constexpr __iterator& operator ++() {
290
- auto && __inner = [&]() -> auto && {
319
+ auto __get_inner_range = [&]() -> decltype ( auto ) {
291
320
if constexpr (__ref_is_glvalue)
292
- return *__outer_ ;
321
+ return *__get_outer () ;
293
322
else
294
- return *__parent_->__cache_ ;
295
- }() ;
296
- if (++*__inner_ == ranges::end (__inner )) {
297
- ++__outer_ ;
323
+ return *__parent_->__inner_ ;
324
+ };
325
+ if (++*__inner_ == ranges::end (ranges::__as_lvalue ( __get_inner_range ()) )) {
326
+ ++__get_outer () ;
298
327
__satisfy ();
299
328
}
300
329
return *this ;
@@ -324,11 +353,11 @@ namespace ranges {
324
353
common_range<range_reference_t <_Base>>
325
354
{
326
355
if (__outer_ == ranges::end (__parent_->__base_ ))
327
- __inner_ = ranges::end (*--__outer_);
356
+ __inner_ = ranges::end (ranges::__as_lvalue ( *--__outer_) );
328
357
329
358
// Skip empty inner ranges when going backwards.
330
- while (*__inner_ == ranges::begin (*__outer_)) {
331
- __inner_ = ranges::end (*--__outer_);
359
+ while (*__inner_ == ranges::begin (ranges::__as_lvalue ( *__outer_) )) {
360
+ __inner_ = ranges::end (ranges::__as_lvalue ( *--__outer_) );
332
361
}
333
362
334
363
--*__inner_;
@@ -350,7 +379,7 @@ namespace ranges {
350
379
_LIBCPP_HIDE_FROM_ABI
351
380
friend constexpr bool operator ==(const __iterator& __x, const __iterator& __y)
352
381
requires __ref_is_glvalue &&
353
- equality_comparable< iterator_t < _Base> > &&
382
+ forward_range< _Base> &&
354
383
equality_comparable<iterator_t <range_reference_t <_Base>>>
355
384
{
356
385
return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_ ;
@@ -436,7 +465,7 @@ struct __segmented_iterator_traits<_JoinViewIterator> {
436
465
}
437
466
};
438
467
439
- #endif // #if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
468
+ #endif // #if _LIBCPP_STD_VER >= 20
440
469
441
470
_LIBCPP_END_NAMESPACE_STD
442
471
0 commit comments