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