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