Commit 99d581e5 authored by Xavier Thompson's avatar Xavier Thompson

Add lazy coroutine task implementation

parents
#ifndef __COROUTINE_HPP__
#define __COROUTINE_HPP__
#if defined(__clang__) && __clang__
#include <experimental/coroutine>
namespace typon
{
using std::experimental::coroutine_handle;
using std::experimental::suspend_always;
using std::experimental::suspend_never;
using std::experimental::noop_coroutine;
}
#elif defined(__GNUC__) && __GNUC__
#include <coroutine>
namespace typon
{
using std::coroutine_handle;
using std::suspend_always;
using std::suspend_never;
using std::noop_coroutine;
}
#endif
#endif // __COROUTINE_HPP__
#ifndef __RESULT_HPP__
#define __RESULT_HPP__
#include <exception>
#include <memory>
#include <type_traits>
namespace typon
{
template <typename T>
struct result
{
std::exception_ptr _exception;
union
{
T _value;
};
~result()
{
if (!_exception)
{
std::destroy_at(std::addressof(_value));
}
}
template <typename U>
void return_value(U&& expr) noexcept(std::is_nothrow_constructible_v<T, U&&>)
{
std::construct_at(std::addressof(_value), std::forward<U>(expr));
}
void unhandled_exception() noexcept
{
_exception = std::current_exception();
}
T& get() &
{
if (_exception)
{
std::rethrow_exception(_exception);
}
return _value;
}
T&& get() &&
{
if (_exception)
{
std::rethrow_exception(_exception);
}
return std::move(_value);
}
};
template <typename T>
struct result<T&>
{
T* _value;
std::exception_ptr _exception;
void return_value(T& expr) noexcept
{
_value = std::addressof(expr);
}
void unhandled_exception() noexcept
{
_exception = std::current_exception();
}
T& get() &
{
if (_exception)
{
std::rethrow_exception(_exception);
}
return *_value;
}
};
template <>
struct result<void>
{
std::exception_ptr _exception;
void return_void() noexcept {}
void unhandled_exception() noexcept
{
_exception = std::current_exception();
}
void get()
{
if (_exception)
{
std::rethrow_exception(_exception);
}
}
};
}
#endif // __RESULT_HPP__
#ifndef __TASK_HPP__
#define __TASK_HPP__
#include <coroutine.hpp>
#include <result.hpp>
namespace typon
{
template <typename T = void>
struct [[nodiscard]] task
{
struct promise_type;
coroutine_handle<promise_type> _coroutine;
~task()
{
_coroutine.destroy();
}
struct promise_type : result<T>
{
coroutine_handle<> _continuation;
task get_return_object() noexcept
{
return { coroutine_handle<promise_type>::from_promise(*this) };
}
suspend_always initial_suspend() noexcept
{
return {};
}
auto final_suspend() noexcept
{
struct awaitable : suspend_always
{
coroutine_handle<> await_suspend(coroutine_handle<promise_type> coroutine) noexcept
{
return coroutine.promise()._continuation;
}
};
return awaitable {};
}
};
auto operator co_await() && noexcept
{
struct awaitable
{
coroutine_handle<promise_type> _coroutine;
bool await_ready() noexcept
{
return false;
}
coroutine_handle<> await_suspend(coroutine_handle<> awaiting_coroutine) noexcept
{
_coroutine.promise()._continuation = awaiting_coroutine;
return _coroutine;
}
decltype(auto) await_resume()
{
return _coroutine.promise().get();
}
};
return awaitable { _coroutine };
}
decltype(auto) call() &&
{
_coroutine.promise()._continuation = noop_coroutine();
_coroutine.resume();
return _coroutine.promise().get();
}
};
}
#endif // __TASK_HPP__
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment