xref: /llvm-project/libcxx/test/std/ranges/range.access/data.pass.cpp (revision b177a90ce7b590dfce6479142f46fd1b9554a3b3)
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