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 
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 struct DataMember {
36   int x;
37   constexpr const int *data() const { return &x; }
38 };
39 static_assert( std::is_invocable_v<RangeDataT, DataMember &>);
40 static_assert(!std::is_invocable_v<RangeDataT, DataMember &&>);
41 static_assert( std::is_invocable_v<RangeDataT, DataMember const&>);
42 static_assert(!std::is_invocable_v<RangeDataT, DataMember const&&>);
43 
44 constexpr bool testReturnTypes() {
45   {
46     int *x[2];
47     ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int**);
48   }
49   {
50     int x[2][2];
51     ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int(*)[2]);
52   }
53   {
54     struct D {
55       char*& data();
56       short*& data() const;
57     };
58     ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<D&>())), char*);
59     static_assert(!std::is_invocable_v<RangeDataT, D&&>);
60     ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const D&>())), short*);
61     static_assert(!std::is_invocable_v<RangeDataT, const D&&>);
62   }
63   {
64     struct NC {
65       char *begin() const;
66       char *end() const;
67       int *data();
68     };
69     static_assert(!std::ranges::contiguous_range<NC>);
70     static_assert( std::ranges::contiguous_range<const NC>);
71     ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<NC&>())), int*);
72     static_assert(!std::is_invocable_v<RangeDataT, NC&&>);
73     ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const NC&>())), char*);
74     static_assert(!std::is_invocable_v<RangeDataT, const NC&&>);
75   }
76   return true;
77 }
78 
79 struct VoidDataMember {
80   void *data() const;
81 };
82 static_assert(!std::is_invocable_v<RangeDataT, VoidDataMember const&>);
83 
84 struct Empty { };
85 struct EmptyDataMember {
86   Empty data() const;
87 };
88 static_assert(!std::is_invocable_v<RangeDataT, EmptyDataMember const&>);
89 
90 struct PtrConvertibleDataMember {
91   struct Ptr {
92     operator int*() const;
93   };
94   Ptr data() const;
95 };
96 static_assert(!std::is_invocable_v<RangeDataT, PtrConvertibleDataMember const&>);
97 
98 struct NonConstDataMember {
99   int x;
100   constexpr int *data() { return &x; }
101 };
102 
103 struct EnabledBorrowingDataMember {
104   constexpr int *data() { return &globalBuff[0]; }
105 };
106 template<>
107 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingDataMember> = true;
108 
109 struct DataMemberAndBegin {
110   int x;
111   constexpr const int *data() const { return &x; }
112   const int *begin() const;
113 };
114 
115 constexpr bool testDataMember() {
116   DataMember a;
117   assert(std::ranges::data(a) == &a.x);
118 
119   NonConstDataMember b;
120   assert(std::ranges::data(b) == &b.x);
121 
122   EnabledBorrowingDataMember c;
123   assert(std::ranges::data(std::move(c)) == &globalBuff[0]);
124 
125   DataMemberAndBegin d;
126   assert(std::ranges::data(d) == &d.x);
127 
128   return true;
129 }
130 
131 using ContiguousIter = contiguous_iterator<const int*>;
132 
133 struct BeginMemberContiguousIterator {
134   int buff[8];
135 
136   constexpr ContiguousIter begin() const { return ContiguousIter(buff); }
137 };
138 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>);
139 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>);
140 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>);
141 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>);
142 
143 struct BeginMemberRandomAccess {
144   int buff[8];
145 
146   random_access_iterator<const int*> begin() const;
147 };
148 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess&>);
149 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess&&>);
150 static_assert(!std::is_invocable_v<RangeDataT, const BeginMemberRandomAccess&>);
151 static_assert(!std::is_invocable_v<RangeDataT, const BeginMemberRandomAccess&&>);
152 
153 struct BeginFriendContiguousIterator {
154   int buff[8];
155 
156   friend constexpr ContiguousIter begin(const BeginFriendContiguousIterator &iter) {
157     return ContiguousIter(iter.buff);
158   }
159 };
160 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>);
161 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>);
162 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>);
163 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>);
164 
165 struct BeginFriendRandomAccess {
166   friend random_access_iterator<const int*> begin(const BeginFriendRandomAccess iter);
167 };
168 static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess&>);
169 static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess&&>);
170 static_assert(!std::is_invocable_v<RangeDataT, const BeginFriendRandomAccess&>);
171 static_assert(!std::is_invocable_v<RangeDataT, const BeginFriendRandomAccess&&>);
172 
173 struct BeginMemberRvalue {
174   int buff[8];
175 
176   ContiguousIter begin() &&;
177 };
178 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&>);
179 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&&>);
180 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&>);
181 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&&>);
182 
183 struct BeginMemberBorrowingEnabled {
184   constexpr contiguous_iterator<int*> begin() { return contiguous_iterator<int*>{&globalBuff[1]}; }
185 };
186 template<>
187 inline constexpr bool std::ranges::enable_borrowed_range<BeginMemberBorrowingEnabled> = true;
188 static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &>);
189 static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &&>);
190 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&>);
191 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&&>);
192 
193 constexpr bool testViaRangesBegin() {
194   int arr[2];
195   assert(std::ranges::data(arr) == arr + 0);
196 
197   BeginMemberContiguousIterator a;
198   assert(std::ranges::data(a) == a.buff);
199 
200   const BeginFriendContiguousIterator b {};
201   assert(std::ranges::data(b) == b.buff);
202 
203   BeginMemberBorrowingEnabled c;
204   assert(std::ranges::data(std::move(c)) == &globalBuff[1]);
205 
206   return true;
207 }
208 
209 // Test ADL-proofing.
210 struct Incomplete;
211 template<class T> struct Holder { T t; };
212 static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*>);
213 static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*&>);
214 
215 struct RandomButNotContiguous {
216   random_access_iterator<int*> begin() const;
217   random_access_iterator<int*> end() const;
218 };
219 static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous>);
220 static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous&>);
221 
222 int main(int, char**) {
223   static_assert(testReturnTypes());
224 
225   testDataMember();
226   static_assert(testDataMember());
227 
228   testViaRangesBegin();
229   static_assert(testViaRangesBegin());
230 
231   return 0;
232 }
233