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