extract generator code into library

This commit is contained in:
2023-04-02 15:30:34 -07:00
parent 4d884d7b1c
commit 9b4c881903
2 changed files with 80 additions and 43 deletions

View 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_