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