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