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 // template<class D> 12 // requires is_class_v<D> && same_as<D, remove_cv_t<D>> 13 // class view_interface; 14 15 #include <ranges> 16 17 #include <cassert> 18 #include "test_macros.h" 19 #include "test_iterators.h" 20 21 template<class T> 22 concept ValidViewInterfaceType = requires { typename std::ranges::view_interface<T>; }; 23 24 struct Empty { }; 25 26 static_assert(!ValidViewInterfaceType<void>); 27 static_assert(!ValidViewInterfaceType<void*>); 28 static_assert(!ValidViewInterfaceType<Empty*>); 29 static_assert(!ValidViewInterfaceType<Empty const>); 30 static_assert(!ValidViewInterfaceType<Empty &>); 31 static_assert( ValidViewInterfaceType<Empty>); 32 33 using InputIter = cpp20_input_iterator<const int*>; 34 35 struct InputRange : std::ranges::view_interface<InputRange> { 36 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 37 constexpr InputIter begin() const { return InputIter(buff); } 38 constexpr InputIter end() const { return InputIter(buff + 8); } 39 }; 40 41 struct NotSizedSentinel { 42 using value_type = int; 43 using difference_type = std::ptrdiff_t; 44 using iterator_concept = std::forward_iterator_tag; 45 46 explicit NotSizedSentinel() = default; 47 explicit NotSizedSentinel(int*); 48 int& operator*() const; 49 NotSizedSentinel& operator++(); 50 NotSizedSentinel operator++(int); 51 bool operator==(NotSizedSentinel const&) const; 52 }; 53 static_assert(std::forward_iterator<NotSizedSentinel>); 54 55 using ForwardIter = forward_iterator<int*>; 56 57 // So that we conform to sized_sentinel_for. 58 constexpr std::ptrdiff_t operator-(const ForwardIter& x, const ForwardIter& y) { 59 return base(x) - base(y); 60 } 61 62 struct ForwardRange : std::ranges::view_interface<ForwardRange> { 63 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 64 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); } 65 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); } 66 }; 67 static_assert(std::ranges::view<ForwardRange>); 68 69 struct MoveOnlyForwardRange : std::ranges::view_interface<MoveOnlyForwardRange> { 70 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 71 MoveOnlyForwardRange(MoveOnlyForwardRange const&) = delete; 72 MoveOnlyForwardRange(MoveOnlyForwardRange &&) = default; 73 MoveOnlyForwardRange& operator=(MoveOnlyForwardRange &&) = default; 74 MoveOnlyForwardRange() = default; 75 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); } 76 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); } 77 }; 78 static_assert(std::ranges::view<MoveOnlyForwardRange>); 79 80 struct MI : std::ranges::view_interface<InputRange>, 81 std::ranges::view_interface<MoveOnlyForwardRange> { 82 }; 83 static_assert(!std::ranges::view<MI>); 84 85 struct EmptyIsTrue : std::ranges::view_interface<EmptyIsTrue> { 86 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 87 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); } 88 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); } 89 constexpr bool empty() const { return true; } 90 }; 91 static_assert(std::ranges::view<EmptyIsTrue>); 92 93 struct SizeIsTen : std::ranges::view_interface<SizeIsTen> { 94 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 95 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); } 96 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); } 97 constexpr size_t size() const { return 10; } 98 }; 99 static_assert(std::ranges::view<SizeIsTen>); 100 101 using RAIter = random_access_iterator<int*>; 102 103 struct RARange : std::ranges::view_interface<RARange> { 104 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 105 constexpr RAIter begin() const { return RAIter(const_cast<int*>(buff)); } 106 constexpr RAIter end() const { return RAIter(const_cast<int*>(buff) + 8); } 107 }; 108 static_assert(std::ranges::view<RARange>); 109 110 using ContIter = contiguous_iterator<const int*>; 111 112 struct ContRange : std::ranges::view_interface<ContRange> { 113 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 114 constexpr ContIter begin() const { return ContIter(buff); } 115 constexpr ContIter end() const { return ContIter(buff + 8); } 116 }; 117 static_assert(std::ranges::view<ContRange>); 118 119 struct DataIsNull : std::ranges::view_interface<DataIsNull> { 120 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 121 constexpr ContIter begin() const { return ContIter(buff); } 122 constexpr ContIter end() const { return ContIter(buff + 8); } 123 constexpr const int *data() const { return nullptr; } 124 }; 125 static_assert(std::ranges::view<DataIsNull>); 126 127 struct BoolConvertibleComparison : std::ranges::view_interface<BoolConvertibleComparison> { 128 struct ResultType { 129 bool value; 130 constexpr operator bool() const { return value; } 131 }; 132 133 struct SentinelType { 134 int *base_; 135 explicit SentinelType() = default; 136 constexpr explicit SentinelType(int *base) : base_(base) {} 137 friend constexpr ResultType operator==(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) == sent.base_}; } 138 friend constexpr ResultType operator==(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) == sent.base_}; } 139 friend constexpr ResultType operator!=(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) != sent.base_}; } 140 friend constexpr ResultType operator!=(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) != sent.base_}; } 141 }; 142 143 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 144 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); } 145 constexpr SentinelType end() const { return SentinelType(const_cast<int*>(buff) + 8); } 146 }; 147 static_assert(std::ranges::view<BoolConvertibleComparison>); 148 149 template<class T> 150 concept EmptyInvocable = requires (T const& obj) { obj.empty(); }; 151 152 template<class T> 153 concept BoolOpInvocable = requires (T const& obj) { bool(obj); }; 154 155 constexpr bool testEmpty() { 156 static_assert(!EmptyInvocable<InputRange>); 157 static_assert( EmptyInvocable<ForwardRange>); 158 159 static_assert(!BoolOpInvocable<InputRange>); 160 static_assert( BoolOpInvocable<ForwardRange>); 161 162 ForwardRange forwardRange; 163 assert(!forwardRange.empty()); 164 assert(!static_cast<ForwardRange const&>(forwardRange).empty()); 165 166 assert(forwardRange); 167 assert(static_cast<ForwardRange const&>(forwardRange)); 168 169 assert(!std::ranges::empty(forwardRange)); 170 assert(!std::ranges::empty(static_cast<ForwardRange const&>(forwardRange))); 171 172 EmptyIsTrue emptyTrue; 173 assert(emptyTrue.empty()); 174 assert(static_cast<EmptyIsTrue const&>(emptyTrue).empty()); 175 assert(!emptyTrue.std::ranges::view_interface<EmptyIsTrue>::empty()); 176 177 assert(!emptyTrue); 178 assert(!static_cast<EmptyIsTrue const&>(emptyTrue)); 179 assert(!emptyTrue.std::ranges::view_interface<EmptyIsTrue>::operator bool()); 180 181 assert(std::ranges::empty(emptyTrue)); 182 assert(std::ranges::empty(static_cast<EmptyIsTrue const&>(emptyTrue))); 183 184 // Try calling empty on an rvalue. 185 MoveOnlyForwardRange moveOnly; 186 assert(!std::move(moveOnly).empty()); 187 188 BoolConvertibleComparison boolConv; 189 ASSERT_NOT_NOEXCEPT(boolConv.empty()); 190 191 assert(!boolConv.empty()); 192 assert(!static_cast<const BoolConvertibleComparison&>(boolConv).empty()); 193 194 assert(boolConv); 195 assert(static_cast<const BoolConvertibleComparison&>(boolConv)); 196 197 assert(!std::ranges::empty(boolConv)); 198 assert(!std::ranges::empty(static_cast<const BoolConvertibleComparison&>(boolConv))); 199 200 return true; 201 } 202 203 template<class T> 204 concept DataInvocable = requires (T const& obj) { obj.data(); }; 205 206 constexpr bool testData() { 207 static_assert(!DataInvocable<ForwardRange>); 208 static_assert( DataInvocable<ContRange>); 209 210 ContRange contiguous; 211 assert(contiguous.data() == contiguous.buff); 212 assert(static_cast<ContRange const&>(contiguous).data() == contiguous.buff); 213 214 assert(std::ranges::data(contiguous) == contiguous.buff); 215 assert(std::ranges::data(static_cast<ContRange const&>(contiguous)) == contiguous.buff); 216 217 DataIsNull dataNull; 218 assert(dataNull.data() == nullptr); 219 assert(static_cast<DataIsNull const&>(dataNull).data() == nullptr); 220 assert(dataNull.std::ranges::view_interface<DataIsNull>::data() == dataNull.buff); 221 222 assert(std::ranges::data(dataNull) == nullptr); 223 assert(std::ranges::data(static_cast<DataIsNull const&>(dataNull)) == nullptr); 224 225 return true; 226 } 227 228 template<class T> 229 concept SizeInvocable = requires (T const& obj) { obj.size(); }; 230 231 constexpr bool testSize() { 232 static_assert(!SizeInvocable<InputRange>); 233 static_assert(!SizeInvocable<NotSizedSentinel>); 234 static_assert( SizeInvocable<ForwardRange>); 235 236 ForwardRange forwardRange; 237 assert(forwardRange.size() == 8); 238 assert(static_cast<ForwardRange const&>(forwardRange).size() == 8); 239 240 assert(std::ranges::size(forwardRange) == 8); 241 assert(std::ranges::size(static_cast<ForwardRange const&>(forwardRange)) == 8); 242 243 SizeIsTen sizeTen; 244 assert(sizeTen.size() == 10); 245 assert(static_cast<SizeIsTen const&>(sizeTen).size() == 10); 246 assert(sizeTen.std::ranges::view_interface<SizeIsTen>::size() == 8); 247 248 assert(std::ranges::size(sizeTen) == 10); 249 assert(std::ranges::size(static_cast<SizeIsTen const&>(sizeTen)) == 10); 250 251 return true; 252 } 253 254 template<class T> 255 concept SubscriptInvocable = requires (T const& obj, size_t n) { obj[n]; }; 256 257 constexpr bool testSubscript() { 258 static_assert(!SubscriptInvocable<ForwardRange>); 259 static_assert( SubscriptInvocable<RARange>); 260 261 RARange randomAccess; 262 assert(randomAccess[2] == 2); 263 assert(static_cast<RARange const&>(randomAccess)[2] == 2); 264 randomAccess[2] = 3; 265 assert(randomAccess[2] == 3); 266 267 return true; 268 } 269 270 template<class T> 271 concept FrontInvocable = requires (T const& obj) { obj.front(); }; 272 273 template<class T> 274 concept BackInvocable = requires (T const& obj) { obj.back(); }; 275 276 constexpr bool testFrontBack() { 277 static_assert(!FrontInvocable<InputRange>); 278 static_assert( FrontInvocable<ForwardRange>); 279 static_assert(!BackInvocable<ForwardRange>); 280 static_assert( BackInvocable<RARange>); 281 282 ForwardRange forwardRange; 283 assert(forwardRange.front() == 0); 284 assert(static_cast<ForwardRange const&>(forwardRange).front() == 0); 285 forwardRange.front() = 2; 286 assert(forwardRange.front() == 2); 287 288 RARange randomAccess; 289 assert(randomAccess.front() == 0); 290 assert(static_cast<RARange const&>(randomAccess).front() == 0); 291 randomAccess.front() = 2; 292 assert(randomAccess.front() == 2); 293 294 assert(randomAccess.back() == 7); 295 assert(static_cast<RARange const&>(randomAccess).back() == 7); 296 randomAccess.back() = 2; 297 assert(randomAccess.back() == 2); 298 299 return true; 300 } 301 302 struct V1 : std::ranges::view_interface<V1> { }; 303 struct V2 : std::ranges::view_interface<V2> { V1 base_; }; 304 static_assert(sizeof(V2) == sizeof(V1)); 305 306 int main(int, char**) { 307 testEmpty(); 308 static_assert(testEmpty()); 309 310 testData(); 311 static_assert(testData()); 312 313 testSize(); 314 static_assert(testSize()); 315 316 testSubscript(); 317 static_assert(testSubscript()); 318 319 testFrontBack(); 320 static_assert(testFrontBack()); 321 322 return 0; 323 } 324