32
32
#include < __ranges/view_interface.h>
33
33
#include < __type_traits/common_type.h>
34
34
#include < __type_traits/maybe_const.h>
35
+ #include < __utility/as_lvalue.h>
36
+ #include < __utility/empty.h>
35
37
#include < __utility/forward.h>
36
38
#include < optional>
37
39
41
43
42
44
_LIBCPP_BEGIN_NAMESPACE_STD
43
45
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
48
47
49
48
namespace ranges {
50
49
template <class >
@@ -84,11 +83,16 @@ namespace ranges {
84
83
template <class >
85
84
friend struct std ::__segmented_iterator_traits;
86
85
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
86
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
91
87
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
+
92
96
public:
93
97
_LIBCPP_HIDE_FROM_ABI
94
98
join_view () requires default_initializable<_View> = default ;
@@ -105,16 +109,22 @@ namespace ranges {
105
109
106
110
_LIBCPP_HIDE_FROM_ABI
107
111
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
+ }
111
120
}
112
121
113
122
template <class _V2 = _View>
114
123
_LIBCPP_HIDE_FROM_ABI
115
124
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>>
118
128
{
119
129
return __iterator<true >{*this , ranges::begin (__base_)};
120
130
}
@@ -134,13 +144,12 @@ namespace ranges {
134
144
template <class _V2 = _View>
135
145
_LIBCPP_HIDE_FROM_ABI
136
146
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>>
139
150
{
140
151
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> &&
144
153
common_range<const _View> &&
145
154
common_range<_ConstInnerRange>) {
146
155
return __iterator<true >{*this , ranges::end (__base_)};
@@ -154,12 +163,12 @@ namespace ranges {
154
163
requires view<_View> && input_range<range_reference_t <_View>>
155
164
template <bool _Const>
156
165
struct join_view <_View>::__sentinel {
157
- template <bool >
166
+ private:
167
+ template <bool >
158
168
friend struct __sentinel ;
159
169
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>;
163
172
sentinel_t <_Base> __end_ = sentinel_t <_Base>();
164
173
165
174
public:
@@ -179,7 +188,7 @@ namespace ranges {
179
188
requires sentinel_for<sentinel_t <_Base>, iterator_t <__maybe_const<_OtherConst, _View>>>
180
189
_LIBCPP_HIDE_FROM_ABI
181
190
friend constexpr bool operator ==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
182
- return __x.__outer_ == __y.__end_ ;
191
+ return __x.__get_outer () == __y.__end_ ;
183
192
}
184
193
};
185
194
@@ -191,9 +200,7 @@ namespace ranges {
191
200
template <bool _Const>
192
201
struct join_view <_View>::__iterator final
193
202
: public __join_view_iterator_category<__maybe_const<_Const, _View>> {
194
-
195
- template <bool >
196
- friend struct __iterator ;
203
+ friend join_view;
197
204
198
205
template <class >
199
206
friend struct std ::__segmented_iterator_traits;
@@ -207,23 +214,25 @@ namespace ranges {
207
214
using _Inner = iterator_t <range_reference_t <_Base>>;
208
215
using _InnerRange = range_reference_t <_View>;
209
216
217
+ static_assert (!_Const || forward_range<_Base>, " Const can only be true when Base models forward_range." );
218
+
210
219
static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t <_Base>>;
211
220
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();
214
224
215
- private:
216
225
optional<_Inner> __inner_;
217
- _Parent * __parent_ = nullptr ;
226
+ _Parent* __parent_ = nullptr ;
218
227
219
228
_LIBCPP_HIDE_FROM_ABI
220
229
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 && {
223
232
if constexpr (__ref_is_glvalue)
224
- return *__outer_ ;
233
+ return *__get_outer () ;
225
234
else
226
- return __parent_->__cache_ .__emplace_from ([&]() -> decltype (auto ) { return *__outer_ ; });
235
+ return __parent_->__inner_ .__emplace_from ([&]() -> decltype (auto ) { return *__get_outer () ; });
227
236
}();
228
237
__inner_ = ranges::begin (__inner);
229
238
if (*__inner_ != ranges::end (__inner))
@@ -234,8 +243,37 @@ namespace ranges {
234
243
__inner_.reset ();
235
244
}
236
245
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
+
237
274
_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) {}
239
277
240
278
public:
241
279
using iterator_concept = _If<
@@ -254,15 +292,7 @@ namespace ranges {
254
292
using difference_type = common_type_t <
255
293
range_difference_t <_Base>, range_difference_t <range_reference_t <_Base>>>;
256
294
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;
266
296
267
297
_LIBCPP_HIDE_FROM_ABI
268
298
constexpr __iterator (__iterator<!_Const> __i)
@@ -287,14 +317,14 @@ namespace ranges {
287
317
288
318
_LIBCPP_HIDE_FROM_ABI
289
319
constexpr __iterator& operator ++() {
290
- auto && __inner = [&]() -> auto && {
320
+ auto __get_inner_range = [&]() -> decltype ( auto ) {
291
321
if constexpr (__ref_is_glvalue)
292
- return *__outer_ ;
322
+ return *__get_outer () ;
293
323
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 () ;
298
328
__satisfy ();
299
329
}
300
330
return *this ;
@@ -324,11 +354,11 @@ namespace ranges {
324
354
common_range<range_reference_t <_Base>>
325
355
{
326
356
if (__outer_ == ranges::end (__parent_->__base_ ))
327
- __inner_ = ranges::end (*--__outer_);
357
+ __inner_ = ranges::end (std::__as_lvalue ( *--__outer_) );
328
358
329
359
// 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_) );
332
362
}
333
363
334
364
--*__inner_;
@@ -350,7 +380,7 @@ namespace ranges {
350
380
_LIBCPP_HIDE_FROM_ABI
351
381
friend constexpr bool operator ==(const __iterator& __x, const __iterator& __y)
352
382
requires __ref_is_glvalue &&
353
- equality_comparable< iterator_t < _Base> > &&
383
+ forward_range< _Base> &&
354
384
equality_comparable<iterator_t <range_reference_t <_Base>>>
355
385
{
356
386
return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_ ;
@@ -436,7 +466,7 @@ struct __segmented_iterator_traits<_JoinViewIterator> {
436
466
}
437
467
};
438
468
439
- #endif // #if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
469
+ #endif // #if _LIBCPP_STD_VER >= 20
440
470
441
471
_LIBCPP_END_NAMESPACE_STD
442
472
0 commit comments