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; 43 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 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; 123 constexpr int *data() { return &x; } 124 }; 125 126 struct EnabledBorrowingDataMember { 127 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; 134 constexpr const int *data() const { return &x; } 135 const int *begin() const; 136 }; 137 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 163 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 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 { 231 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 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 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