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