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