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