cpp-utils/include/ranges/enumerate.hpp
2022-06-23 17:26:19 +01:00

91 lines
2.4 KiB
C++

#pragma once
#include "types.hpp"
#include <ranges>
namespace util {
namespace rg = std::ranges;
template <rg::range R> struct enumerate_iterator_t : rg::iterator_t<R> {
using base = rg::iterator_t<R>;
using enumerator_type = std::size_t;
using value_type = std::pair<enumerator_type, rg::range_value_t<R>>;
using reference =
std::pair<enumerator_type, std::remove_cv_t<rg::range_reference_t<R>>>;
enumerator_type enumerator{};
enumerate_iterator_t() = default;
enumerate_iterator_t(const base &b) : base{b}, enumerator(0) {}
auto operator<=>(const enumerate_iterator_t &other) const {
return static_cast<const base &>(*this) <=>
static_cast<const base &>(other);
}
auto inc_enumerator() -> void { enumerator++; }
auto operator++(int) -> enumerate_iterator_t {
const auto result = static_cast<base &>(*this)++;
inc_enumerator();
return result;
}
auto operator++() -> enumerate_iterator_t & {
inc_enumerator();
++static_cast<base &>(*this);
return (*this);
}
auto operator*() -> reference {
return reference(enumerator, *static_cast<base &>(*this));
}
auto operator*() const -> reference {
return reference(enumerator, *static_cast<const base &>(*this));
}
};
template <rg::range R>
class enumerate_view : public rg::view_interface<enumerate_view<R>> {
R base_{};
isize enumerator{};
enumerate_iterator_t<R> iter_{std::begin(base_)};
public:
enumerate_view() = default;
constexpr enumerate_view(R base) : base_(base), iter_(std::begin(base_)) {}
constexpr R base() const & { return base_; }
constexpr R base() && { return std::move(base_); }
constexpr auto begin() const { return iter_; }
constexpr auto end() const { return std::end(base_); }
};
namespace detail {
struct enumerate_range_adaptor_closure {
template <rg::viewable_range R> constexpr auto operator()(R &&r) const {
return enumerate_view(std::forward<R>(r));
}
};
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 views {
inline detail::enumerate_range_adaptor_closure enumerate;
} // namespace views
} // namespace util