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