xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.join/end.pass.cpp (revision 6a664674990094c1b5d2e717256f08cb04485899)
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 
test()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 
main(int,char **)298 int main(int, char**) {
299   test();
300   static_assert(test());
301 
302   return 0;
303 }
304