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

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