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 | // constexpr auto end(); |
12 | // constexpr auto end() const; |
13 | // requires forward_range<const V> && |
14 | // is_reference_v<range_reference_t<const V>> && |
15 | // input_range<range_reference_t<const V>> |
16 | |
17 | #include <cassert> |
18 | #include <ranges> |
19 | #include <type_traits> |
20 | |
21 | #include "test_macros.h" |
22 | #include "types.h" |
23 | |
24 | template <class T> |
25 | concept HasConstEnd = requires (const T& t){ |
26 | t.end(); |
27 | }; |
28 | |
29 | |
30 | // | ID | outer | outer | outer | inner | inner | inner | end() | end() | |
31 | // | | simple | forward | common | l_ref | forward | common | | const | |
32 | // |----|--------|---------|--------|-------|---------|--------|---------------|--------------| |
33 | // | 1 | Y | Y | Y | Y | Y | Y |iterator<true> |iterator<true>| |
34 | // | 2 | Y | Y | Y | Y | Y | N |sentinel<true> |sentinel<true>| |
35 | // | 3 | Y | Y | Y | Y | N | Y |sentinel<true> |sentinel<true>| |
36 | // | 4 | Y | Y | Y | N | Y | Y |sentinel<true> | - | |
37 | // | 5 | Y | Y | N | Y | Y | Y |sentinel<true> |sentinel<true>| |
38 | // | 6 | Y | N | Y | Y | Y | Y |sentinel<true> | - | |
39 | // | 7 | N | Y | Y | Y | Y | Y |iterator<false>|iterator<true>| |
40 | // | 8 | N | Y | Y | Y | Y | N |sentinel<false>|sentinel<true>| |
41 | // | 9 | N | Y | Y | Y | N | Y |sentinel<false>|sentinel<true>| |
42 | // | 10 | N | Y | Y | N | Y | Y |sentinel<false>| - | |
43 | // | 11 | N | Y | N | Y | Y | Y |sentinel<false>|sentinel<true>| |
44 | // | 12 | N | N | Y | Y | Y | Y |sentinel<false>| - | |
45 | // |
46 | // |
47 | |
48 | struct ConstNotRange : std::ranges::view_base { |
49 | const ChildView* begin(); |
50 | const ChildView* end(); |
51 | }; |
52 | |
53 | constexpr bool test() { |
54 | int buffer[4][4] = {{1111, 2222, 3333, 4444}, {555, 666, 777, 888}, {99, 1010, 1111, 1212}, {13, 14, 15, 16}}; |
55 | |
56 | { |
57 | // test ID 1 |
58 | ForwardCommonInner inners[4] = {buffer[0], buffer[1], buffer[2], buffer[3]}; |
59 | SimpleForwardCommonOuter<ForwardCommonInner> outer{inners}; |
60 | |
61 | std::ranges::join_view jv(outer); |
62 | assert(jv.end() == std::ranges::next(jv.begin(), 16)); |
63 | assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 16)); |
64 | |
65 | static_assert(HasConstEnd<decltype(jv)>); |
66 | static_assert(std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); |
67 | static_assert(std::ranges::common_range<decltype(jv)>); |
68 | static_assert(std::ranges::common_range<const decltype(jv)>); |
69 | } |
70 | |
71 | { |
72 | // test ID 2 |
73 | ForwardNonCommonInner inners[3] = {buffer[0], buffer[1], buffer[2]}; |
74 | SimpleForwardCommonOuter<ForwardNonCommonInner> outer{inners}; |
75 | |
76 | std::ranges::join_view jv(outer); |
77 | assert(jv.end() == std::ranges::next(jv.begin(), 12)); |
78 | assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 12)); |
79 | |
80 | static_assert(HasConstEnd<decltype(jv)>); |
81 | static_assert(std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); |
82 | static_assert(!std::ranges::common_range<decltype(jv)>); |
83 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
84 | } |
85 | |
86 | { |
87 | // test ID 3 |
88 | InputCommonInner inners[3] = {buffer[0], buffer[1], buffer[2]}; |
89 | SimpleForwardCommonOuter<InputCommonInner> outer{inners}; |
90 | |
91 | std::ranges::join_view jv(outer); |
92 | assert(jv.end() == std::ranges::next(jv.begin(), 12)); |
93 | assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 12)); |
94 | |
95 | static_assert(HasConstEnd<decltype(jv)>); |
96 | static_assert(std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); |
97 | static_assert(!std::ranges::common_range<decltype(jv)>); |
98 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
99 | } |
100 | |
101 | { |
102 | // test ID 4 |
103 | ForwardCommonInner inners[2] = {buffer[0], buffer[1]}; |
104 | InnerRValue<SimpleForwardCommonOuter<ForwardCommonInner>> outer{inners}; |
105 | |
106 | std::ranges::join_view jv(outer); |
107 | assert(jv.end() == std::ranges::next(jv.begin(), 8)); |
108 | |
109 | static_assert(!HasConstEnd<decltype(jv)>); |
110 | static_assert(!std::ranges::common_range<decltype(jv)>); |
111 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
112 | } |
113 | |
114 | { |
115 | // test ID 5 |
116 | ForwardCommonInner inners[4] = {buffer[0], buffer[1], buffer[2], buffer[3]}; |
117 | SimpleForwardNonCommonOuter<ForwardCommonInner> outer{inners}; |
118 | |
119 | std::ranges::join_view jv(outer); |
120 | assert(jv.end() == std::ranges::next(jv.begin(), 16)); |
121 | assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 16)); |
122 | |
123 | static_assert(HasConstEnd<decltype(jv)>); |
124 | static_assert(std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); |
125 | static_assert(!std::ranges::common_range<decltype(jv)>); |
126 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
127 | } |
128 | |
129 | { |
130 | // test ID 6 |
131 | ForwardCommonInner inners[4] = {buffer[0], buffer[1], buffer[2], buffer[3]}; |
132 | SimpleInputCommonOuter<ForwardCommonInner> outer{inners}; |
133 | |
134 | std::ranges::join_view jv(outer); |
135 | assert(jv.end() == std::ranges::next(jv.begin(), 16)); |
136 | |
137 | static_assert(!HasConstEnd<decltype(jv)>); |
138 | static_assert(!std::ranges::common_range<decltype(jv)>); |
139 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
140 | } |
141 | |
142 | { |
143 | // test ID 7 |
144 | ForwardCommonInner inners[1] = {buffer[0]}; |
145 | NonSimpleForwardCommonOuter<ForwardCommonInner> outer{inners}; |
146 | |
147 | std::ranges::join_view jv(outer); |
148 | assert(jv.end() == std::ranges::next(jv.begin(), 4)); |
149 | assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 4)); |
150 | |
151 | static_assert(HasConstEnd<decltype(jv)>); |
152 | static_assert(!std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); |
153 | static_assert(std::ranges::common_range<decltype(jv)>); |
154 | static_assert(std::ranges::common_range<const decltype(jv)>); |
155 | } |
156 | |
157 | { |
158 | // test ID 8 |
159 | ForwardNonCommonInner inners[3] = {buffer[0], buffer[1], buffer[2]}; |
160 | NonSimpleForwardCommonOuter<ForwardNonCommonInner> outer{inners}; |
161 | |
162 | std::ranges::join_view jv(outer); |
163 | assert(jv.end() == std::ranges::next(jv.begin(), 12)); |
164 | assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 12)); |
165 | |
166 | static_assert(HasConstEnd<decltype(jv)>); |
167 | static_assert(!std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); |
168 | static_assert(!std::ranges::common_range<decltype(jv)>); |
169 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
170 | } |
171 | |
172 | { |
173 | // test ID 9 |
174 | InputCommonInner inners[3] = {buffer[0], buffer[1], buffer[2]}; |
175 | NonSimpleForwardCommonOuter<InputCommonInner> outer{inners}; |
176 | |
177 | std::ranges::join_view jv(outer); |
178 | assert(jv.end() == std::ranges::next(jv.begin(), 12)); |
179 | assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 12)); |
180 | |
181 | static_assert(HasConstEnd<decltype(jv)>); |
182 | static_assert(!std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); |
183 | static_assert(!std::ranges::common_range<decltype(jv)>); |
184 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
185 | } |
186 | |
187 | { |
188 | // test ID 10 |
189 | ForwardCommonInner inners[2] = {buffer[0], buffer[1]}; |
190 | InnerRValue<NonSimpleForwardCommonOuter<ForwardCommonInner>> outer{inners}; |
191 | |
192 | std::ranges::join_view jv(outer); |
193 | assert(jv.end() == std::ranges::next(jv.begin(), 8)); |
194 | |
195 | static_assert(!HasConstEnd<decltype(jv)>); |
196 | static_assert(!std::ranges::common_range<decltype(jv)>); |
197 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
198 | } |
199 | |
200 | { |
201 | // test ID 11 |
202 | ForwardCommonInner inners[4] = {buffer[0], buffer[1], buffer[2], buffer[3]}; |
203 | NonSimpleForwardNonCommonOuter<ForwardCommonInner> outer{inners}; |
204 | |
205 | std::ranges::join_view jv(outer); |
206 | assert(jv.end() == std::ranges::next(jv.begin(), 16)); |
207 | assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 16)); |
208 | |
209 | static_assert(HasConstEnd<decltype(jv)>); |
210 | static_assert(!std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); |
211 | static_assert(!std::ranges::common_range<decltype(jv)>); |
212 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
213 | } |
214 | |
215 | { |
216 | // test ID 12 |
217 | ForwardCommonInner inners[4] = {buffer[0], buffer[1], buffer[2], buffer[3]}; |
218 | NonSimpleInputCommonOuter<ForwardCommonInner> outer{inners}; |
219 | |
220 | std::ranges::join_view jv(outer); |
221 | assert(jv.end() == std::ranges::next(jv.begin(), 16)); |
222 | |
223 | static_assert(!HasConstEnd<decltype(jv)>); |
224 | static_assert(!std::ranges::common_range<decltype(jv)>); |
225 | static_assert(!std::ranges::common_range<const decltype(jv)>); |
226 | } |
227 | |
228 | { |
229 | std::ranges::join_view jv(ConstNotRange{}); |
230 | static_assert(!HasConstEnd<decltype(jv)>); |
231 | } |
232 | |
233 | // Has some empty children. |
234 | { |
235 | CopyableChild children[4] = {CopyableChild(buffer[0], 4), CopyableChild(buffer[1], 0), CopyableChild(buffer[2], 1), CopyableChild(buffer[3], 0)}; |
236 | auto jv = std::ranges::join_view(ParentView(children)); |
237 | assert(jv.end() == std::ranges::next(jv.begin(), 5)); |
238 | } |
239 | |
240 | // Parent is empty. |
241 | { |
242 | CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]), CopyableChild(buffer[3])}; |
243 | std::ranges::join_view jv(ParentView(children, 0)); |
244 | assert(jv.end() == jv.begin()); |
245 | } |
246 | |
247 | // Parent size is one. |
248 | { |
249 | CopyableChild children[1] = {CopyableChild(buffer[0])}; |
250 | std::ranges::join_view jv(ParentView(children, 1)); |
251 | assert(jv.end() == std::ranges::next(jv.begin(), 4)); |
252 | } |
253 | |
254 | // Parent and child size is one. |
255 | { |
256 | CopyableChild children[1] = {CopyableChild(buffer[0], 1)}; |
257 | std::ranges::join_view jv(ParentView(children, 1)); |
258 | assert(jv.end() == std::ranges::next(jv.begin())); |
259 | } |
260 | |
261 | // Parent size is one child is empty |
262 | { |
263 | CopyableChild children[1] = {CopyableChild(buffer[0], 0)}; |
264 | std::ranges::join_view jv(ParentView(children, 1)); |
265 | assert(jv.end() == jv.begin()); |
266 | } |
267 | |
268 | // Has all empty children. |
269 | { |
270 | CopyableChild children[4] = {CopyableChild(buffer[0], 0), CopyableChild(buffer[1], 0), CopyableChild(buffer[2], 0), CopyableChild(buffer[3], 0)}; |
271 | auto jv = std::ranges::join_view(ParentView(children)); |
272 | assert(jv.end() == jv.begin()); |
273 | } |
274 | |
275 | // First child is empty, others are not. |
276 | { |
277 | CopyableChild children[4] = {CopyableChild(buffer[0], 4), CopyableChild(buffer[1], 0), CopyableChild(buffer[2], 0), CopyableChild(buffer[3], 0)}; |
278 | auto jv = std::ranges::join_view(ParentView(children)); |
279 | assert(jv.end() == std::ranges::next(jv.begin(), 4)); |
280 | } |
281 | |
282 | // Last child is empty, others are not. |
283 | { |
284 | CopyableChild children[4] = {CopyableChild(buffer[0], 4), CopyableChild(buffer[1], 4), CopyableChild(buffer[2], 4), CopyableChild(buffer[3], 0)}; |
285 | auto jv = std::ranges::join_view(ParentView(children)); |
286 | assert(jv.end() == std::ranges::next(jv.begin(), 12)); |
287 | } |
288 | |
289 | // LWG3700: The `const begin` of the `join_view` family does not require `InnerRng` to be a range |
290 | { |
291 | std::ranges::join_view<ConstNonJoinableRange> jv; |
292 | static_assert(!HasConstEnd<decltype(jv)>); |
293 | } |
294 | |
295 | return true; |
296 | } |
297 | |
298 | int main(int, char**) { |
299 | test(); |
300 | static_assert(test()); |
301 | |
302 | return 0; |
303 | } |
304 | |