extract generator code into library
This commit is contained in:
71
lib/include/aocpp/Generator.hpp
Normal file
71
lib/include/aocpp/Generator.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef AOCPP_GENERATOR_HPP_
|
||||
#define AOCPP_GENERATOR_HPP_
|
||||
|
||||
#include <exception>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#if __has_include(<coroutine>)
|
||||
#include <coroutine>
|
||||
namespace co = std;
|
||||
#elif __has_include(<experimental/coroutine>)
|
||||
#include <experimental/coroutine>
|
||||
namespace co = std::experimental;
|
||||
#endif
|
||||
|
||||
namespace aocpp {
|
||||
|
||||
template <typename T>
|
||||
class Generator
|
||||
{
|
||||
public:
|
||||
struct promise_type;
|
||||
|
||||
private:
|
||||
using handle_type = co::coroutine_handle<promise_type>;
|
||||
handle_type h_;
|
||||
|
||||
public:
|
||||
struct promise_type
|
||||
{
|
||||
std::optional<T> value_;
|
||||
std::exception_ptr exception_;
|
||||
|
||||
Generator get_return_object()
|
||||
{
|
||||
return Generator{handle_type::from_promise(*this)};
|
||||
}
|
||||
co::suspend_always initial_suspend() { return {}; }
|
||||
co::suspend_always final_suspend() noexcept { return {}; }
|
||||
void unhandled_exception() { exception_ = std::current_exception(); }
|
||||
|
||||
template <std::convertible_to<T> From> // C++20 concept
|
||||
std::suspend_always yield_value(From&& from)
|
||||
{
|
||||
value_ = std::forward<From>(from); // caching the result in promise
|
||||
return {};
|
||||
}
|
||||
void return_void() { value_.reset(); }
|
||||
};
|
||||
|
||||
public:
|
||||
Generator() noexcept = default;
|
||||
Generator(handle_type h) : h_(h) {}
|
||||
Generator(Generator && g) : h_{g.h_} { g.h_ = nullptr; };
|
||||
Generator(Generator const& g) = delete;
|
||||
Generator & operator=(Generator && rhs) = delete;
|
||||
Generator & operator=(Generator const& rhs) = delete;
|
||||
~Generator() { if (h_) h_.destroy(); }
|
||||
std::optional<T> operator()()
|
||||
{
|
||||
h_();
|
||||
if (h_.promise().exception_) {
|
||||
std::rethrow_exception(h_.promise().exception_);
|
||||
}
|
||||
return std::move(h_.promise().value_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // AOCPP_GENERATOR_HPP_
|
Reference in New Issue
Block a user