355 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 11// template<class D>12// requires is_class_v<D> && same_as<D, remove_cv_t<D>>13// class view_interface;14 15#include <ranges>16 17#include <cassert>18#include <utility>19#include "test_macros.h"20#include "test_iterators.h"21 22template<class T>23concept ValidViewInterfaceType = requires { typename std::ranges::view_interface<T>; };24 25struct Empty { };26 27static_assert(!ValidViewInterfaceType<void>);28static_assert(!ValidViewInterfaceType<void*>);29static_assert(!ValidViewInterfaceType<Empty*>);30static_assert(!ValidViewInterfaceType<Empty const>);31static_assert(!ValidViewInterfaceType<Empty &>);32static_assert( ValidViewInterfaceType<Empty>);33 34using InputIter = cpp20_input_iterator<const int*>;35 36struct InputRange : std::ranges::view_interface<InputRange> {37 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};38 constexpr InputIter begin() const { return InputIter(buff); }39 constexpr InputIter end() const { return InputIter(buff + 8); }40};41 42struct SizedInputRange : std::ranges::view_interface<SizedInputRange> {43 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};44 constexpr InputIter begin() const { return InputIter(buff); }45 constexpr sentinel_wrapper<InputIter> end() const { return sentinel_wrapper(InputIter(buff + 8)); }46 constexpr std::size_t size() const { return 8; }47};48static_assert(std::ranges::sized_range<SizedInputRange>);49 50struct NotSizedSentinel {51 using value_type = int;52 using difference_type = std::ptrdiff_t;53 using iterator_concept = std::forward_iterator_tag;54 55 explicit NotSizedSentinel() = default;56 explicit NotSizedSentinel(int*);57 int& operator*() const;58 NotSizedSentinel& operator++();59 NotSizedSentinel operator++(int);60 bool operator==(NotSizedSentinel const&) const;61};62static_assert(std::forward_iterator<NotSizedSentinel>);63 64using ForwardIter = forward_iterator<int*>;65 66// So that we conform to sized_sentinel_for.67constexpr std::ptrdiff_t operator-(const ForwardIter& x, const ForwardIter& y) {68 return base(x) - base(y);69}70 71struct ForwardRange : std::ranges::view_interface<ForwardRange> {72 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};73 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }74 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }75};76static_assert(std::ranges::view<ForwardRange>);77 78struct MoveOnlyForwardRange : std::ranges::view_interface<MoveOnlyForwardRange> {79 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};80 MoveOnlyForwardRange(MoveOnlyForwardRange const&) = delete;81 MoveOnlyForwardRange(MoveOnlyForwardRange &&) = default;82 MoveOnlyForwardRange& operator=(MoveOnlyForwardRange &&) = default;83 MoveOnlyForwardRange() = default;84 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }85 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }86};87static_assert(std::ranges::view<MoveOnlyForwardRange>);88 89struct MI : std::ranges::view_interface<InputRange>,90 std::ranges::view_interface<MoveOnlyForwardRange> {91};92static_assert(!std::ranges::view<MI>);93 94struct EmptyIsTrue : std::ranges::view_interface<EmptyIsTrue> {95 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};96 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }97 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }98 constexpr bool empty() const { return true; }99};100static_assert(std::ranges::view<EmptyIsTrue>);101 102struct SizeIsTen : std::ranges::view_interface<SizeIsTen> {103 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};104 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }105 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }106 constexpr std::size_t size() const { return 10; }107};108static_assert(std::ranges::view<SizeIsTen>);109 110using RAIter = random_access_iterator<int*>;111 112struct RARange : std::ranges::view_interface<RARange> {113 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};114 constexpr RAIter begin() const { return RAIter(const_cast<int*>(buff)); }115 constexpr RAIter end() const { return RAIter(const_cast<int*>(buff) + 8); }116};117static_assert(std::ranges::view<RARange>);118 119using ContIter = contiguous_iterator<const int*>;120 121struct ContRange : std::ranges::view_interface<ContRange> {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};126static_assert(std::ranges::view<ContRange>);127 128struct DataIsNull : std::ranges::view_interface<DataIsNull> {129 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};130 constexpr ContIter begin() const { return ContIter(buff); }131 constexpr ContIter end() const { return ContIter(buff + 8); }132 constexpr const int *data() const { return nullptr; }133};134static_assert(std::ranges::view<DataIsNull>);135 136struct BoolConvertibleComparison : std::ranges::view_interface<BoolConvertibleComparison> {137 struct ResultType {138 bool value;139 constexpr operator bool() const { return value; }140 };141 142 struct SentinelType {143 int *base_;144 explicit SentinelType() = default;145 constexpr explicit SentinelType(int *base) : base_(base) {}146 friend constexpr ResultType operator==(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) == sent.base_}; }147 friend constexpr ResultType operator==(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) == sent.base_}; }148 friend constexpr ResultType operator!=(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) != sent.base_}; }149 friend constexpr ResultType operator!=(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) != sent.base_}; }150 };151 152 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};153 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }154 constexpr SentinelType end() const { return SentinelType(const_cast<int*>(buff) + 8); }155};156static_assert(std::ranges::view<BoolConvertibleComparison>);157 158template<class T>159concept EmptyInvocable = requires (T const& obj) { obj.empty(); };160 161template<class T>162concept BoolOpInvocable = requires (T const& obj) { bool(obj); };163 164constexpr bool testEmpty() {165 static_assert(!EmptyInvocable<InputRange>);166 // LWG 3715: `view_interface::empty` is overconstrained167 static_assert(EmptyInvocable<SizedInputRange>);168 static_assert( EmptyInvocable<ForwardRange>);169 170 static_assert(!BoolOpInvocable<InputRange>);171 static_assert(BoolOpInvocable<SizedInputRange>);172 static_assert( BoolOpInvocable<ForwardRange>);173 174 SizedInputRange sizedInputRange;175 assert(!sizedInputRange.empty());176 assert(!static_cast<SizedInputRange const&>(sizedInputRange).empty());177 178 assert(sizedInputRange);179 assert(static_cast<SizedInputRange const&>(sizedInputRange));180 181 assert(!std::ranges::empty(sizedInputRange));182 assert(!std::ranges::empty(static_cast<SizedInputRange const&>(sizedInputRange)));183 184 ForwardRange forwardRange;185 assert(!forwardRange.empty());186 assert(!static_cast<ForwardRange const&>(forwardRange).empty());187 188 assert(forwardRange);189 assert(static_cast<ForwardRange const&>(forwardRange));190 191 assert(!std::ranges::empty(forwardRange));192 assert(!std::ranges::empty(static_cast<ForwardRange const&>(forwardRange)));193 194 EmptyIsTrue emptyTrue;195 assert(emptyTrue.empty());196 assert(static_cast<EmptyIsTrue const&>(emptyTrue).empty());197 assert(!emptyTrue.std::ranges::view_interface<EmptyIsTrue>::empty());198 199 assert(!emptyTrue);200 assert(!static_cast<EmptyIsTrue const&>(emptyTrue));201 assert(!emptyTrue.std::ranges::view_interface<EmptyIsTrue>::operator bool());202 203 assert(std::ranges::empty(emptyTrue));204 assert(std::ranges::empty(static_cast<EmptyIsTrue const&>(emptyTrue)));205 206 // Try calling empty on an rvalue.207 MoveOnlyForwardRange moveOnly;208 assert(!std::move(moveOnly).empty());209 210 BoolConvertibleComparison boolConv;211 ASSERT_NOT_NOEXCEPT(boolConv.empty());212 213 assert(!boolConv.empty());214 assert(!static_cast<const BoolConvertibleComparison&>(boolConv).empty());215 216 assert(boolConv);217 assert(static_cast<const BoolConvertibleComparison&>(boolConv));218 219 assert(!std::ranges::empty(boolConv));220 assert(!std::ranges::empty(static_cast<const BoolConvertibleComparison&>(boolConv)));221 222 return true;223}224 225template<class T>226concept DataInvocable = requires (T const& obj) { obj.data(); };227 228constexpr bool testData() {229 static_assert(!DataInvocable<ForwardRange>);230 static_assert( DataInvocable<ContRange>);231 232 ContRange contiguous;233 assert(contiguous.data() == contiguous.buff);234 assert(static_cast<ContRange const&>(contiguous).data() == contiguous.buff);235 236 assert(std::ranges::data(contiguous) == contiguous.buff);237 assert(std::ranges::data(static_cast<ContRange const&>(contiguous)) == contiguous.buff);238 239 DataIsNull dataNull;240 assert(dataNull.data() == nullptr);241 assert(static_cast<DataIsNull const&>(dataNull).data() == nullptr);242 assert(dataNull.std::ranges::view_interface<DataIsNull>::data() == dataNull.buff);243 244 assert(std::ranges::data(dataNull) == nullptr);245 assert(std::ranges::data(static_cast<DataIsNull const&>(dataNull)) == nullptr);246 247 return true;248}249 250template<class T>251concept SizeInvocable = requires (T const& obj) { obj.size(); };252 253constexpr bool testSize() {254 static_assert(!SizeInvocable<InputRange>);255 static_assert(!SizeInvocable<NotSizedSentinel>);256 static_assert( SizeInvocable<ForwardRange>);257 258 // Test the test.259 static_assert(std::same_as<decltype(std::declval<ForwardIter>() - std::declval<ForwardIter>()), std::ptrdiff_t>);260 using UnsignedSize = std::make_unsigned_t<std::ptrdiff_t>;261 using SignedSize = std::common_type_t<std::ptrdiff_t, std::make_signed_t<UnsignedSize>>;262 ForwardRange forwardRange;263 assert(forwardRange.size() == 8);264 assert(static_cast<ForwardRange const&>(forwardRange).size() == 8);265 266 assert(std::ranges::size(forwardRange) == 8);267 static_assert(std::same_as<decltype(std::ranges::size(std::declval<ForwardRange>())), UnsignedSize>);268 static_assert(std::same_as<decltype(std::ranges::ssize(std::declval<ForwardRange>())), SignedSize>);269 270 assert(std::ranges::size(static_cast<ForwardRange const&>(forwardRange)) == 8);271 static_assert(std::same_as<decltype(std::ranges::size(std::declval<ForwardRange const>())), UnsignedSize>);272 static_assert(std::same_as<decltype(std::ranges::ssize(std::declval<ForwardRange const>())), SignedSize>);273 274 SizeIsTen sizeTen;275 assert(sizeTen.size() == 10);276 assert(static_cast<SizeIsTen const&>(sizeTen).size() == 10);277 assert(sizeTen.std::ranges::view_interface<SizeIsTen>::size() == 8);278 279 assert(std::ranges::size(sizeTen) == 10);280 assert(std::ranges::size(static_cast<SizeIsTen const&>(sizeTen)) == 10);281 282 return true;283}284 285template<class T>286concept SubscriptInvocable = requires (T const& obj, std::size_t n) { obj[n]; };287 288constexpr bool testSubscript() {289 static_assert(!SubscriptInvocable<ForwardRange>);290 static_assert( SubscriptInvocable<RARange>);291 292 RARange randomAccess;293 assert(randomAccess[2] == 2);294 assert(static_cast<RARange const&>(randomAccess)[2] == 2);295 randomAccess[2] = 3;296 assert(randomAccess[2] == 3);297 298 return true;299}300 301template<class T>302concept FrontInvocable = requires (T const& obj) { obj.front(); };303 304template<class T>305concept BackInvocable = requires (T const& obj) { obj.back(); };306 307constexpr bool testFrontBack() {308 static_assert(!FrontInvocable<InputRange>);309 static_assert( FrontInvocable<ForwardRange>);310 static_assert(!BackInvocable<ForwardRange>);311 static_assert( BackInvocable<RARange>);312 313 ForwardRange forwardRange;314 assert(forwardRange.front() == 0);315 assert(static_cast<ForwardRange const&>(forwardRange).front() == 0);316 forwardRange.front() = 2;317 assert(forwardRange.front() == 2);318 319 RARange randomAccess;320 assert(randomAccess.front() == 0);321 assert(static_cast<RARange const&>(randomAccess).front() == 0);322 randomAccess.front() = 2;323 assert(randomAccess.front() == 2);324 325 assert(randomAccess.back() == 7);326 assert(static_cast<RARange const&>(randomAccess).back() == 7);327 randomAccess.back() = 2;328 assert(randomAccess.back() == 2);329 330 return true;331}332 333struct V1 : std::ranges::view_interface<V1> { };334struct V2 : std::ranges::view_interface<V2> { V1 base_; };335static_assert(sizeof(V2) == sizeof(V1));336 337int main(int, char**) {338 testEmpty();339 static_assert(testEmpty());340 341 testData();342 static_assert(testData());343 344 testSize();345 static_assert(testSize());346 347 testSubscript();348 static_assert(testSubscript());349 350 testFrontBack();351 static_assert(testFrontBack());352 353 return 0;354}355