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

82 lines
1.9 KiB
C++

#pragma once
#include <concepts>
#include <cstddef>
#include <ranges>
#include <xutility>
namespace util {
namespace rg = std::ranges;
namespace detail {
template <std::invocable F> struct generated_iterator {
using value_type = decltype(std::declval<F>()());
using reference = value_type &;
using difference_type = std::ptrdiff_t;
value_type value{};
F generator{};
generated_iterator() = default;
generated_iterator(const F &gen) : generator(gen), value(gen()) {}
generated_iterator(F &&gen) : generator(std::move(gen)), value(gen()) {}
auto generate_new_value() -> void { value = generator(); }
constexpr auto operator==(const generated_iterator &other) const {
return false;
}
auto operator++(int) -> generated_iterator {
const auto result = *this;
++(*this);
return result;
}
auto operator++() -> generated_iterator & {
generate_new_value();
return (*this);
}
auto operator*() { return value; }
auto operator*() const { return value; }
};
} // namespace detail
template <std::invocable F>
class generated_view : rg::view_interface<generated_view<F>> {
F generator;
public:
generated_view() = default;
constexpr generated_view(F &&generator) : generator(generator) {}
constexpr auto begin() const { return detail::generated_iterator(generator); }
constexpr auto end() const { return std::unreachable_sentinel; }
};
namespace detail {
struct generated_range_adaptor_closure {
template <std::invocable F> constexpr auto operator()(F &&fn) const {
return generated_view(std::forward<F>(fn));
}
};
struct generated_range_adaptor {
template <std::invocable F> constexpr auto operator()(F &&r) {
return generated_view(std::forward<F>(r));
}
constexpr auto operator()() { return generated_range_adaptor_closure(); }
};
} // namespace detail
namespace views {
inline detail::generated_range_adaptor_closure from;
}
} // namespace util