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