Skip to content

Commit 6a66467

Browse files
[libc++] P2770R0: Stashing stashing iterators for proper flattening (#66033)
- Partially implements P2770R0 (http://wg21.link/p2770) - Fixes https://wg21.link/LWG3698, https://wg21.link/LWG3700, and https://wg21.link/LWG3791 - join_with_view hasn't been done yet since this type isn't implemented yet - Rename tuple test directory to match the standard (which changed in P2770R0) - Rename join_view test directory to match the standard
1 parent 87c6867 commit 6a66467

File tree

55 files changed

+605
-196
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+605
-196
lines changed

libcxx/docs/Status/Cxx23.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Paper Status
4545
clang doesn't issue a diagnostic for deprecated using template declarations.
4646
.. [#note-P2520R0] P2520R0: Libc++ implemented this paper as a DR in C++20 as well.
4747
.. [#note-P2711R1] P2711R1: ``join_with_view`` hasn't been done yet since this type isn't implemented yet.
48+
.. [#note-P2770R0] P2770R0: ``join_with_view`` hasn't been done yet since this type isn't implemented yet.
4849
.. [#note-P2693R1] P2693R1: The formatter for ``std::thread::id`` is implemented.
4950
The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is
5051
not implemented yet.

libcxx/docs/Status/Cxx23Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
"`P2708R1 <https://wg21.link/P2708R1>`__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","",""
105105
"","","","","","",""
106106
"`P0290R4 <https://wg21.link/P0290R4>`__","LWG", "``apply()`` for ``synchronized_value<T>``","February 2023","","","|concurrency TS|"
107-
"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|In Progress|","","|ranges|"
107+
"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|Partial| [#note-P2770R0]_","","|ranges|"
108108
"`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","","","|ranges|"
109109
"`P2711R1 <https://wg21.link/P2711R1>`__","LWG", "Making multi-param constructors of ``views`` ``explicit``","February 2023","|In Progress| [#note-P2711R1]_","","|ranges|"
110110
"`P2609R3 <https://wg21.link/P2609R3>`__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|"

libcxx/docs/UsingLibcxx.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ when ``-fexperimental-library`` is passed:
5050
* ``std::stop_token``, ``std::stop_source`` and ``std::stop_callback``
5151
* ``std::jthread``
5252
* ``std::chrono::tzdb`` and related time zone functionality
53-
* ``std::ranges::join_view``
5453

5554
.. warning::
5655
Experimental libraries are experimental.

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ set(files
837837
__type_traits/void_t.h
838838
__undef_macros
839839
__utility/as_const.h
840+
__utility/as_lvalue.h
840841
__utility/auto_cast.h
841842
__utility/cmp.h
842843
__utility/convert_to_integral.h

libcxx/include/__ranges/join_view.h

Lines changed: 84 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
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

@@ -41,10 +43,7 @@
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

4948
namespace 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

libcxx/include/__utility/as_lvalue.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___UTILITY_AS_LVALUE_H
11+
#define _LIBCPP___UTILITY_AS_LVALUE_H
12+
13+
#include <__config>
14+
15+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
16+
# pragma GCC system_header
17+
#endif
18+
19+
_LIBCPP_PUSH_MACROS
20+
#include <__undef_macros>
21+
22+
_LIBCPP_BEGIN_NAMESPACE_STD
23+
24+
#ifndef _LIBCPP_CXX03_LANG
25+
26+
template <class _Tp>
27+
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __as_lvalue(_LIBCPP_LIFETIMEBOUND _Tp&& __t) {
28+
return static_cast<_Tp&>(__t);
29+
}
30+
31+
#endif // !_LIBCPP_CXX03_LANG
32+
33+
_LIBCPP_END_NAMESPACE_STD
34+
35+
_LIBCPP_POP_MACROS
36+
37+
#endif // _LIBCPP___UTILITY_AS_LVALUE_H

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2019,6 +2019,7 @@ module std_private_type_traits_unwrap_ref [system
20192019
module std_private_type_traits_void_t [system] { header "__type_traits/void_t.h" }
20202020

20212021
module std_private_utility_as_const [system] { header "__utility/as_const.h" }
2022+
module std_private_utility_as_lvalue [system] { header "__utility/as_lvalue.h" }
20222023
module std_private_utility_auto_cast [system] {
20232024
header "__utility/auto_cast.h"
20242025
export std_private_type_traits_decay

libcxx/include/regex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@ public:
697697
typedef const value_type* pointer;
698698
typedef const value_type& reference;
699699
typedef forward_iterator_tag iterator_category;
700+
typedef input_iterator_tag iterator_concept; // since C++20
700701
701702
regex_iterator();
702703
regex_iterator(BidirectionalIterator a, BidirectionalIterator b,
@@ -737,6 +738,7 @@ public:
737738
typedef const value_type* pointer;
738739
typedef const value_type& reference;
739740
typedef forward_iterator_tag iterator_category;
741+
typedef input_iterator_tag iterator_concept; // since C++20
740742
741743
regex_token_iterator();
742744
regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
@@ -6407,6 +6409,9 @@ public:
64076409
typedef const value_type* pointer;
64086410
typedef const value_type& reference;
64096411
typedef forward_iterator_tag iterator_category;
6412+
#if _LIBCPP_STD_VER >= 20
6413+
typedef input_iterator_tag iterator_concept;
6414+
#endif
64106415

64116416
private:
64126417
_BidirectionalIterator __begin_;
@@ -6542,6 +6547,9 @@ public:
65426547
typedef const value_type* pointer;
65436548
typedef const value_type& reference;
65446549
typedef forward_iterator_tag iterator_category;
6550+
#if _LIBCPP_STD_VER >= 20
6551+
typedef input_iterator_tag iterator_concept;
6552+
#endif
65456553

65466554
private:
65476555
typedef regex_iterator<_BidirectionalIterator, _CharT, _Traits> _Position;

libcxx/include/utility

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ template <class T>
249249
#include <__assert> // all public C++ headers provide the assertion handler
250250
#include <__config>
251251
#include <__utility/as_const.h>
252+
#include <__utility/as_lvalue.h>
252253
#include <__utility/auto_cast.h>
253254
#include <__utility/cmp.h>
254255
#include <__utility/declval.h>

0 commit comments

Comments
 (0)