Skip to content

Commit 28d5f0c

Browse files
committed
[libc++] P2770R0: "Stashing stashing iterators for proper flattening"
* Parially implements P2770R0: "Stashing stashing iterators for proper flattening" * `join_with_view` hasn't been done yet since this type isn't implemented yet * Rename `test/libcxx/ranges/range.adaptors/range.adaptor.tuple` directory to `test/libcxx/ranges/range.adaptors/range.adaptor.helpers` to match the standard: http://eel.is/c++draft/range.adaptor.helpers (this change happened in P2770R0, see point 3 of wording). * Rename `libcxx\test\std\ranges\range.adaptors\range.join.view` to `libcxx\test\std\ranges\range.adaptors\range.join` to match the standard * Add new `__ranges/helpers.h` file with `__as_const` function (used by both `views::join` and `views::join_with`)
1 parent c7d65e4 commit 28d5f0c

Some content is hidden

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

45 files changed

+350
-182
lines changed

libcxx/docs/Status/Cxx23.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Paper Status
4646
clang doesn't issue a diagnostic for deprecated using template declarations.
4747
.. [#note-P2520R0] P2520R0: Libc++ implemented this paper as a DR in C++20 as well.
4848
.. [#note-P2711R1] P2711R1: ``join_with_view`` hasn't been done yet since this type isn't implemented yet.
49+
.. [#note-P2770R0] P2770R0: Same as the above.
4950
.. [#note-P2693R1] P2693R1: The formatter for ``std::thread::id`` is implemented.
5051
The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is
5152
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","","","|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","|Partial| [#note-P2711R1]_","","|ranges|"
110110
"`P2609R3 <https://wg21.link/P2609R3>`__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|"

libcxx/docs/Status/RangesMajorFeatures.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ Standard,Name,Assignee,CL,Status
22
C++23,`ranges::to <https://wg21.link/P1206R7>`_,Konstantin Varlamov,`D142335 <https://reviews.llvm.org/D142335>`_,Complete
33
C++23,`Pipe support for user-defined range adaptors <https://wg21.link/P2387R3>`_,Unassigned,No patch yet,Not started
44
C++23,`Formatting Ranges <https://wg21.link/P2286R8>`_,Mark de Wever,Various,Complete
5+
C++20,`Stashing stashing iterators for proper flattening <https://wg21.link/P2770R0>`_,Jakub Mazurkiewicz,Various,In progress

libcxx/docs/Status/RangesViews.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ C++23,`zip <https://wg21.link/P2321R2>`_,Hui Xie,`D122806 <https://llvm.org/D122
2828
C++23,`zip_transform <https://wg21.link/P2321R2>`_,Hui Xie,No patch yet,Not started
2929
C++23,`adjacent <https://wg21.link/P2321R2>`_,Hui Xie,No patch yet,Not started
3030
C++23,`adjacent_transform <https://wg21.link/P2321R2>`_,Hui Xie,No patch yet,Not started
31-
C++23,`join_with <https://wg21.link/P2441R2>`_,Unassigned,No patch yet,Not started
31+
C++23,`join_with <https://wg21.link/P2441R2>`_,Jakub Mazurkiewicz,`GitHub #65536 <https://github.com/llvm/llvm-project/pull/65536>`_,In progress
3232
C++23,`slide <https://wg21.link/P2442R1>`_,Unassigned,No patch yet,Not started
3333
C++23,`chunk <https://wg21.link/P2442R1>`_,Unassigned,No patch yet,Not started
3434
C++23,`chunk_by <https://wg21.link/P2443R1>`_,Jakub Mazurkiewicz,`D144767 <https://llvm.org/D144767>`_,✅

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ set(files
620620
__ranges/enable_view.h
621621
__ranges/filter_view.h
622622
__ranges/from_range.h
623+
__ranges/helpers.h
623624
__ranges/iota_view.h
624625
__ranges/istream_view.h
625626
__ranges/join_view.h

libcxx/include/__ranges/helpers.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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___RANGES_HELPERS_H
11+
#define _LIBCPP___RANGES_HELPERS_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+
#if _LIBCPP_STD_VER >= 20
25+
26+
namespace ranges {
27+
template <class _Tp>
28+
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __as_lvalue(_LIBCPP_LIFETIMEBOUND _Tp&& __t) {
29+
return static_cast<_Tp&>(__t);
30+
}
31+
} // namespace ranges
32+
33+
#endif // _LIBCPP_STD_VER >= 20
34+
35+
_LIBCPP_END_NAMESPACE_STD
36+
37+
_LIBCPP_POP_MACROS
38+
39+
#endif // _LIBCPP___RANGES_HELPERS_H

libcxx/include/__ranges/join_view.h

Lines changed: 80 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <__ranges/all.h>
2828
#include <__ranges/concepts.h>
2929
#include <__ranges/empty.h>
30+
#include <__ranges/helpers.h>
3031
#include <__ranges/non_propagating_cache.h>
3132
#include <__ranges/range_adaptor.h>
3233
#include <__ranges/view_interface.h>
@@ -41,10 +42,7 @@
4142

4243
_LIBCPP_BEGIN_NAMESPACE_STD
4344

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
4846

4947
namespace ranges {
5048
template<class>
@@ -84,11 +82,16 @@ namespace ranges {
8482
template <class>
8583
friend struct std::__segmented_iterator_traits;
8684

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_;
9085
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
9186

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+
9295
public:
9396
_LIBCPP_HIDE_FROM_ABI
9497
join_view() requires default_initializable<_View> = default;
@@ -105,16 +108,22 @@ namespace ranges {
105108

106109
_LIBCPP_HIDE_FROM_ABI
107110
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+
}
111119
}
112120

113121
template<class _V2 = _View>
114122
_LIBCPP_HIDE_FROM_ABI
115123
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>>
118127
{
119128
return __iterator<true>{*this, ranges::begin(__base_)};
120129
}
@@ -134,13 +143,12 @@ namespace ranges {
134143
template<class _V2 = _View>
135144
_LIBCPP_HIDE_FROM_ABI
136145
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>>
139149
{
140150
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> &&
144152
common_range<const _View> &&
145153
common_range<_ConstInnerRange>) {
146154
return __iterator<true>{*this, ranges::end(__base_)};
@@ -154,11 +162,10 @@ namespace ranges {
154162
requires view<_View> && input_range<range_reference_t<_View>>
155163
template<bool _Const>
156164
struct join_view<_View>::__sentinel {
157-
template<bool>
158-
friend struct __sentinel;
159-
160165
private:
161-
using _Parent = __maybe_const<_Const, join_view<_View>>;
166+
friend join_view;
167+
168+
using _Parent = __maybe_const<_Const, join_view>;
162169
using _Base = __maybe_const<_Const, _View>;
163170
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
164171

@@ -179,7 +186,7 @@ namespace ranges {
179186
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
180187
_LIBCPP_HIDE_FROM_ABI
181188
friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
182-
return __x.__outer_ == __y.__end_;
189+
return __x.__get_outer() == __y.__end_;
183190
}
184191
};
185192

@@ -191,9 +198,7 @@ namespace ranges {
191198
template<bool _Const>
192199
struct join_view<_View>::__iterator final
193200
: public __join_view_iterator_category<__maybe_const<_Const, _View>> {
194-
195-
template<bool>
196-
friend struct __iterator;
201+
friend join_view;
197202

198203
template <class>
199204
friend struct std::__segmented_iterator_traits;
@@ -209,21 +214,24 @@ namespace ranges {
209214

210215
static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>;
211216

217+
static constexpr bool _OuterPresent = forward_range<_Base>;
218+
using _OuterType = _If<_OuterPresent, _Outer, __empty_cache>; // TODO Use `__empty` from D154238
219+
212220
public:
213-
_Outer __outer_ = _Outer();
221+
_LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType();
214222

215223
private:
216224
optional<_Inner> __inner_;
217225
_Parent *__parent_ = nullptr;
218226

219227
_LIBCPP_HIDE_FROM_ABI
220228
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&& {
223231
if constexpr (__ref_is_glvalue)
224-
return *__outer_;
232+
return *__get_outer();
225233
else
226-
return __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__outer_; });
234+
return __parent_->__inner_.__emplace_from([&]() -> decltype(auto) { return *__get_outer(); });
227235
}();
228236
__inner_ = ranges::begin(__inner);
229237
if (*__inner_ != ranges::end(__inner))
@@ -234,8 +242,37 @@ namespace ranges {
234242
__inner_.reset();
235243
}
236244

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+
237273
_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) {}
239276

240277
public:
241278
using iterator_concept = _If<
@@ -254,15 +291,7 @@ namespace ranges {
254291
using difference_type = common_type_t<
255292
range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>;
256293

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;
266295

267296
_LIBCPP_HIDE_FROM_ABI
268297
constexpr __iterator(__iterator<!_Const> __i)
@@ -287,14 +316,14 @@ namespace ranges {
287316

288317
_LIBCPP_HIDE_FROM_ABI
289318
constexpr __iterator& operator++() {
290-
auto&& __inner = [&]() -> auto&& {
319+
auto __get_inner_range = [&]() -> decltype(auto) {
291320
if constexpr (__ref_is_glvalue)
292-
return *__outer_;
321+
return *__get_outer();
293322
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();
298327
__satisfy();
299328
}
300329
return *this;
@@ -324,11 +353,11 @@ namespace ranges {
324353
common_range<range_reference_t<_Base>>
325354
{
326355
if (__outer_ == ranges::end(__parent_->__base_))
327-
__inner_ = ranges::end(*--__outer_);
356+
__inner_ = ranges::end(ranges::__as_lvalue(*--__outer_));
328357

329358
// 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_));
332361
}
333362

334363
--*__inner_;
@@ -350,7 +379,7 @@ namespace ranges {
350379
_LIBCPP_HIDE_FROM_ABI
351380
friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
352381
requires __ref_is_glvalue &&
353-
equality_comparable<iterator_t<_Base>> &&
382+
forward_range<_Base> &&
354383
equality_comparable<iterator_t<range_reference_t<_Base>>>
355384
{
356385
return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_;
@@ -436,7 +465,7 @@ struct __segmented_iterator_traits<_JoinViewIterator> {
436465
}
437466
};
438467

439-
#endif // #if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
468+
#endif // #if _LIBCPP_STD_VER >= 20
440469

441470
_LIBCPP_END_NAMESPACE_STD
442471

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,7 @@ module std_private_ranges_filter_view [system] {
16921692
export std_private_ranges_range_adaptor
16931693
}
16941694
module std_private_ranges_from_range [system] { header "__ranges/from_range.h" }
1695+
module std_private_ranges_helpers [system] { header "__ranges/helpers.h" }
16951696
module std_private_ranges_iota_view [system] { header "__ranges/iota_view.h" }
16961697
module std_private_ranges_istream_view [system] {
16971698
header "__ranges/istream_view.h"

libcxx/include/ranges

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ namespace std {
395395
#include <__ranges/enable_view.h>
396396
#include <__ranges/filter_view.h>
397397
#include <__ranges/from_range.h>
398+
#include <__ranges/helpers.h>
398399
#include <__ranges/iota_view.h>
399400
#include <__ranges/join_view.h>
400401
#include <__ranges/lazy_split_view.h>

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;

0 commit comments

Comments
 (0)