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