215 lines
6.5 KiB
C++
215 lines
6.5 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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;
|
|
}
|