xref: /llvm-project/libcxx/test/std/ranges/range.access/end.pass.cpp (revision 53406fb691db38b21decf233e091f648f8317b2d)
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 // UNSUPPORTED: libcpp-no-concepts
11 
12 // std::ranges::end
13 // std::ranges::cend
14 
15 #include <ranges>
16 
17 #include <cassert>
18 #include <utility>
19 #include "test_macros.h"
20 #include "test_iterators.h"
21 
22 using RangeEndT = decltype(std::ranges::end);
23 using RangeCEndT = decltype(std::ranges::cend);
24 
25 static int globalBuff[8];
26 
27 static_assert(!std::is_invocable_v<RangeEndT, int (&&)[]>);
28 static_assert(!std::is_invocable_v<RangeEndT, int (&)[]>);
29 static_assert(!std::is_invocable_v<RangeEndT, int (&&)[10]>);
30 static_assert( std::is_invocable_v<RangeEndT, int (&)[10]>);
31 static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[]>);
32 static_assert(!std::is_invocable_v<RangeCEndT, int (&)[]>);
33 static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[10]>);
34 static_assert( std::is_invocable_v<RangeCEndT, int (&)[10]>);
35 
36 struct Incomplete;
37 static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[]>);
38 static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[42]>);
39 static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>);
40 static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[42]>);
41 
42 struct EndMember {
43   int x;
44   const int *begin() const;
45   constexpr const int *end() const { return &x; }
46 };
47 
48 // Ensure that we can't call with rvalues with borrowing disabled.
49 static_assert( std::is_invocable_v<RangeEndT, EndMember &>);
50 static_assert(!std::is_invocable_v<RangeEndT, EndMember &&>);
51 static_assert( std::is_invocable_v<RangeEndT, EndMember const&>);
52 static_assert(!std::is_invocable_v<RangeEndT, EndMember const&&>);
53 static_assert( std::is_invocable_v<RangeCEndT, EndMember &>);
54 static_assert(!std::is_invocable_v<RangeCEndT, EndMember &&>);
55 static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>);
56 static_assert(!std::is_invocable_v<RangeCEndT, EndMember const&&>);
57 
58 constexpr bool testReturnTypes() {
59   {
60     int *x[2];
61     ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int**);
62     ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), int* const*);
63   }
64   {
65     int x[2][2];
66     ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int(*)[2]);
67     ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), const int(*)[2]);
68   }
69   {
70     struct Different {
71       char *begin();
72       sentinel_wrapper<char*>& end();
73       short *begin() const;
74       sentinel_wrapper<short*>& end() const;
75     } x;
76     ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), sentinel_wrapper<char*>);
77     ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), sentinel_wrapper<short*>);
78   }
79   return true;
80 }
81 
82 constexpr bool testArray() {
83   int a[2];
84   assert(std::ranges::end(a) == a + 2);
85   assert(std::ranges::cend(a) == a + 2);
86 
87   int b[2][2];
88   assert(std::ranges::end(b) == b + 2);
89   assert(std::ranges::cend(b) == b + 2);
90 
91   EndMember c[2];
92   assert(std::ranges::end(c) == c + 2);
93   assert(std::ranges::cend(c) == c + 2);
94 
95   return true;
96 }
97 
98 struct EndMemberReturnsInt {
99   int begin() const;
100   int end() const;
101 };
102 static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsInt const&>);
103 
104 struct EndMemberReturnsVoidPtr {
105   const void *begin() const;
106   const void *end() const;
107 };
108 static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsVoidPtr const&>);
109 
110 struct PtrConvertible {
111   operator int*() const;
112 };
113 struct PtrConvertibleEndMember {
114   PtrConvertible begin() const;
115   PtrConvertible end() const;
116 };
117 static_assert(!std::is_invocable_v<RangeEndT, PtrConvertibleEndMember const&>);
118 
119 struct NoBeginMember {
120   constexpr const int *end();
121 };
122 static_assert(!std::is_invocable_v<RangeEndT, NoBeginMember const&>);
123 
124 struct NonConstEndMember {
125   int x;
126   constexpr int *begin() { return nullptr; }
127   constexpr int *end() { return &x; }
128 };
129 static_assert( std::is_invocable_v<RangeEndT,  NonConstEndMember &>);
130 static_assert(!std::is_invocable_v<RangeEndT,  NonConstEndMember const&>);
131 static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>);
132 static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>);
133 
134 struct EnabledBorrowingEndMember {
135   constexpr int *begin() const { return nullptr; }
136   constexpr int *end() const { return &globalBuff[0]; }
137 };
138 
139 template<>
140 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingEndMember> = true;
141 
142 struct EndMemberFunction {
143   int x;
144   constexpr const int *begin() const { return nullptr; }
145   constexpr const int *end() const { return &x; }
146   friend constexpr int *end(EndMemberFunction const&);
147 };
148 
149 struct Empty { };
150 struct EmptyEndMember {
151   Empty begin() const;
152   Empty end() const;
153 };
154 static_assert(!std::is_invocable_v<RangeEndT, EmptyEndMember const&>);
155 
156 struct EmptyPtrEndMember {
157   Empty x;
158   constexpr const Empty *begin() const { return nullptr; }
159   constexpr const Empty *end() const { return &x; }
160 };
161 
162 constexpr bool testEndMember() {
163   EndMember a;
164   assert(std::ranges::end(a) == &a.x);
165   assert(std::ranges::cend(a) == &a.x);
166 
167   NonConstEndMember b;
168   assert(std::ranges::end(b) == &b.x);
169   static_assert(!std::is_invocable_v<RangeCEndT, decltype((b))>);
170 
171   EnabledBorrowingEndMember c;
172   assert(std::ranges::end(std::move(c)) == &globalBuff[0]);
173   assert(std::ranges::cend(std::move(c)) == &globalBuff[0]);
174 
175   EndMemberFunction d;
176   assert(std::ranges::end(d) == &d.x);
177   assert(std::ranges::cend(d) == &d.x);
178 
179   EmptyPtrEndMember e;
180   assert(std::ranges::end(e) == &e.x);
181   assert(std::ranges::cend(e) == &e.x);
182 
183   return true;
184 }
185 
186 struct EndFunction {
187   int x;
188   friend constexpr const int *begin(EndFunction const&) { return nullptr; }
189   friend constexpr const int *end(EndFunction const& bf) { return &bf.x; }
190 };
191 
192 static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);
193 static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
194 
195 static_assert( std::is_invocable_v<RangeEndT,  EndFunction const&>);
196 static_assert(!std::is_invocable_v<RangeEndT,  EndFunction &&>);
197 static_assert(!std::is_invocable_v<RangeEndT,  EndFunction &>);
198 static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
199 static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
200 
201 struct EndFunctionReturnsInt {
202   friend constexpr int begin(EndFunctionReturnsInt const&);
203   friend constexpr int end(EndFunctionReturnsInt const&);
204 };
205 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsInt const&>);
206 
207 struct EndFunctionReturnsVoidPtr {
208   friend constexpr void *begin(EndFunctionReturnsVoidPtr const&);
209   friend constexpr void *end(EndFunctionReturnsVoidPtr const&);
210 };
211 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsVoidPtr const&>);
212 
213 struct EndFunctionReturnsEmpty {
214   friend constexpr Empty begin(EndFunctionReturnsEmpty const&);
215   friend constexpr Empty end(EndFunctionReturnsEmpty const&);
216 };
217 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsEmpty const&>);
218 
219 struct EndFunctionReturnsPtrConvertible {
220   friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&);
221   friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&);
222 };
223 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsPtrConvertible const&>);
224 
225 struct NoBeginFunction {
226   friend constexpr const int *end(NoBeginFunction const&);
227 };
228 static_assert(!std::is_invocable_v<RangeEndT, NoBeginFunction const&>);
229 
230 struct EndFunctionByValue {
231   friend constexpr int *begin(EndFunctionByValue) { return nullptr; }
232   friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; }
233 };
234 static_assert(!std::is_invocable_v<RangeCEndT, EndFunctionByValue>);
235 
236 struct EndFunctionEnabledBorrowing {
237   friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; }
238   friend constexpr int *end(EndFunctionEnabledBorrowing) { return &globalBuff[2]; }
239 };
240 template<>
241 inline constexpr bool std::ranges::enable_borrowed_range<EndFunctionEnabledBorrowing> = true;
242 
243 struct EndFunctionReturnsEmptyPtr {
244   Empty x;
245   friend constexpr const Empty *begin(EndFunctionReturnsEmptyPtr const&) { return nullptr; }
246   friend constexpr const Empty *end(EndFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
247 };
248 
249 struct EndFunctionWithDataMember {
250   int x;
251   int end;
252   friend constexpr const int *begin(EndFunctionWithDataMember const&) { return nullptr; }
253   friend constexpr const int *end(EndFunctionWithDataMember const& bf) { return &bf.x; }
254 };
255 
256 struct EndFunctionWithPrivateEndMember {
257   int y;
258   friend constexpr const int *begin(EndFunctionWithPrivateEndMember const&) { return nullptr; }
259   friend constexpr const int *end(EndFunctionWithPrivateEndMember const& bf) { return &bf.y; }
260 private:
261   const int *end() const;
262 };
263 
264 struct BeginMemberEndFunction {
265   int x;
266   constexpr const int *begin() const { return nullptr; }
267   friend constexpr const int *end(BeginMemberEndFunction const& bf) { return &bf.x; }
268 };
269 
270 constexpr bool testEndFunction() {
271   const EndFunction a{};
272   assert(std::ranges::end(a) == &a.x);
273   assert(std::ranges::cend(a) == &a.x);
274   EndFunction aa{};
275   static_assert(!std::is_invocable_v<RangeEndT, decltype((aa))>);
276   assert(std::ranges::cend(aa) == &aa.x);
277 
278   EndFunctionByValue b;
279   assert(std::ranges::end(b) == &globalBuff[1]);
280   assert(std::ranges::cend(b) == &globalBuff[1]);
281 
282   EndFunctionEnabledBorrowing c;
283   assert(std::ranges::end(std::move(c)) == &globalBuff[2]);
284   assert(std::ranges::cend(std::move(c)) == &globalBuff[2]);
285 
286   const EndFunctionReturnsEmptyPtr d{};
287   assert(std::ranges::end(d) == &d.x);
288   assert(std::ranges::cend(d) == &d.x);
289   EndFunctionReturnsEmptyPtr dd{};
290   static_assert(!std::is_invocable_v<RangeEndT, decltype((dd))>);
291   assert(std::ranges::cend(dd) == &dd.x);
292 
293   const EndFunctionWithDataMember e{};
294   assert(std::ranges::end(e) == &e.x);
295   assert(std::ranges::cend(e) == &e.x);
296   EndFunctionWithDataMember ee{};
297   static_assert(!std::is_invocable_v<RangeEndT, decltype((ee))>);
298   assert(std::ranges::cend(ee) == &ee.x);
299 
300   const EndFunctionWithPrivateEndMember f{};
301   assert(std::ranges::end(f) == &f.y);
302   assert(std::ranges::cend(f) == &f.y);
303   EndFunctionWithPrivateEndMember ff{};
304   static_assert(!std::is_invocable_v<RangeEndT, decltype((ff))>);
305   assert(std::ranges::cend(ff) == &ff.y);
306 
307   const BeginMemberEndFunction g{};
308   assert(std::ranges::end(g) == &g.x);
309   assert(std::ranges::cend(g) == &g.x);
310   BeginMemberEndFunction gg{};
311   static_assert(!std::is_invocable_v<RangeEndT, decltype((gg))>);
312   assert(std::ranges::cend(gg) == &gg.x);
313 
314   return true;
315 }
316 
317 
318 ASSERT_NOEXCEPT(std::ranges::end(std::declval<int (&)[10]>()));
319 ASSERT_NOEXCEPT(std::ranges::cend(std::declval<int (&)[10]>()));
320 
321 struct NoThrowMemberEnd {
322   ThrowingIterator<int> begin() const;
323   ThrowingIterator<int> end() const noexcept; // auto(t.end()) doesn't throw
324 } ntme;
325 static_assert(noexcept(std::ranges::end(ntme)));
326 static_assert(noexcept(std::ranges::cend(ntme)));
327 
328 struct NoThrowADLEnd {
329   ThrowingIterator<int> begin() const;
330   friend ThrowingIterator<int> end(NoThrowADLEnd&) noexcept;  // auto(end(t)) doesn't throw
331   friend ThrowingIterator<int> end(const NoThrowADLEnd&) noexcept;
332 } ntae;
333 static_assert(noexcept(std::ranges::end(ntae)));
334 static_assert(noexcept(std::ranges::cend(ntae)));
335 
336 struct NoThrowMemberEndReturnsRef {
337   ThrowingIterator<int> begin() const;
338   ThrowingIterator<int>& end() const noexcept; // auto(t.end()) may throw
339 } ntmerr;
340 static_assert(!noexcept(std::ranges::end(ntmerr)));
341 static_assert(!noexcept(std::ranges::cend(ntmerr)));
342 
343 struct EndReturnsArrayRef {
344     auto begin() const noexcept -> int(&)[10];
345     auto end() const noexcept -> int(&)[10];
346 } erar;
347 static_assert(noexcept(std::ranges::end(erar)));
348 static_assert(noexcept(std::ranges::cend(erar)));
349 
350 // Test ADL-proofing.
351 struct Incomplete;
352 template<class T> struct Holder { T t; };
353 static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*>);
354 static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*&>);
355 static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);
356 static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>);
357 
358 int main(int, char**) {
359   static_assert(testReturnTypes());
360 
361   testArray();
362   static_assert(testArray());
363 
364   testEndMember();
365   static_assert(testEndMember());
366 
367   testEndFunction();
368   static_assert(testEndFunction());
369 
370   return 0;
371 }
372