cpp-utils/include/ranges/generated.hpp
2022-07-13 01:40:17 +01:00

102 lines
2.5 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;
// TODO: make 1 constructor that generates a value, move/copy value in all
// other constructors
generated_iterator() = default;
explicit generated_iterator(F &&gen)
: generator(std::move(gen)), value(gen()) {}
generated_iterator(const generated_iterator &other)
: generator(other.generator), value(other.value) {}
generated_iterator(generated_iterator &&other)
: generator(std::move(other.generator)), value(std::move(other.value)) {}
auto operator=(const generated_iterator &other) -> generated_iterator & {
generator = other.generator;
value = other.value;
return *this;
}
auto operator=(generated_iterator &&other) -> generated_iterator & {
generator = std::move(other.generator);
value = std::move(other.value);
return *this;
}
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>> {
detail::generated_iterator<F> iter_{};
public:
constexpr generated_view() = default;
constexpr generated_view(F generator)
: iter_(detail::generated_iterator(std::move(generator))) {}
constexpr auto begin() const { return iter_; }
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