215 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<bool OtherConst>12// requires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>13// friend constexpr range_difference_t<maybe-const<OtherConst, V>>14// operator-(const iterator<OtherConst>& x, const sentinel& y);15//16// template<bool OtherConst>17// requires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>18// friend constexpr range_difference_t<maybe-const<OtherConst, V>>19// operator-(const sentinel& x, const iterator<OtherConst>& y);20 21#include <cassert>22#include <concepts>23#include <cstddef>24#include <functional>25#include <ranges>26#include <tuple>27 28#include "../types.h"29 30template <bool Const>31struct Iter {32 std::tuple<int>* it_;33 34 using value_type = std::tuple<int>;35 using difference_type = std::ptrdiff_t;36 using iterator_concept = std::input_iterator_tag;37 38 constexpr decltype(auto) operator*() const { return *it_; }39 constexpr Iter& operator++() {40 ++it_;41 return *this;42 }43 constexpr void operator++(int) { ++it_; }44};45 46template <bool Const>47struct Sent {48 std::tuple<int>* end_;49 50 constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }51};52 53template <bool Const>54struct SizedSent {55 std::tuple<int>* end_;56 57 constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }58 59 friend constexpr auto operator-(const SizedSent& st, const Iter<Const>& it) { return st.end_ - it.it_; }60 61 friend constexpr auto operator-(const Iter<Const>& it, const SizedSent& st) { return it.it_ - st.end_; }62};63 64template <bool Const>65struct CrossSizedSent {66 std::tuple<int>* end_;67 68 template <bool C>69 constexpr bool operator==(const Iter<C>& i) const {70 return i.it_ == end_;71 }72 73 template <bool C>74 friend constexpr auto operator-(const CrossSizedSent& st, const Iter<C>& it) {75 return st.end_ - it.it_;76 }77 78 template <bool C>79 friend constexpr auto operator-(const Iter<C>& it, const CrossSizedSent& st) {80 return it.it_ - st.end_;81 }82};83 84template <template <bool> class It, template <bool> class St>85struct Range : TupleBufferView {86 using TupleBufferView::TupleBufferView;87 88 using iterator = It<false>;89 using sentinel = St<false>;90 using const_iterator = It<true>;91 using const_sentinel = St<true>;92 93 constexpr iterator begin() { return {buffer_}; }94 constexpr const_iterator begin() const { return {buffer_}; }95 constexpr sentinel end() { return sentinel{buffer_ + size_}; }96 constexpr const_sentinel end() const { return const_sentinel{buffer_ + size_}; }97};98 99template <class T, class U>100concept HasMinus = requires(const T t, const U u) { t - u; };101 102template <class BaseRange>103using ElementsView = std::ranges::elements_view<BaseRange, 0>;104 105template <class BaseRange>106using ElemIter = std::ranges::iterator_t<ElementsView<BaseRange>>;107 108template <class BaseRange>109using EleConstIter = std::ranges::iterator_t<const ElementsView<BaseRange>>;110 111template <class BaseRange>112using EleSent = std::ranges::sentinel_t<ElementsView<BaseRange>>;113 114template <class BaseRange>115using EleConstSent = std::ranges::sentinel_t<const ElementsView<BaseRange>>;116 117constexpr void testConstraints() {118 // base is not sized119 {120 using Base = Range<Iter, Sent>;121 static_assert(!HasMinus<EleSent<Base>, ElemIter<Base>>);122 static_assert(!HasMinus<ElemIter<Base>, EleSent<Base>>);123 124 static_assert(!HasMinus<EleSent<Base>, EleConstIter<Base>>);125 static_assert(!HasMinus<EleConstIter<Base>, EleSent<Base>>);126 127 static_assert(!HasMinus<EleConstSent<Base>, EleConstIter<Base>>);128 static_assert(!HasMinus<EleConstIter<Base>, EleConstSent<Base>>);129 130 static_assert(!HasMinus<EleConstSent<Base>, ElemIter<Base>>);131 static_assert(!HasMinus<ElemIter<Base>, EleConstSent<Base>>);132 }133 134 // base is sized but not cross const135 {136 using Base = Range<Iter, SizedSent>;137 static_assert(HasMinus<EleSent<Base>, ElemIter<Base>>);138 static_assert(HasMinus<ElemIter<Base>, EleSent<Base>>);139 140 static_assert(!HasMinus<EleSent<Base>, EleConstIter<Base>>);141 static_assert(!HasMinus<EleConstIter<Base>, EleSent<Base>>);142 143 static_assert(HasMinus<EleConstSent<Base>, EleConstIter<Base>>);144 static_assert(HasMinus<EleConstIter<Base>, EleConstSent<Base>>);145 146 static_assert(!HasMinus<EleConstSent<Base>, ElemIter<Base>>);147 static_assert(!HasMinus<ElemIter<Base>, EleConstSent<Base>>);148 }149 150 // base is cross const sized151 {152 using Base = Range<Iter, CrossSizedSent>;153 static_assert(HasMinus<EleSent<Base>, ElemIter<Base>>);154 static_assert(HasMinus<ElemIter<Base>, EleSent<Base>>);155 156 static_assert(HasMinus<EleSent<Base>, EleConstIter<Base>>);157 static_assert(HasMinus<EleConstIter<Base>, EleSent<Base>>);158 159 static_assert(HasMinus<EleConstSent<Base>, EleConstIter<Base>>);160 static_assert(HasMinus<EleConstIter<Base>, EleConstSent<Base>>);161 162 static_assert(HasMinus<EleConstSent<Base>, ElemIter<Base>>);163 static_assert(HasMinus<ElemIter<Base>, EleConstSent<Base>>);164 }165}166 167constexpr bool test() {168 std::tuple<int> buffer[] = {{1}, {2}, {3}, {4}, {5}};169 170 // base is sized but not cross const171 {172 using Base = Range<Iter, SizedSent>;173 Base base{buffer};174 auto ev = base | std::views::elements<0>;175 auto iter = ev.begin();176 auto const_iter = std::as_const(ev).begin();177 auto sent = ev.end();178 auto const_sent = std::as_const(ev).end();179 180 assert(iter - sent == -5);181 assert(sent - iter == 5);182 assert(const_iter - const_sent == -5);183 assert(const_sent - const_iter == 5);184 }185 186 // base is cross const sized187 {188 using Base = Range<Iter, CrossSizedSent>;189 Base base{buffer};190 auto ev = base | std::views::elements<0>;191 auto iter = ev.begin();192 auto const_iter = std::as_const(ev).begin();193 auto sent = ev.end();194 auto const_sent = std::as_const(ev).end();195 196 assert(iter - sent == -5);197 assert(sent - iter == 5);198 assert(iter - const_sent == -5);199 assert(const_sent - iter == 5);200 assert(const_iter - sent == -5);201 assert(sent - const_iter == 5);202 assert(const_iter - const_sent == -5);203 assert(const_sent - const_iter == 5);204 }205 206 return true;207}208 209int main(int, char**) {210 test();211 static_assert(test());212 213 return 0;214}215