Commit c330ac55 authored by Xavier Thompson's avatar Xavier Thompson

Refactor future.hpp

parent 153bf460
......@@ -6,115 +6,17 @@
#include <type_traits>
#include <utility>
#include <typon/fundamental/meta.hpp>
#include <typon/fundamental/scope.hpp>
#include <typon/result.hpp>
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>
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;
......@@ -128,7 +30,7 @@ namespace typon::rt
{
if (ready)
{
CoroutineGuard guard { coroutine };
fdt::defer defer { [&coroutine]() { coroutine.destroy(); } };
std::construct_at(&(_result), coroutine.promise().get());
}
else
......@@ -182,7 +84,58 @@ namespace typon::rt
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>
{
using value_type = typename Promise::value_type;
......@@ -197,7 +150,7 @@ namespace typon::rt
{
if (ready)
{
CoroutineGuard guard { coroutine };
fdt::defer defer { [&coroutine]() { coroutine.destroy(); } };
std::construct_at(&(_result), coroutine.promise().get());
}
else
......@@ -206,6 +159,9 @@ namespace typon::rt
}
}
Future(Future && other) = default;
Future& operator=(Future && other) = default;
~Future()
{
if (!_coroutine)
......@@ -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>
{
using value_type = typename Promise::value_type;
......@@ -237,7 +194,7 @@ namespace typon::rt
{
if (ready)
{
CoroutineGuard guard { coroutine };
fdt::defer defer { [&coroutine]() { coroutine.destroy(); } };
_result = std::addressof(coroutine.promise().get());
}
else
......@@ -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>
{
using value_type = typename Promise::value_type;
......@@ -268,7 +226,7 @@ namespace typon::rt
{
if (ready)
{
CoroutineGuard guard { coroutine };
fdt::defer defer { [&coroutine]() { coroutine.destroy(); } };
coroutine.promise().get();
}
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