enumerate fix
This commit is contained in:
parent
0930d32fd1
commit
cac97fe59d
|
@ -2,125 +2,253 @@
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <type_traits>
|
||||||
#include <xutility>
|
#include <xutility>
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
namespace rg = std::ranges;
|
namespace rg = std::ranges;
|
||||||
|
|
||||||
template <rg::range R> struct enumerate_iterator_t {
|
template <class R>
|
||||||
using base = rg::iterator_t<R>;
|
concept simple_view = // exposition only
|
||||||
using enumerator_type = std::size_t;
|
rg::view<R> && rg::range<const R> &&
|
||||||
using value_type = std::pair<enumerator_type, rg::range_value_t<R>>;
|
std::same_as<std::ranges::iterator_t<R>,
|
||||||
using difference_type = std::ptrdiff_t;
|
std::ranges::iterator_t<const R>> &&
|
||||||
using reference =
|
std::same_as<std::ranges::sentinel_t<R>, std::ranges::sentinel_t<const R>>;
|
||||||
std::pair<enumerator_type, std::remove_cv_t<rg::range_reference_t<R>>>;
|
|
||||||
|
|
||||||
base base_iter{};
|
template <rg::input_range R>
|
||||||
enumerator_type enumerator{};
|
requires(rg::view<R>) class enumerate_view
|
||||||
|
: public rg::view_interface<enumerate_view<R>> {
|
||||||
|
private:
|
||||||
|
R base_ = R();
|
||||||
|
|
||||||
enumerate_iterator_t() = default;
|
public:
|
||||||
enumerate_iterator_t(const base &b) : base_iter{b}, enumerator(0) {}
|
template <bool Const> class iterator;
|
||||||
enumerate_iterator_t(base &&b) : base_iter{std::move(b)}, enumerator(0) {}
|
template <bool Const> class sentinel;
|
||||||
|
|
||||||
auto constexpr operator==(const enumerate_iterator_t &other) const -> bool {
|
constexpr enumerate_view() = default;
|
||||||
return base_iter == other.base_iter;
|
constexpr enumerate_view(R base) : base_(std::move(base)) {}
|
||||||
|
|
||||||
|
constexpr auto size() -> rg::range_difference_t<R>
|
||||||
|
requires(rg::sized_range<R>) { return rg::size(base_); }
|
||||||
|
constexpr auto size() const -> rg::range_difference_t<R>
|
||||||
|
requires(rg::sized_range<const R>) { return rg::size(base_); }
|
||||||
|
|
||||||
|
constexpr auto begin() -> iterator<false> {
|
||||||
|
return iterator<false>{rg::begin(base_), 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::sentinel_for<base> S>
|
constexpr auto begin() const -> iterator<true> {
|
||||||
auto constexpr operator==(const S &sentinel) const -> bool {
|
return iterator<true>{rg::begin(base_), 0};
|
||||||
return sentinel == base_iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr operator<=>(const enumerate_iterator_t &other) const {
|
constexpr auto end() { return sentinel<false>(rg::end(base_)); }
|
||||||
return base_iter <=> other.base_iter;
|
|
||||||
|
constexpr auto end() requires(rg::common_range<R> &&rg::sized_range<R>) {
|
||||||
|
return iterator<false>{rg::end(base_),
|
||||||
|
static_cast<rg::range_difference_t<R>>(size())};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto inc_enumerator() -> void { enumerator++; }
|
constexpr auto end() const requires(rg::range<const R>) {
|
||||||
auto dec_enumerator() -> void { enumerator--; }
|
return sentinel<true>{rg::end(base_)};
|
||||||
auto dec_enumerator(const difference_type &n) -> void { enumerator -= n; }
|
|
||||||
|
|
||||||
auto operator++(int) -> enumerate_iterator_t {
|
|
||||||
const auto result = *this;
|
|
||||||
base_iter++;
|
|
||||||
inc_enumerator();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator++() -> enumerate_iterator_t & {
|
constexpr auto end() const
|
||||||
inc_enumerator();
|
requires(rg::common_range<const R> &&rg::sized_range<R>) {
|
||||||
++base_iter;
|
return iterator<true>{rg::end(base_),
|
||||||
return (*this);
|
static_cast<rg::range_difference_t<R>>(size())};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator--(int) -> enumerate_iterator_t
|
constexpr auto base() const -> R &requires(std::copy_constructible<R>) {
|
||||||
requires(std::bidirectional_iterator<base>) {
|
return base_;
|
||||||
const auto result = *this;
|
}
|
||||||
base_iter--;
|
constexpr auto base() -> R && { return std::move(base_); }
|
||||||
dec_enumerator();
|
};
|
||||||
return result;
|
|
||||||
|
template <class R> enumerate_view(R &&) -> enumerate_view<std::views::all_t<R>>;
|
||||||
|
|
||||||
|
template <rg::input_range R>
|
||||||
|
requires(rg::view<R>) template <bool Const> class enumerate_view<R>::iterator {
|
||||||
|
public:
|
||||||
|
using Base = std::conditional_t<Const, const R, R>;
|
||||||
|
using iterator_type = rg::iterator_t<Base>;
|
||||||
|
using iterator_category =
|
||||||
|
typename std::iterator_traits<iterator_type>::iterator_category;
|
||||||
|
using iterator_concept = iterator_category;
|
||||||
|
|
||||||
|
using difference_type = typename rg::range_difference_t<Base>;
|
||||||
|
using enumerator_type = difference_type;
|
||||||
|
|
||||||
|
struct result {
|
||||||
|
const enumerator_type index;
|
||||||
|
rg::range_reference_t<Base> value;
|
||||||
|
};
|
||||||
|
|
||||||
|
using reference = result;
|
||||||
|
using value_type = result;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enumerator_type index_ = {};
|
||||||
|
iterator_type base_ = iterator_type();
|
||||||
|
|
||||||
|
iterator() = default;
|
||||||
|
constexpr explicit iterator(iterator_type base, enumerator_type index = 0)
|
||||||
|
: base_(std::move(base)), index_(index) {}
|
||||||
|
constexpr iterator(iterator<!Const> i) requires Const
|
||||||
|
&& std::convertible_to<rg::iterator_t<R>, rg::iterator_t<Base>>
|
||||||
|
: base_(std::move(i.base_)), index_(std::move(i.index_)) {}
|
||||||
|
|
||||||
|
constexpr rg::iterator_t<Base>
|
||||||
|
base() const &requires std::copyable<rg::iterator_t<Base>> {
|
||||||
|
return base_;
|
||||||
|
}
|
||||||
|
constexpr rg::iterator_t<Base> base() && { return std::move(base_); }
|
||||||
|
|
||||||
|
constexpr decltype(auto) operator*() const { return result{index_, *base_}; }
|
||||||
|
|
||||||
|
constexpr auto operator++() -> iterator & {
|
||||||
|
++index_;
|
||||||
|
++base_;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator--()
|
constexpr auto operator++(int) -> void requires(!rg::forward_range<Base>) {
|
||||||
-> enumerate_iterator_t &requires(std::bidirectional_iterator<base>) {
|
++index_;
|
||||||
dec_enumerator();
|
++base_;
|
||||||
--base_iter;
|
|
||||||
return (*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr operator+(const difference_type &n) const
|
constexpr auto operator++(int) -> iterator requires(rg::forward_range<Base>) {
|
||||||
-> enumerate_iterator_t {
|
const auto tmp = *this;
|
||||||
auto ret = *this;
|
++index_;
|
||||||
ret.inc_enumerator(n);
|
++base_;
|
||||||
base_iter += n;
|
return tmp;
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator*() -> reference { return reference(enumerator, *base_iter); }
|
constexpr auto operator--()
|
||||||
auto operator*() const -> reference {
|
-> iterator &requires(rg::bidirectional_range<Base>) {
|
||||||
return reference(enumerator, *base_iter);
|
--index_;
|
||||||
|
--base_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto operator--(int) -> iterator
|
||||||
|
requires(rg::bidirectional_range<Base>) {
|
||||||
|
const auto tmp = *this;
|
||||||
|
--index_;
|
||||||
|
--base_;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto operator+=(difference_type n)
|
||||||
|
-> iterator &requires(rg::random_access_range<Base>) {
|
||||||
|
index_ += n;
|
||||||
|
base_ += n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto operator-=(difference_type n)
|
||||||
|
-> iterator &requires(rg::random_access_range<Base>) {
|
||||||
|
index_ -= n;
|
||||||
|
base_ -= n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr auto operator==(const iterator &lhs, const iterator &rhs)
|
||||||
|
-> bool requires(std::equality_comparable<rg::iterator_t<Base>>) {
|
||||||
|
return lhs.base_ == rhs.base_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr auto operator<(const iterator &lhs, const iterator &rhs)
|
||||||
|
-> bool requires(rg::random_access_range<Base>) {
|
||||||
|
return lhs.base_ < rhs.base_;
|
||||||
|
}
|
||||||
|
friend constexpr auto operator>(const iterator &lhs, const iterator &rhs)
|
||||||
|
-> bool requires(rg::random_access_range<Base>) {
|
||||||
|
return rhs < lhs;
|
||||||
|
}
|
||||||
|
friend constexpr auto operator<=(const iterator &lhs, const iterator &rhs)
|
||||||
|
-> bool requires(rg::random_access_range<Base>) {
|
||||||
|
return !(rhs < lhs);
|
||||||
|
}
|
||||||
|
friend constexpr auto operator>=(const iterator &lhs, const iterator &rhs)
|
||||||
|
-> bool requires(rg::random_access_range<Base>) {
|
||||||
|
return !(lhs < rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr auto operator<=>(
|
||||||
|
const iterator &lhs,
|
||||||
|
const iterator &rhs) requires(std::three_way_comparable<iterator_type>) {
|
||||||
|
return lhs.base_ <=> rhs.base_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr auto operator+(const iterator &lhs, difference_type n)
|
||||||
|
-> iterator requires(rg::random_access_range<Base>) {
|
||||||
|
return iterator{lhs} + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr auto operator+(difference_type n, const iterator &rhs)
|
||||||
|
-> iterator requires(rg::random_access_range<Base>) {
|
||||||
|
return n + rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr auto operator-(const iterator &lhs, difference_type n)
|
||||||
|
-> iterator requires(rg::random_access_range<Base>) {
|
||||||
|
return iterator{lhs} -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr auto operator-(const iterator &lhs, const iterator &rhs)
|
||||||
|
-> iterator requires(rg::random_access_range<Base>) {
|
||||||
|
return lhs.base_ - rhs.base_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <rg::range R>
|
template <rg::input_range R>
|
||||||
class enumerate_view : public rg::view_interface<enumerate_view<R>> {
|
requires(rg::view<R>) template <bool Const> class enumerate_view<R>::sentinel {
|
||||||
isize enumerator{};
|
private:
|
||||||
enumerate_iterator_t<R> iter_;
|
using Base = std::conditional_t<Const, const R, R>;
|
||||||
enumerate_iterator_t<R> end_;
|
rg::sentinel_t<Base> end_ = rg::sentinel_t<Base>();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enumerate_view() = default;
|
sentinel() = default;
|
||||||
|
constexpr explicit sentinel(rg::sentinel_t<Base> end) : end_(end) {}
|
||||||
|
constexpr sentinel(sentinel<!Const> other) requires Const
|
||||||
|
&& std::convertible_to<rg::sentinel_t<R>, rg::sentinel_t<Base>>
|
||||||
|
: end_(std::move(other.end_)) {}
|
||||||
|
|
||||||
constexpr enumerate_view(R base)
|
constexpr auto base() const -> rg::sentinel_t<Base> { return end_; }
|
||||||
: iter_(std::begin(base)), end_(std::end(base)) {}
|
|
||||||
|
|
||||||
constexpr auto begin() const { return iter_; }
|
friend constexpr auto operator==(const iterator<Const> &rhs,
|
||||||
constexpr auto end() const { return end_; }
|
const sentinel &lhs) -> bool {
|
||||||
|
return rhs.base_ == lhs.end_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr auto operator-(const iterator<Const> &rhs,
|
||||||
|
const sentinel &lhs)
|
||||||
|
-> rg::range_difference_t<Base> {
|
||||||
|
return rhs.base_ - lhs.end_;
|
||||||
|
}
|
||||||
|
friend constexpr auto operator-(const sentinel &rhs,
|
||||||
|
const iterator<Const> &lhs)
|
||||||
|
-> rg::range_difference_t<Base> {
|
||||||
|
return rhs.end_ - lhs.base_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
struct enumerate_range_adaptor_closure {
|
|
||||||
template <rg::viewable_range R> constexpr auto operator()(R &&r) const {
|
struct enumerate_view_adaptor {
|
||||||
return enumerate_view(std::forward<R>(r));
|
template <typename R> constexpr auto operator()(R &&r) const {
|
||||||
|
return enumerate_view{std::move(r)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <rg::range R>
|
||||||
|
constexpr friend auto operator|(R &&rng, const enumerate_view_adaptor &) {
|
||||||
|
return enumerate_view{std::move(rng)};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct enumerate_range_adaptor {
|
|
||||||
template <rg::viewable_range R> constexpr auto operator()(R &&r) {
|
|
||||||
return enumerate_view(std::forward<R>(r));
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr auto operator()() { return enumerate_range_adaptor_closure(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <rg::viewable_range R>
|
|
||||||
constexpr auto operator|(R &&r, enumerate_range_adaptor_closure const &a) {
|
|
||||||
return a(std::forward<R>(r));
|
|
||||||
}
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
namespace views {
|
namespace views {
|
||||||
inline detail::enumerate_range_adaptor_closure enumerate;
|
inline detail::enumerate_view_adaptor enumerate;
|
||||||
} // namespace views
|
} // namespace views
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
Loading…
Reference in a new issue