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