// Datei coro_04

#ifndef coro_04_h
#define coro_04_h

#include <coroutine>

// Die Coroutinen-Klasse
template <typename T = int>
struct MyCoroutine
{
    struct promise_type;
    using handle = std::coroutine_handle<promise_type>;
    // promise_type Klasse
    struct promise_type
    {
        // Letzter aus der Coroutine zurueckgegebener Wert
        T saved_value;
        // Mit co_yield zurueckgegebener Wert
        T act_value;
        // Aufruf unmittelbar nach Start der Coroutine
        auto initial_suspend()
        {
            return std::suspend_always{};
        }
        // Aufruf nach Beenden der Coroutine
        auto final_suspend() noexcept
        {
            return std::suspend_always{};
        }
        // Aufruf beim Ausloesen einer nicht behandelten
        // Ausnahme
        void unhandled_exception()
        {
            std::terminate();
        }
        // Liefert das Coroutinen-Objekt zurueck
        auto get_return_object()
        {
            return MyCoroutine{ handle::from_promise(*this) };
        }

        // Aufruf durch co_return;
        void return_void()
        { }
        // Aufruf durch co_yield DATUM;
        auto yield_value(T value)
        {
            act_value = value;
            return std::suspend_always{};
        }
    };
    // Setzt die Ausfuehrung der Coroutine fort (coro.resume()),
    // wenn das Coroutinen-Handle gueltig ist (ungleich 0)
    bool resume()
    {
        return coro ? (coro.resume(), !coro.done()) : false;
    }
    // const-Referenz auf das co_return Datum zurueckgeben
    const T& GetValue() const
    {
        return coro.promise().saved_value;
    }
    // const-Referenz auf das co_yield Datum zurueckgeben
    const T& GetActValue() const
    {
        return coro.promise().act_value;
    }
private:
    // Coroutinen-Handle
    handle coro;
    // ctor, speichert das uebergebene Coroutinen-Handle ab
    MyCoroutine(handle h) : coro(h)
    {
    }
};
#endif
