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