#pragma once #include #include namespace alpaqa::util { template struct enumerate_t : std::ranges::view_interface> { Rng rng; // P2325R3: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2325r3.html enumerate_t() = default; enumerate_t(Rng rng) : rng{std::forward(rng)} {} using begin_t = decltype(std::ranges::begin(std::as_const(rng))); using end_t = decltype(std::ranges::end(std::as_const(rng))); struct sentinel_t { end_t it; }; struct iter_t { // P2325R3: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2325r3.html iter_t() = default; iter_t(begin_t &&it) : it{std::forward(it)} {} using index_t = std::ranges::range_difference_t; index_t index{}; begin_t it; using difference_type = std::ptrdiff_t; using value_type = std::tuple; bool operator!=(sentinel_t s) const { return s.it != it; } bool operator==(sentinel_t s) const { return s.it == it; } // TODO: For Clang bug friend bool operator!=(sentinel_t s, const iter_t &i) { return i != s; } friend bool operator==(sentinel_t s, const iter_t &i) { return i == s; } iter_t &operator++() { ++it; ++index; return *this; } iter_t operator++(int) const { auto tmp = *this; ++*this; return tmp; } value_type operator*() const { return {index, *it}; } }; auto begin() const -> std::input_or_output_iterator auto{ return iter_t{std::ranges::begin(rng)}; } auto end() const // -> std::sentinel_for auto { return sentinel_t{std::ranges::end(rng)}; } }; template auto enumerate(Rng &&rng) { return enumerate_t>{std::forward(rng)}; } } // namespace alpaqa::util