Skip to content

Commit b40a3d7

Browse files
committed
[libc++] Implement P2446R2 (views::as_rvalue)
Reviewed By: ldionne, var-const, #libc Spies: libcxx-commits Differential Revision: https://reviews.llvm.org/D137637
1 parent 6c48540 commit b40a3d7

File tree

20 files changed

+888
-2
lines changed

20 files changed

+888
-2
lines changed

libcxx/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Implemented Papers
6868
- P0323R12 - ``std::expected``
6969
- P1035R7 - Input Range Adaptors
7070
- P2325R3 - Views should not be required to be default constructible
71+
- P2446R2 - ``views::as_rvalue``
7172

7273
Improvements and New Features
7374
-----------------------------

libcxx/docs/Status/Cxx2bPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
"`P2419R2 <https://wg21.link/P2419R2>`__","LWG","Clarify handling of encodings in localized formatting of chrono types","July 2022","",""
7474
"`P2438R2 <https://wg21.link/P2438R2>`__","LWG","``std::string::substr() &&``","July 2022","|Complete|","16.0"
7575
"`P2445R1 <https://wg21.link/P2445R1>`__","LWG","``forward_like``","July 2022","|Complete|","16.0"
76-
"`P2446R2 <https://wg21.link/P2446R2>`__","LWG","``views::as_rvalue``","July 2022","","","|ranges|"
76+
"`P2446R2 <https://wg21.link/P2446R2>`__","LWG","``views::as_rvalue``","July 2022","|Complete|","16.0","|ranges|"
7777
"`P2460R2 <https://wg21.link/P2460R2>`__","LWG","Relax requirements on ``wchar_t`` to match existing practices","July 2022","",""
7878
"`P2465R3 <https://wg21.link/P2465R3>`__","LWG","Standard Library Modules ``std`` and ``std.compat``","July 2022","",""
7979
"`P2467R1 <https://wg21.link/P2467R1>`__","LWG","Support exclusive mode for ``fstreams``","July 2022","",""

libcxx/docs/Status/RangesViews.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ 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>`_,Unassigned,No patch yet,Not started
3535
C++23,`as_const <https://wg21.link/P2278R4>`_,Unassigned,No patch yet,Not started
36-
C++23,`as_rvalue <https://wg21.link/P2446R2>`_,Nikolas Klauser,`D137637 <https://llvm.org/D137637>`_,Under review
36+
C++23,`as_rvalue <https://wg21.link/P2446R2>`_,Nikolas Klauser,`D137637 <https://llvm.org/D137637>`_,Complete
3737
C++23,`stride <https://wg21.link/P1899R3>`_,Unassigned,No patch yet,Not started

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ set(files
499499
__random/weibull_distribution.h
500500
__ranges/access.h
501501
__ranges/all.h
502+
__ranges/as_rvalue_view.h
502503
__ranges/common_view.h
503504
__ranges/concepts.h
504505
__ranges/copyable_box.h

libcxx/include/__iterator/move_sentinel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ class _LIBCPP_TEMPLATE_VIS move_sentinel
5050
_Sent __last_ = _Sent();
5151
};
5252

53+
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(move_sentinel);
54+
5355
#endif // _LIBCPP_STD_VER > 17
5456

5557
_LIBCPP_END_NAMESPACE_STD
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___RANGES_AS_RVALUE_H
10+
#define _LIBCPP___RANGES_AS_RVALUE_H
11+
12+
#include <__concepts/constructible.h>
13+
#include <__concepts/same_as.h>
14+
#include <__config>
15+
#include <__iterator/move_iterator.h>
16+
#include <__iterator/move_sentinel.h>
17+
#include <__ranges/access.h>
18+
#include <__ranges/all.h>
19+
#include <__ranges/concepts.h>
20+
#include <__ranges/enable_borrowed_range.h>
21+
#include <__ranges/range_adaptor.h>
22+
#include <__ranges/size.h>
23+
#include <__ranges/view_interface.h>
24+
#include <__utility/forward.h>
25+
#include <__utility/move.h>
26+
27+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28+
# pragma GCC system_header
29+
#endif
30+
31+
#if _LIBCPP_STD_VER >= 23
32+
33+
_LIBCPP_BEGIN_NAMESPACE_STD
34+
35+
namespace ranges {
36+
template <view _View>
37+
requires input_range<_View>
38+
class as_rvalue_view : public view_interface<as_rvalue_view<_View>> {
39+
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
40+
41+
public:
42+
_LIBCPP_HIDE_FROM_ABI as_rvalue_view()
43+
requires default_initializable<_View>
44+
= default;
45+
46+
_LIBCPP_HIDE_FROM_ABI constexpr explicit as_rvalue_view(_View __base) : __base_(std::move(__base)) {}
47+
48+
_LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
49+
requires copy_constructible<_View>
50+
{
51+
return __base_;
52+
}
53+
54+
_LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
55+
56+
_LIBCPP_HIDE_FROM_ABI constexpr auto begin()
57+
requires(!__simple_view<_View>)
58+
{
59+
return move_iterator(ranges::begin(__base_));
60+
}
61+
62+
_LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
63+
requires range<const _View>
64+
{
65+
return move_iterator(ranges::begin(__base_));
66+
}
67+
68+
_LIBCPP_HIDE_FROM_ABI constexpr auto end()
69+
requires(!__simple_view<_View>)
70+
{
71+
if constexpr (common_range<_View>) {
72+
return move_iterator(ranges::end(__base_));
73+
} else {
74+
return move_sentinel(ranges::end(__base_));
75+
}
76+
}
77+
78+
_LIBCPP_HIDE_FROM_ABI constexpr auto end() const
79+
requires range<const _View>
80+
{
81+
if constexpr (common_range<const _View>) {
82+
return move_iterator(ranges::end(__base_));
83+
} else {
84+
return move_sentinel(ranges::end(__base_));
85+
}
86+
}
87+
88+
_LIBCPP_HIDE_FROM_ABI constexpr auto size()
89+
requires sized_range<_View>
90+
{
91+
return ranges::size(__base_);
92+
}
93+
94+
_LIBCPP_HIDE_FROM_ABI constexpr auto size() const
95+
requires sized_range<const _View>
96+
{
97+
return ranges::size(__base_);
98+
}
99+
};
100+
101+
template <class _Range>
102+
as_rvalue_view(_Range&&) -> as_rvalue_view<views::all_t<_Range>>;
103+
104+
template <class _View>
105+
inline constexpr bool enable_borrowed_range<as_rvalue_view<_View>> = enable_borrowed_range<_View>;
106+
107+
namespace views {
108+
namespace __as_rvalue {
109+
struct __fn : __range_adaptor_closure<__fn> {
110+
template <class _Range>
111+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
112+
noexcept(noexcept(/**/ as_rvalue_view(std::forward<_Range>(__range))))
113+
-> decltype(/*--*/ as_rvalue_view(std::forward<_Range>(__range))) {
114+
return /*-------------*/ as_rvalue_view(std::forward<_Range>(__range));
115+
}
116+
117+
template <class _Range>
118+
requires same_as<range_rvalue_reference_t<_Range>, range_reference_t<_Range>>
119+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
120+
noexcept(noexcept(/**/ views::all(std::forward<_Range>(__range))))
121+
-> decltype(/*--*/ views::all(std::forward<_Range>(__range))) {
122+
return /*-------------*/ views::all(std::forward<_Range>(__range));
123+
}
124+
};
125+
} // namespace __as_rvalue
126+
127+
inline namespace __cpo {
128+
constexpr auto as_rvalue = __as_rvalue::__fn{};
129+
} // namespace __cpo
130+
} // namespace views
131+
} // namespace ranges
132+
133+
_LIBCPP_END_NAMESPACE_STD
134+
135+
#endif // _LIBCPP_STD_VER >= 23
136+
137+
#endif // _LIBCPP___RANGES_AS_RVALUE_H

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,7 @@ module std [system] {
12211221
export functional.__functional.compose
12221222
export functional.__functional.perfect_forward
12231223
}
1224+
module as_rvalue_view { private header "__ranges/as_rvalue_view.h" }
12241225
module common_view { private header "__ranges/common_view.h" }
12251226
module concepts { private header "__ranges/concepts.h" }
12261227
module copyable_box { private header "__ranges/copyable_box.h" }

libcxx/include/ranges

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,13 @@ namespace std::ranges {
292292
(enable_borrowed_range<Views> && ...);
293293
294294
namespace views { inline constexpr unspecified zip = unspecified; } // C++2b
295+
296+
// [range.as.rvalue]
297+
template <view V>
298+
requires input_range<V>
299+
class as_rvalue_view; // since C++23
300+
301+
namespace views { inline constexpr unspecified as_rvalue ) unspecified; } // since C++23
295302
}
296303
297304
namespace std {
@@ -330,6 +337,7 @@ namespace std {
330337
#include <__config>
331338
#include <__ranges/access.h>
332339
#include <__ranges/all.h>
340+
#include <__ranges/as_rvalue_view.h>
333341
#include <__ranges/common_view.h>
334342
#include <__ranges/concepts.h>
335343
#include <__ranges/counted.h>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// Check that view adaptors are marked [[nodiscard]] as a conforming extension
10+
11+
// UNSUPPORTED: c++03, c++11, c++14 ,c++17, c++20
12+
13+
#include <ranges>
14+
#include <vector>
15+
16+
void func() {
17+
std::vector<int> range;
18+
19+
auto rvalue_view = std::views::as_rvalue(range);
20+
std::views::as_rvalue(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
21+
std::views::as_rvalue(rvalue_view); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
22+
}

libcxx/test/libcxx/private_headers.verify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ END-SCRIPT
530530
#include <__random/weibull_distribution.h> // expected-error@*:* {{use of private header from outside its module: '__random/weibull_distribution.h'}}
531531
#include <__ranges/access.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/access.h'}}
532532
#include <__ranges/all.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/all.h'}}
533+
#include <__ranges/as_rvalue_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/as_rvalue_view.h'}}
533534
#include <__ranges/common_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/common_view.h'}}
534535
#include <__ranges/concepts.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/concepts.h'}}
535536
#include <__ranges/copyable_box.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/copyable_box.h'}}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
11+
#include <iterator>
12+
#include <type_traits>
13+
14+
#include <test_iterators.h>
15+
16+
static_assert(std::is_same_v<decltype(std::move_sentinel(std::default_sentinel_t{})),
17+
std::move_sentinel<std::default_sentinel_t>>);
18+
19+
static_assert(
20+
std::is_same_v<decltype(std::move_sentinel(sentinel_wrapper<int*>{})), std::move_sentinel<sentinel_wrapper<int*>>>);
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10+
11+
// std::views::as_rvalue
12+
13+
#include <cassert>
14+
#include <functional>
15+
#include <ranges>
16+
#include <vector>
17+
18+
#include "test_iterators.h"
19+
20+
struct DefaultConstructibleView : std::ranges::view_base {
21+
int i_;
22+
int* begin();
23+
int* end();
24+
};
25+
26+
struct RValueView : std::ranges::view_base {};
27+
28+
template <class View, class T>
29+
concept HasPipe = requires(View&& view, T&& t) {
30+
{ std::forward<View>(view) | std::forward<T>(t) };
31+
};
32+
33+
struct NoView {};
34+
static_assert(std::is_invocable_v<decltype(std::views::as_rvalue), DefaultConstructibleView>);
35+
static_assert(!std::is_invocable_v<decltype(std::views::as_rvalue)>);
36+
static_assert(!std::is_invocable_v<decltype(std::views::as_rvalue), NoView>);
37+
static_assert(HasPipe<DefaultConstructibleView&, decltype(std::views::as_rvalue)>);
38+
static_assert(HasPipe<int (&)[10], decltype(std::views::as_rvalue)>);
39+
static_assert(!HasPipe<int (&&)[10], decltype(std::views::as_rvalue)>);
40+
static_assert(!HasPipe<NoView, decltype(std::views::as_rvalue)>);
41+
static_assert(std::is_same_v<decltype(std::views::as_rvalue), decltype(std::ranges::views::as_rvalue)>);
42+
43+
struct move_iterator_range {
44+
constexpr std::move_iterator<int*> begin() const { return {}; }
45+
constexpr std::move_iterator<int*> end() const { return {}; }
46+
};
47+
48+
static_assert(!std::ranges::view<move_iterator_range>);
49+
static_assert(std::ranges::range<move_iterator_range>);
50+
51+
constexpr bool test() {
52+
{ // view | views::as_rvalue
53+
DefaultConstructibleView v{{}, 3};
54+
std::same_as<std::ranges::as_rvalue_view<DefaultConstructibleView>> decltype(auto) view = v | std::views::as_rvalue;
55+
assert(view.base().i_ == 3);
56+
}
57+
58+
{ // adaptor | views::as_rvalue
59+
DefaultConstructibleView v{{}, 3};
60+
const auto partial = std::views::transform(std::identity{}) | std::views::as_rvalue;
61+
std::same_as<std::ranges::as_rvalue_view<
62+
std::ranges::transform_view<DefaultConstructibleView, std::identity>>> decltype(auto) view = partial(v);
63+
assert(view.base().base().i_ == 3);
64+
}
65+
66+
{ // views::as_rvalue | adaptor
67+
DefaultConstructibleView v{{}, 3};
68+
const auto partial = std::views::as_rvalue | std::views::transform(std::identity{});
69+
std::same_as<std::ranges::transform_view<std::ranges::as_rvalue_view<DefaultConstructibleView>,
70+
std::identity>> decltype(auto) view = partial(v);
71+
assert(view.base().base().i_ == 3);
72+
}
73+
74+
{ // rvalue-view | views::as_rvalue
75+
int a[4] = {1, 2, 3, 4};
76+
std::ranges::subrange range(rvalue_iterator{a}, rvalue_iterator{a + 4});
77+
[[maybe_unused]] std::same_as<std::ranges::subrange<rvalue_iterator<int>>> decltype(auto) rval_range =
78+
range | std::views::as_rvalue;
79+
}
80+
81+
{ // range | views::as_rvalue
82+
[[maybe_unused]] std::same_as<std::ranges::as_rvalue_view<std::views::all_t<std::vector<int>>>> decltype(auto)
83+
view = std::vector<int>{} | std::views::as_rvalue;
84+
}
85+
86+
{ // rvalue-range | views::as_rvalue
87+
[[maybe_unused]] std::same_as<std::views::all_t<move_iterator_range>> decltype(auto) view =
88+
move_iterator_range{} | std::views::as_rvalue;
89+
}
90+
91+
return true;
92+
}
93+
94+
int main(int, char**) {
95+
test();
96+
static_assert(test());
97+
98+
return 0;
99+
}

0 commit comments

Comments
 (0)