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