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