102 lines
2.5 KiB
C++
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
|