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
24template <class T>
25concept 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
48struct ConstNotRange : std::ranges::view_base {
49 const ChildView* begin();
50 const ChildView* end();
51};
52
53constexpr 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
298int main(int, char**) {
299 test();
300 static_assert(test());
301
302 return 0;
303}
304

source code of libcxx/test/std/ranges/range.adaptors/range.join/end.pass.cpp