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