[+] Coroutine interopability

This commit is contained in:
Reece Wilson 2023-07-08 12:31:49 +01:00
parent a0794a2cc9
commit fae92993be

View File

@ -7,6 +7,11 @@
***/
#pragma once
namespace __detail
{
struct FutureAccessor;
}
template<typename T, typename Error_t = void>
struct AuFuture : AuEnableSharedFromThis<AuFuture<T, Error_t>>
{
@ -174,12 +179,39 @@ public:
return pRet;
}
protected:
friend struct __detail::FutureAccessor;
CppFun<T>::B &GetValue()
{
return value;
}
bool WaitOn()
{
this->event->Wait();
return this->bComplete;
}
bool IsFinished()
{
return this->bComplete || this->bFailed;
}
AuThreading::IWaitable *GetWaitOnInterface()
{
return this->event.AsPointer();
}
private:
void SubmitComplete()
{
if (AuAsync::GetCurrentWorkerPId() == this->pid)
{
this->event->Set();
if (!this->onFailure && !this->callback)
{
DoWaterFalls();
@ -262,17 +294,23 @@ private:
AuDebug::DecMemoryCrunch();
}
AuFuture()
AuFuture() :
event(false, false, true)
{
this->pid = AuAsync::GetCurrentWorkerPId();
}
AuFuture(AuConsumer<Move_t> callback) : callback(callback)
AuFuture(AuConsumer<Move_t> callback) :
callback(callback),
event(false, false, true)
{
this->pid = AuAsync::GetCurrentWorkerPId();
}
AuFuture(AuConsumer<Move_t> callback, ErrorCallback_f onFailure) : callback(callback), onFailure(onFailure)
AuFuture(AuConsumer<Move_t> callback, ErrorCallback_f onFailure) :
callback(callback),
onFailure(onFailure),
event(false, false, true)
{
this->pid = AuAsync::GetCurrentWorkerPId();
}
@ -280,6 +318,7 @@ private:
CppFun<T>::B value;
ErrorStore_t errorValue;
AuThreadPrimitives::Mutex mutex;
AuThreadPrimitives::Event event;
CompleteCallback_f callback;
ErrorCallback_f onFailure;
AuOptionalEx<AuAsync::WorkerPId_t> pid; // todo: make weak?
@ -507,4 +546,199 @@ private:
bool bFailed {};
};
using AuSharedWaterfall = AuWaterfall;
using AuSharedWaterfall = AuSPtr<AuWaterfall>;
namespace __detail
{
struct FutureAccessor
{
template<typename A, typename B>
static auto &GetValue(AuFuture<A, B> &future)
{
return future.GetValue();
}
template<typename A, typename B>
static bool WaitOn(AuFuture<A, B> &future)
{
return future.GetValue();
}
template<typename A, typename B>
static bool IsFinished(AuFuture<A, B> &future)
{
return future.bComplete || future.bFailed;
}
template<typename A, typename B>
static AuThreading::IWaitable *GetWaitOnInterface(AuFuture<A, B> &future)
{
return future.event.AsPointer();
}
};
}
#if defined(AU_LANG_CPP_17) || defined(AU_LANG_CPP_14)
#if !defined(AU_HasCoRoutinedNoIncludeIfAvailable)
#define AU_HasCoRoutinedNoIncludeIfAvailable
#endif
#endif
#if defined(AU_HasCoRoutinedIncluded)
#define __AUHAS_COROUTINES_CO_AWAIT
#else
#if !defined(AU_HasCoRoutinedNoIncludeIfAvailable)
#include <coroutine>
#endif
#define __AUHAS_COROUTINES_CO_AWAIT
#endif
#if defined(__AUHAS_COROUTINES_CO_AWAIT)
namespace std
{
#if !defined(AU_HasVoidCoRoutineTraitsAvailable)
template<>
struct coroutine_traits<void>
{
struct promise_type
{
void get_return_object()
{ }
void set_exception(exception_ptr const &) noexcept
{ }
std::suspend_always initial_suspend() noexcept
{
return {};
}
std::suspend_always final_suspend() noexcept
{
return {};
}
void return_void() noexcept
{ }
void unhandled_exception()
{ }
};
};
template<class... T>
struct coroutine_traits<void, T...>
{
struct promise_type
{
void get_return_object()
{ }
void set_exception(exception_ptr const &) noexcept
{ }
std::suspend_always initial_suspend() noexcept
{
return {};
}
std::suspend_always final_suspend() noexcept
{
return {};
}
void return_void() noexcept
{ }
void unhandled_exception()
{ }
};
};
#endif
}
#endif
namespace __detail
{
template <typename A, typename B>
struct Awaitable
{
AuSharedFuture<A, B> pFuture;
bool await_ready()
{
return __detail::FutureAccessor::IsFinished(*pFuture.get());
}
template <typename T>
void await_suspend(T h)
{
pFuture->OnComplete([=]()
{
h.resume();
});
pFuture->OnFailure([=]()
{
h.resume();
});
}
A await_resume()
{
return __detail::FutureAccessor::GetValue(*pFuture.get());
}
};
template <typename B>
struct AwaitableVoid
{
AuSharedFuture<void, B> pFuture;
bool await_ready()
{
return __detail::FutureAccessor::IsFinished(*pFuture.get());
}
template <typename T>
void await_suspend(T h)
{
pFuture->OnComplete([=]()
{
h.resume();
});
pFuture->OnFailure([=]()
{
h.resume();
});
}
void await_resume()
{
}
};
}
#if defined(__AUHAS_COROUTINES_CO_AWAIT)
template <typename A, typename B, AU_TEMPLATE_ENABLE_WHEN(!AuIsVoid_v<A>)>
inline auto operator co_await (const AuSharedFuture<A, B> &pFuture)
{
SysAssert(pFuture);
return __detail::Awaitable<A, B> { pFuture };
}
template <typename A, typename B, AU_TEMPLATE_ENABLE_WHEN(AuIsVoid_v<A>)>
inline auto operator co_await (const AuSharedFuture<A, B> &pFuture)
{
SysAssert(pFuture);
return __detail::AwaitableVoid<B> { pFuture };
}
#endif