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 | // std::views::all; |
12 | |
13 | #include <ranges> |
14 | |
15 | #include <cassert> |
16 | #include <concepts> |
17 | #include <type_traits> |
18 | #include <utility> |
19 | |
20 | #include "test_iterators.h" |
21 | #include "test_macros.h" |
22 | #include "test_range.h" |
23 | |
24 | int globalBuff[8]; |
25 | |
26 | template<bool IsNoexcept> |
27 | struct View : std::ranges::view_base { |
28 | int start_ = 0; |
29 | explicit View() noexcept(IsNoexcept) = default; |
30 | constexpr explicit View(int start) : start_(start) {} |
31 | View(View&&) noexcept(IsNoexcept) = default; |
32 | View& operator=(View&&) noexcept(IsNoexcept) = default; |
33 | constexpr int* begin() const { return globalBuff + start_; } |
34 | constexpr int* end() const { return globalBuff + 8; } |
35 | }; |
36 | static_assert(std::ranges::view<View<true>>); |
37 | static_assert(std::ranges::view<View<false>>); |
38 | |
39 | template<bool IsNoexcept> |
40 | struct CopyableView : std::ranges::view_base { |
41 | int start_ = 0; |
42 | explicit CopyableView() noexcept(IsNoexcept) = default; |
43 | CopyableView(CopyableView const&) noexcept(IsNoexcept) = default; |
44 | CopyableView& operator=(CopyableView const&) noexcept(IsNoexcept) = default; |
45 | constexpr explicit CopyableView(int start) noexcept : start_(start) {} |
46 | constexpr int* begin() const { return globalBuff + start_; } |
47 | constexpr int* end() const { return globalBuff + 8; } |
48 | }; |
49 | static_assert(std::ranges::view<CopyableView<true>>); |
50 | static_assert(std::ranges::view<CopyableView<false>>); |
51 | |
52 | struct MoveOnlyView : std::ranges::view_base{ |
53 | MoveOnlyView() = default; |
54 | MoveOnlyView(const MoveOnlyView&) = delete; |
55 | MoveOnlyView& operator=(const MoveOnlyView&) = delete; |
56 | MoveOnlyView(MoveOnlyView&&) = default; |
57 | MoveOnlyView& operator=(MoveOnlyView&&) = default; |
58 | |
59 | int* begin() const; |
60 | int* end() const; |
61 | }; |
62 | |
63 | struct Range { |
64 | int start_; |
65 | constexpr explicit Range(int start) noexcept : start_(start) {} |
66 | constexpr int* begin() const { return globalBuff + start_; } |
67 | constexpr int* end() const { return globalBuff + 8; } |
68 | }; |
69 | |
70 | struct BorrowableRange { |
71 | int start_; |
72 | constexpr explicit BorrowableRange(int start) noexcept : start_(start) {} |
73 | constexpr int* begin() const { return globalBuff + start_; } |
74 | constexpr int* end() const { return globalBuff + 8; } |
75 | }; |
76 | template<> |
77 | inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true; |
78 | |
79 | struct RandomAccessRange { |
80 | constexpr auto begin() { return random_access_iterator<int*>(globalBuff); } |
81 | constexpr auto end() { return sized_sentinel(random_access_iterator<int*>(globalBuff + 8)); } |
82 | }; |
83 | template<> |
84 | inline constexpr bool std::ranges::enable_borrowed_range<RandomAccessRange> = true; |
85 | |
86 | constexpr bool test() { |
87 | { |
88 | ASSERT_SAME_TYPE(decltype(std::views::all(View<true>())), View<true>); |
89 | static_assert(noexcept(std::views::all(View<true>()))); |
90 | static_assert(!noexcept(std::views::all(View<false>()))); |
91 | |
92 | auto viewCopy = std::views::all(View<true>(2)); |
93 | ASSERT_SAME_TYPE(decltype(viewCopy), View<true>); |
94 | assert(std::ranges::begin(viewCopy) == globalBuff + 2); |
95 | assert(std::ranges::end(viewCopy) == globalBuff + 8); |
96 | } |
97 | |
98 | { |
99 | ASSERT_SAME_TYPE(decltype(std::views::all(std::declval<const CopyableView<true>&>())), CopyableView<true>); |
100 | static_assert(noexcept(std::views::all(CopyableView<true>()))); |
101 | static_assert(!noexcept(std::views::all(CopyableView<false>()))); |
102 | |
103 | CopyableView<true> view(2); |
104 | auto viewCopy = std::views::all(view); |
105 | ASSERT_SAME_TYPE(decltype(viewCopy), CopyableView<true>); |
106 | assert(std::ranges::begin(viewCopy) == globalBuff + 2); |
107 | assert(std::ranges::end(viewCopy) == globalBuff + 8); |
108 | } |
109 | |
110 | { |
111 | Range range(2); |
112 | auto ref = std::views::all(range); |
113 | ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<Range>); |
114 | assert(std::ranges::begin(ref) == globalBuff + 2); |
115 | assert(std::ranges::end(ref) == globalBuff + 8); |
116 | |
117 | auto own = std::views::all(std::move(range)); |
118 | ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<Range>); |
119 | assert(std::ranges::begin(own) == globalBuff + 2); |
120 | assert(std::ranges::end(own) == globalBuff + 8); |
121 | |
122 | auto cref = std::views::all(std::as_const(range)); |
123 | ASSERT_SAME_TYPE(decltype(cref), std::ranges::ref_view<const Range>); |
124 | assert(std::ranges::begin(cref) == globalBuff + 2); |
125 | assert(std::ranges::end(cref) == globalBuff + 8); |
126 | |
127 | static_assert(!std::is_invocable_v<decltype(std::views::all), const Range&&>); |
128 | } |
129 | |
130 | { |
131 | auto own = std::views::all(BorrowableRange(2)); |
132 | ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<BorrowableRange>); |
133 | assert(std::ranges::begin(own) == globalBuff + 2); |
134 | assert(std::ranges::end(own) == globalBuff + 8); |
135 | } |
136 | |
137 | { |
138 | auto own = std::views::all(RandomAccessRange()); |
139 | ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<RandomAccessRange>); |
140 | assert(base(std::ranges::begin(own)) == globalBuff); |
141 | assert(base(base(std::ranges::end(own))) == globalBuff + 8); |
142 | } |
143 | |
144 | // Check SFINAE friendliness of the call operator |
145 | { |
146 | static_assert(!std::is_invocable_v<decltype(std::views::all)>); |
147 | static_assert(!std::is_invocable_v<decltype(std::views::all), RandomAccessRange, RandomAccessRange>); |
148 | |
149 | // `views::all(v)` is expression equivalent to `decay-copy(v)` if the decayed type |
150 | // of `v` models `view`. If `v` is an lvalue-reference to a move-only view, the |
151 | // expression should be ill-formed because `v` is not copyable |
152 | static_assert(!std::is_invocable_v<decltype(std::views::all), MoveOnlyView&>); |
153 | } |
154 | |
155 | // Test that std::views::all is a range adaptor |
156 | { |
157 | // Test `v | views::all` |
158 | { |
159 | Range range(0); |
160 | auto result = range | std::views::all; |
161 | ASSERT_SAME_TYPE(decltype(result), std::ranges::ref_view<Range>); |
162 | assert(&result.base() == &range); |
163 | } |
164 | |
165 | // Test `adaptor | views::all` |
166 | { |
167 | Range range(0); |
168 | auto f = [](int i) { return i; }; |
169 | auto const partial = std::views::transform(f) | std::views::all; |
170 | using Result = std::ranges::transform_view<std::ranges::ref_view<Range>, decltype(f)>; |
171 | std::same_as<Result> auto result = partial(range); |
172 | assert(&result.base().base() == &range); |
173 | } |
174 | |
175 | // Test `views::all | adaptor` |
176 | { |
177 | Range range(0); |
178 | auto f = [](int i) { return i; }; |
179 | auto const partial = std::views::all | std::views::transform(f); |
180 | using Result = std::ranges::transform_view<std::ranges::ref_view<Range>, decltype(f)>; |
181 | std::same_as<Result> auto result = partial(range); |
182 | assert(&result.base().base() == &range); |
183 | } |
184 | |
185 | { |
186 | struct NotAView { }; |
187 | static_assert( CanBePiped<Range&, decltype(std::views::all)>); |
188 | static_assert(!CanBePiped<NotAView, decltype(std::views::all)>); |
189 | } |
190 | } |
191 | |
192 | { |
193 | static_assert(std::same_as<decltype(std::views::all), decltype(std::ranges::views::all)>); |
194 | } |
195 | |
196 | return true; |
197 | } |
198 | |
199 | int main(int, char**) { |
200 | test(); |
201 | static_assert(test()); |
202 | |
203 | return 0; |
204 | } |
205 | |