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-has-no-incomplete-ranges
11 
12 // std::ranges::data
13 
14 #include <ranges>
15 
16 #include <cassert>
17 #include <type_traits>
18 #include "test_macros.h"
19 #include "test_iterators.h"
20 
21 using RangeDataT = decltype(std::ranges::data);
22 using RangeCDataT = decltype(std::ranges::cdata);
23 
24 static int globalBuff[2];
25 
26 struct Incomplete;
27 
28 static_assert(!std::is_invocable_v<RangeDataT, Incomplete[]>);
29 static_assert(!std::is_invocable_v<RangeDataT, Incomplete(&&)[2]>);
30 static_assert(!std::is_invocable_v<RangeDataT, Incomplete(&&)[2][2]>);
31 static_assert(!std::is_invocable_v<RangeDataT, int [1]>);
32 static_assert(!std::is_invocable_v<RangeDataT, int (&&)[1]>);
33 static_assert( std::is_invocable_v<RangeDataT, int (&)[1]>);
34 
35 static_assert(!std::is_invocable_v<RangeCDataT, Incomplete[]>);
36 static_assert(!std::is_invocable_v<RangeCDataT, Incomplete(&&)[2]>);
37 static_assert(!std::is_invocable_v<RangeCDataT, Incomplete(&&)[2][2]>);
38 static_assert(!std::is_invocable_v<RangeCDataT, int [1]>);
39 static_assert(!std::is_invocable_v<RangeCDataT, int (&&)[1]>);
40 static_assert( std::is_invocable_v<RangeCDataT, int (&)[1]>);
41 
42 struct DataMember {
43   int x;
44   constexpr const int *data() const { return &x; }
45 };
46 static_assert( std::is_invocable_v<RangeDataT, DataMember &>);
47 static_assert(!std::is_invocable_v<RangeDataT, DataMember &&>);
48 static_assert( std::is_invocable_v<RangeDataT, DataMember const&>);
49 static_assert(!std::is_invocable_v<RangeDataT, DataMember const&&>);
50 static_assert( std::is_invocable_v<RangeCDataT, DataMember &>);
51 static_assert(!std::is_invocable_v<RangeCDataT, DataMember &&>);
52 static_assert( std::is_invocable_v<RangeCDataT, DataMember const&>);
53 static_assert(!std::is_invocable_v<RangeCDataT, DataMember const&&>);
54 
55 constexpr bool testReturnTypes() {
56   {
57     int *x[2];
58     ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int**);
59     ASSERT_SAME_TYPE(decltype(std::ranges::cdata(x)), int* const*);
60   }
61   {
62     int x[2][2];
63     ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int(*)[2]);
64     ASSERT_SAME_TYPE(decltype(std::ranges::cdata(x)), const int(*)[2]);
65   }
66   {
67     struct D {
68       char*& data();
69       short*& data() const;
70     };
71     ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<D&>())), char*);
72     static_assert(!std::is_invocable_v<RangeDataT, D&&>);
73     ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const D&>())), short*);
74     static_assert(!std::is_invocable_v<RangeDataT, const D&&>);
75     ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<D&>())), short*);
76     static_assert(!std::is_invocable_v<RangeCDataT, D&&>);
77     ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<const D&>())), short*);
78     static_assert(!std::is_invocable_v<RangeCDataT, const D&&>);
79   }
80   {
81     struct NC {
82       char *begin() const;
83       char *end() const;
84       int *data();
85     };
86     static_assert(!std::ranges::contiguous_range<NC>);
87     static_assert( std::ranges::contiguous_range<const NC>);
88     ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<NC&>())), int*);
89     static_assert(!std::is_invocable_v<RangeDataT, NC&&>);
90     ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const NC&>())), char*);
91     static_assert(!std::is_invocable_v<RangeDataT, const NC&&>);
92     ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<NC&>())), char*);
93     static_assert(!std::is_invocable_v<RangeCDataT, NC&&>);
94     ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<const NC&>())), char*);
95     static_assert(!std::is_invocable_v<RangeCDataT, const NC&&>);
96   }
97   return true;
98 }
99 
100 struct VoidDataMember {
101   void *data() const;
102 };
103 static_assert(!std::is_invocable_v<RangeDataT, VoidDataMember const&>);
104 static_assert(!std::is_invocable_v<RangeCDataT, VoidDataMember const&>);
105 
106 struct Empty { };
107 struct EmptyDataMember {
108   Empty data() const;
109 };
110 static_assert(!std::is_invocable_v<RangeDataT, EmptyDataMember const&>);
111 static_assert(!std::is_invocable_v<RangeCDataT, EmptyDataMember const&>);
112 
113 struct PtrConvertibleDataMember {
114   struct Ptr {
115     operator int*() const;
116   };
117   Ptr data() const;
118 };
119 static_assert(!std::is_invocable_v<RangeDataT, PtrConvertibleDataMember const&>);
120 static_assert(!std::is_invocable_v<RangeCDataT, PtrConvertibleDataMember const&>);
121 
122 struct NonConstDataMember {
123   int x;
124   constexpr int *data() { return &x; }
125 };
126 
127 struct EnabledBorrowingDataMember {
128   constexpr int *data() { return &globalBuff[0]; }
129 };
130 template<>
131 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingDataMember> = true;
132 
133 struct DataMemberAndBegin {
134   int x;
135   constexpr const int *data() const { return &x; }
136   const int *begin() const;
137 };
138 
139 constexpr bool testDataMember() {
140   DataMember a;
141   assert(std::ranges::data(a) == &a.x);
142   assert(std::ranges::cdata(a) == &a.x);
143 
144   NonConstDataMember b;
145   assert(std::ranges::data(b) == &b.x);
146   static_assert(!std::is_invocable_v<RangeCDataT, decltype((b))>);
147 
148   EnabledBorrowingDataMember c;
149   assert(std::ranges::data(std::move(c)) == &globalBuff[0]);
150   static_assert(!std::is_invocable_v<RangeCDataT, decltype(std::move(c))>);
151 
152   DataMemberAndBegin d;
153   assert(std::ranges::data(d) == &d.x);
154   assert(std::ranges::cdata(d) == &d.x);
155 
156   return true;
157 }
158 
159 using ContiguousIter = contiguous_iterator<const int*>;
160 
161 struct BeginMemberContiguousIterator {
162   int buff[8];
163 
164   constexpr ContiguousIter begin() const { return ContiguousIter(buff); }
165 };
166 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>);
167 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>);
168 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>);
169 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>);
170 static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &>);
171 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &&>);
172 static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&>);
173 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&&>);
174 
175 struct BeginMemberRandomAccess {
176   int buff[8];
177 
178   random_access_iterator<const int*> begin() const;
179 };
180 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess&>);
181 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess&&>);
182 static_assert(!std::is_invocable_v<RangeDataT, const BeginMemberRandomAccess&>);
183 static_assert(!std::is_invocable_v<RangeDataT, const BeginMemberRandomAccess&&>);
184 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRandomAccess&>);
185 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRandomAccess&&>);
186 static_assert(!std::is_invocable_v<RangeCDataT, const BeginMemberRandomAccess&>);
187 static_assert(!std::is_invocable_v<RangeCDataT, const BeginMemberRandomAccess&&>);
188 
189 struct BeginFriendContiguousIterator {
190   int buff[8];
191 
192   friend constexpr ContiguousIter begin(const BeginFriendContiguousIterator &iter) {
193     return ContiguousIter(iter.buff);
194   }
195 };
196 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>);
197 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>);
198 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>);
199 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>);
200 static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &>);
201 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &&>);
202 static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&>);
203 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&&>);
204 
205 struct BeginFriendRandomAccess {
206   friend random_access_iterator<const int*> begin(const BeginFriendRandomAccess iter);
207 };
208 static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess&>);
209 static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess&&>);
210 static_assert(!std::is_invocable_v<RangeDataT, const BeginFriendRandomAccess&>);
211 static_assert(!std::is_invocable_v<RangeDataT, const BeginFriendRandomAccess&&>);
212 static_assert(!std::is_invocable_v<RangeCDataT, BeginFriendRandomAccess&>);
213 static_assert(!std::is_invocable_v<RangeCDataT, BeginFriendRandomAccess&&>);
214 static_assert(!std::is_invocable_v<RangeCDataT, const BeginFriendRandomAccess&>);
215 static_assert(!std::is_invocable_v<RangeCDataT, const BeginFriendRandomAccess&&>);
216 
217 struct BeginMemberRvalue {
218   int buff[8];
219 
220   ContiguousIter begin() &&;
221 };
222 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&>);
223 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&&>);
224 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&>);
225 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&&>);
226 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue&>);
227 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue&&>);
228 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue const&>);
229 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue const&&>);
230 
231 struct BeginMemberBorrowingEnabled {
232   constexpr contiguous_iterator<int*> begin() { return contiguous_iterator<int*>{&globalBuff[1]}; }
233 };
234 template<>
235 inline constexpr bool std::ranges::enable_borrowed_range<BeginMemberBorrowingEnabled> = true;
236 static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &>);
237 static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &&>);
238 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&>);
239 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&&>);
240 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled &>);
241 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled &&>);
242 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled const&>);
243 static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled const&&>);
244 
245 constexpr bool testViaRangesBegin() {
246   int arr[2];
247   assert(std::ranges::data(arr) == arr + 0);
248   assert(std::ranges::cdata(arr) == arr + 0);
249 
250   BeginMemberContiguousIterator a;
251   assert(std::ranges::data(a) == a.buff);
252   assert(std::ranges::cdata(a) == a.buff);
253 
254   const BeginFriendContiguousIterator b {};
255   assert(std::ranges::data(b) == b.buff);
256   assert(std::ranges::cdata(b) == b.buff);
257 
258   BeginMemberBorrowingEnabled c;
259   assert(std::ranges::data(std::move(c)) == &globalBuff[1]);
260   static_assert(!std::is_invocable_v<RangeCDataT, decltype(std::move(c))>);
261 
262   return true;
263 }
264 
265 // Test ADL-proofing.
266 struct Incomplete;
267 template<class T> struct Holder { T t; };
268 static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*>);
269 static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*&>);
270 static_assert(!std::is_invocable_v<RangeCDataT, Holder<Incomplete>*>);
271 static_assert(!std::is_invocable_v<RangeCDataT, Holder<Incomplete>*&>);
272 
273 struct RandomButNotContiguous {
274   random_access_iterator<int*> begin() const;
275   random_access_iterator<int*> end() const;
276 };
277 static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous>);
278 static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous&>);
279 static_assert(!std::is_invocable_v<RangeCDataT, RandomButNotContiguous>);
280 static_assert(!std::is_invocable_v<RangeCDataT, RandomButNotContiguous&>);
281 
282 int main(int, char**) {
283   static_assert(testReturnTypes());
284 
285   testDataMember();
286   static_assert(testDataMember());
287 
288   testViaRangesBegin();
289   static_assert(testViaRangesBegin());
290 
291   return 0;
292 }
293