Commit c330ac55 authored by Xavier Thompson's avatar Xavier Thompson

Refactor future.hpp

parent 153bf460
...@@ -6,115 +6,17 @@ ...@@ -6,115 +6,17 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <typon/fundamental/meta.hpp>
#include <typon/fundamental/scope.hpp>
#include <typon/result.hpp> #include <typon/result.hpp>
namespace typon::rt namespace typon::rt
{ {
template <typename Promise>
using value_type = typename Promise::value_type;
template <typename P>
concept Void = std::is_void_v<value_type<P>>;
template <typename P>
concept Reference = std::is_reference_v<value_type<P>>;
template <typename P>
concept Complete = !Void<P> && !Reference<P>;
template <typename P>
concept Small = sizeof(value_type<P>) <= 2 * sizeof(void*);
template <typename P>
concept TriviallyCopyable = std::is_trivially_copyable_v<value_type<P>>;
struct CoroutineGuard
{
std::coroutine_handle<> _coroutine;
~CoroutineGuard()
{
_coroutine.destroy();
}
};
template <typename Promise> template <typename Promise>
struct Future struct Future
{
template <typename T>
struct always_false
{
static constexpr bool value { false };
};
static_assert(always_false<Promise>::value, "Unexpected Promise type for Future");
};
template <typename Promise>
requires Complete<Promise> && (!Small<Promise>)
struct Future<Promise>
{
std::coroutine_handle<Promise> _coroutine;
bool _owning;
Future(std::coroutine_handle<Promise> coroutine, bool ready)
{
_coroutine = coroutine;
_owning = ready;
if (ready)
{
if (coroutine.promise()._exception)
{
std::rethrow_exception(coroutine.promise()._exception);
}
}
}
Future(const Future &) = delete;
Future& operator=(const Future &) = delete;
Future(Future && other) noexcept
: _coroutine(other._coroutine)
, _owning(std::exchange(other._owning, false))
{}
Future& operator=(Future && other) noexcept
{
std::swap(_owning, other._owning);
std::swap(_coroutine, other._coroutine);
return *this;
}
~Future()
{
if (_owning)
{
_coroutine.destroy();
}
}
auto get()
{
return _coroutine.promise().get();
}
};
template <typename Promise>
requires Complete<Promise> && Small<Promise> && (!TriviallyCopyable<Promise>)
struct Future<Promise>
{ {
using value_type = typename Promise::value_type; using value_type = typename Promise::value_type;
...@@ -128,7 +30,7 @@ namespace typon::rt ...@@ -128,7 +30,7 @@ namespace typon::rt
{ {
if (ready) if (ready)
{ {
CoroutineGuard guard { coroutine }; fdt::defer defer { [&coroutine]() { coroutine.destroy(); } };
std::construct_at(&(_result), coroutine.promise().get()); std::construct_at(&(_result), coroutine.promise().get());
} }
else else
...@@ -182,7 +84,58 @@ namespace typon::rt ...@@ -182,7 +84,58 @@ namespace typon::rt
template <typename Promise> template <typename Promise>
requires Complete<Promise> && Small<Promise> && TriviallyCopyable<Promise> requires requires { sizeof(typename Promise::value_type); }
&& (sizeof(typename Promise::value_type) > 2 * sizeof(void*))
struct Future<Promise>
{
std::coroutine_handle<Promise> _coroutine;
bool _owning;
Future(std::coroutine_handle<Promise> coroutine, bool ready)
{
_coroutine = coroutine;
_owning = ready;
if (ready)
{
if (coroutine.promise()._exception)
{
std::rethrow_exception(coroutine.promise()._exception);
}
}
}
Future(const Future &) = delete;
Future& operator=(const Future &) = delete;
Future(Future && other) noexcept
: _coroutine(other._coroutine)
, _owning(std::exchange(other._owning, false))
{}
Future& operator=(Future && other) noexcept
{
std::swap(_owning, other._owning);
std::swap(_coroutine, other._coroutine);
return *this;
}
~Future()
{
if (_owning)
{
_coroutine.destroy();
}
}
auto get()
{
return _coroutine.promise().get();
}
};
template <typename Promise>
requires std::is_trivially_copyable_v<typename Promise::value_type>
struct Future<Promise> struct Future<Promise>
{ {
using value_type = typename Promise::value_type; using value_type = typename Promise::value_type;
...@@ -197,7 +150,7 @@ namespace typon::rt ...@@ -197,7 +150,7 @@ namespace typon::rt
{ {
if (ready) if (ready)
{ {
CoroutineGuard guard { coroutine }; fdt::defer defer { [&coroutine]() { coroutine.destroy(); } };
std::construct_at(&(_result), coroutine.promise().get()); std::construct_at(&(_result), coroutine.promise().get());
} }
else else
...@@ -206,6 +159,9 @@ namespace typon::rt ...@@ -206,6 +159,9 @@ namespace typon::rt
} }
} }
Future(Future && other) = default;
Future& operator=(Future && other) = default;
~Future() ~Future()
{ {
if (!_coroutine) if (!_coroutine)
...@@ -225,7 +181,8 @@ namespace typon::rt ...@@ -225,7 +181,8 @@ namespace typon::rt
}; };
template <Reference Promise> template <typename Promise>
requires std::is_reference_v<typename Promise::value_type>
struct Future<Promise> struct Future<Promise>
{ {
using value_type = typename Promise::value_type; using value_type = typename Promise::value_type;
...@@ -237,7 +194,7 @@ namespace typon::rt ...@@ -237,7 +194,7 @@ namespace typon::rt
{ {
if (ready) if (ready)
{ {
CoroutineGuard guard { coroutine }; fdt::defer defer { [&coroutine]() { coroutine.destroy(); } };
_result = std::addressof(coroutine.promise().get()); _result = std::addressof(coroutine.promise().get());
} }
else else
...@@ -257,7 +214,8 @@ namespace typon::rt ...@@ -257,7 +214,8 @@ namespace typon::rt
}; };
template <Void Promise> template <typename Promise>
requires std::is_void_v<typename Promise::value_type>
struct Future<Promise> struct Future<Promise>
{ {
using value_type = typename Promise::value_type; using value_type = typename Promise::value_type;
...@@ -268,7 +226,7 @@ namespace typon::rt ...@@ -268,7 +226,7 @@ namespace typon::rt
{ {
if (ready) if (ready)
{ {
CoroutineGuard guard { coroutine }; fdt::defer defer { [&coroutine]() { coroutine.destroy(); } };
coroutine.promise().get(); coroutine.promise().get();
} }
else else
......
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