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::begin
12// std::ranges::cbegin
13
14#include <ranges>
15
16#include <cassert>
17#include <utility>
18#include "test_macros.h"
19#include "test_iterators.h"
20
21using RangeBeginT = decltype(std::ranges::begin);
22using RangeCBeginT = decltype(std::ranges::cbegin);
23
24static int globalBuff[8];
25
26static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[10]>);
27static_assert( std::is_invocable_v<RangeBeginT, int (&)[10]>);
28static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[]>);
29static_assert( std::is_invocable_v<RangeBeginT, int (&)[]>);
30static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[10]>);
31static_assert( std::is_invocable_v<RangeCBeginT, int (&)[10]>);
32static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[]>);
33static_assert( std::is_invocable_v<RangeCBeginT, int (&)[]>);
34
35struct Incomplete;
36static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[]>);
37static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[]>);
38static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>);
39static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[]>);
40
41static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[10]>);
42static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[10]>);
43static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[10]>);
44static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[10]>);
45
46// This case is IFNDR; we handle it SFINAE-friendly.
47LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[]>);
48LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[]>);
49LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[]>);
50LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[]>);
51
52// This case is IFNDR; we handle it SFINAE-friendly.
53LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[10]>);
54LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[10]>);
55LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[10]>);
56LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[10]>);
57
58struct BeginMember {
59 int x;
60 constexpr const int *begin() const { return &x; }
61};
62
63// Ensure that we can't call with rvalues with borrowing disabled.
64static_assert( std::is_invocable_v<RangeBeginT, BeginMember &>);
65static_assert(!std::is_invocable_v<RangeBeginT, BeginMember &&>);
66static_assert( std::is_invocable_v<RangeBeginT, BeginMember const&>);
67static_assert(!std::is_invocable_v<RangeBeginT, BeginMember const&&>);
68static_assert( std::is_invocable_v<RangeCBeginT, BeginMember &>);
69static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember &&>);
70static_assert( std::is_invocable_v<RangeCBeginT, BeginMember const&>);
71static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember const&&>);
72
73constexpr bool testReturnTypes() {
74 {
75 int *x[2];
76 ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int**);
77 ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), int* const*);
78 }
79 {
80 int x[2][2];
81 ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int(*)[2]);
82 ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), const int(*)[2]);
83 }
84 {
85 struct Different {
86 char*& begin();
87 short*& begin() const;
88 } x;
89 ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), char*);
90 ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), short*);
91 }
92 return true;
93}
94
95constexpr bool testArray() {
96 int a[2];
97 assert(std::ranges::begin(a) == a);
98 assert(std::ranges::cbegin(a) == a);
99
100 int b[2][2];
101 assert(std::ranges::begin(b) == b);
102 assert(std::ranges::cbegin(b) == b);
103
104 BeginMember c[2];
105 assert(std::ranges::begin(c) == c);
106 assert(std::ranges::cbegin(c) == c);
107
108 return true;
109}
110
111struct BeginMemberReturnsInt {
112 int begin() const;
113};
114static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsInt const&>);
115
116struct BeginMemberReturnsVoidPtr {
117 const void *begin() const;
118};
119static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsVoidPtr const&>);
120
121struct EmptyBeginMember {
122 struct iterator {};
123 iterator begin() const;
124};
125static_assert(!std::is_invocable_v<RangeBeginT, EmptyBeginMember const&>);
126
127struct PtrConvertibleBeginMember {
128 struct iterator { operator int*() const; };
129 iterator begin() const;
130};
131static_assert(!std::is_invocable_v<RangeBeginT, PtrConvertibleBeginMember const&>);
132
133struct NonConstBeginMember {
134 int x;
135 constexpr int *begin() { return &x; }
136};
137static_assert( std::is_invocable_v<RangeBeginT, NonConstBeginMember &>);
138static_assert(!std::is_invocable_v<RangeBeginT, NonConstBeginMember const&>);
139static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember &>);
140static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember const&>);
141
142struct EnabledBorrowingBeginMember {
143 constexpr int *begin() const { return &globalBuff[0]; }
144};
145template<>
146inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingBeginMember> = true;
147
148struct BeginMemberFunction {
149 int x;
150 constexpr const int *begin() const { return &x; }
151 friend int *begin(BeginMemberFunction const&);
152};
153
154struct EmptyPtrBeginMember {
155 struct Empty {};
156 Empty x;
157 constexpr const Empty *begin() const { return &x; }
158};
159
160constexpr bool testBeginMember() {
161 BeginMember a;
162 assert(std::ranges::begin(a) == &a.x);
163 assert(std::ranges::cbegin(a) == &a.x);
164 static_assert(!std::is_invocable_v<RangeBeginT, BeginMember&&>);
165 static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember&&>);
166
167 NonConstBeginMember b;
168 assert(std::ranges::begin(b) == &b.x);
169 static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember&>);
170
171 EnabledBorrowingBeginMember c;
172 assert(std::ranges::begin(c) == &globalBuff[0]);
173 assert(std::ranges::cbegin(c) == &globalBuff[0]);
174 assert(std::ranges::begin(std::move(c)) == &globalBuff[0]);
175 assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]);
176
177 BeginMemberFunction d;
178 assert(std::ranges::begin(d) == &d.x);
179 assert(std::ranges::cbegin(d) == &d.x);
180
181 EmptyPtrBeginMember e;
182 assert(std::ranges::begin(e) == &e.x);
183 assert(std::ranges::cbegin(e) == &e.x);
184
185 return true;
186}
187
188
189struct BeginFunction {
190 int x;
191 friend constexpr const int *begin(BeginFunction const& bf) { return &bf.x; }
192};
193static_assert( std::is_invocable_v<RangeBeginT, BeginFunction const&>);
194static_assert(!std::is_invocable_v<RangeBeginT, BeginFunction &&>);
195static_assert(std::is_invocable_v<RangeBeginT, BeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
196static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
197static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
198
199struct BeginFunctionReturnsInt {
200 friend int begin(BeginFunctionReturnsInt const&);
201};
202static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsInt const&>);
203
204struct BeginFunctionReturnsVoidPtr {
205 friend void *begin(BeginFunctionReturnsVoidPtr const&);
206};
207static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsVoidPtr const&>);
208
209struct BeginFunctionReturnsPtrConvertible {
210 struct iterator { operator int*() const; };
211 friend iterator begin(BeginFunctionReturnsPtrConvertible const&);
212};
213static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsPtrConvertible const&>);
214
215struct BeginFunctionByValue {
216 friend constexpr int *begin(BeginFunctionByValue) { return &globalBuff[1]; }
217};
218static_assert(!std::is_invocable_v<RangeCBeginT, BeginFunctionByValue>);
219
220struct BeginFunctionEnabledBorrowing {
221 friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; }
222};
223template<>
224inline constexpr bool std::ranges::enable_borrowed_range<BeginFunctionEnabledBorrowing> = true;
225
226struct BeginFunctionReturnsEmptyPtr {
227 struct Empty {};
228 Empty x;
229 friend constexpr const Empty *begin(BeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
230};
231
232struct BeginFunctionWithDataMember {
233 int x;
234 int begin;
235 friend constexpr const int *begin(BeginFunctionWithDataMember const& bf) { return &bf.x; }
236};
237
238struct BeginFunctionWithPrivateBeginMember {
239 int y;
240 friend constexpr const int *begin(BeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; }
241private:
242 const int *begin() const;
243};
244
245constexpr bool testBeginFunction() {
246 BeginFunction a{};
247 const BeginFunction aa{};
248 assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
249 assert(std::ranges::cbegin(a) == &a.x);
250 assert(std::ranges::begin(aa) == &aa.x);
251 assert(std::ranges::cbegin(aa) == &aa.x);
252
253 BeginFunctionByValue b{};
254 const BeginFunctionByValue bb{};
255 assert(std::ranges::begin(b) == &globalBuff[1]);
256 assert(std::ranges::cbegin(b) == &globalBuff[1]);
257 assert(std::ranges::begin(bb) == &globalBuff[1]);
258 assert(std::ranges::cbegin(bb) == &globalBuff[1]);
259
260 BeginFunctionEnabledBorrowing c{};
261 const BeginFunctionEnabledBorrowing cc{};
262 assert(std::ranges::begin(std::move(c)) == &globalBuff[2]);
263 assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]);
264 assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]);
265 assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]);
266
267 BeginFunctionReturnsEmptyPtr d{};
268 const BeginFunctionReturnsEmptyPtr dd{};
269 assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
270 assert(std::ranges::cbegin(d) == &d.x);
271 assert(std::ranges::begin(dd) == &dd.x);
272 assert(std::ranges::cbegin(dd) == &dd.x);
273
274 BeginFunctionWithDataMember e{};
275 const BeginFunctionWithDataMember ee{};
276 assert(std::ranges::begin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
277 assert(std::ranges::begin(ee) == &ee.x);
278 assert(std::ranges::cbegin(e) == &e.x);
279 assert(std::ranges::cbegin(ee) == &ee.x);
280
281 BeginFunctionWithPrivateBeginMember f{};
282 const BeginFunctionWithPrivateBeginMember ff{};
283 assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
284 assert(std::ranges::cbegin(f) == &f.y);
285 assert(std::ranges::begin(ff) == &ff.y);
286 assert(std::ranges::cbegin(ff) == &ff.y);
287
288 return true;
289}
290
291
292ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
293ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval<int (&)[10]>()));
294
295struct NoThrowMemberBegin {
296 ThrowingIterator<int> begin() const noexcept; // auto(t.begin()) doesn't throw
297} ntmb;
298static_assert(noexcept(std::ranges::begin(ntmb)));
299static_assert(noexcept(std::ranges::cbegin(ntmb)));
300
301struct NoThrowADLBegin {
302 friend ThrowingIterator<int> begin(NoThrowADLBegin&) noexcept; // auto(begin(t)) doesn't throw
303 friend ThrowingIterator<int> begin(const NoThrowADLBegin&) noexcept;
304} ntab;
305static_assert(noexcept(std::ranges::begin(ntab)));
306static_assert(noexcept(std::ranges::cbegin(ntab)));
307
308struct NoThrowMemberBeginReturnsRef {
309 ThrowingIterator<int>& begin() const noexcept; // auto(t.begin()) may throw
310} ntmbrr;
311static_assert(!noexcept(std::ranges::begin(ntmbrr)));
312static_assert(!noexcept(std::ranges::cbegin(ntmbrr)));
313
314struct BeginReturnsArrayRef {
315 auto begin() const noexcept -> int(&)[10];
316} brar;
317static_assert(noexcept(std::ranges::begin(brar)));
318static_assert(noexcept(std::ranges::cbegin(brar)));
319
320// Test ADL-proofing.
321struct Incomplete;
322template<class T> struct Holder { T t; };
323static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*>);
324static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*&>);
325static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
326static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*&>);
327
328int main(int, char**) {
329 static_assert(testReturnTypes());
330
331 testArray();
332 static_assert(testArray());
333
334 testBeginMember();
335 static_assert(testBeginMember());
336
337 testBeginFunction();
338 static_assert(testBeginFunction());
339
340 return 0;
341}
342

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