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