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