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