[*] Improve Aurora::Async API

This commit is contained in:
Reece Wilson 2021-10-18 13:53:47 +01:00
parent ad182d07e0
commit bd5222cbfb

View File

@ -78,6 +78,10 @@ namespace Aurora::Async
};
virtual void DispatchFrame(ProcessInfo &info) = 0;
/// A really terrible name for the overloadable method that serves as the critical failure callback
/// You have a 'shutdown'/free function you can overload, it's called the dtor
/// Don't moan about the shitty naming of this, im not refactoring it
virtual void Shutdown() = 0;
virtual void *GetPrivateData() { return nullptr; }
@ -87,7 +91,7 @@ namespace Aurora::Async
struct FJob
{
std::function<void(const Info_t &, const Result_t &)> onSuccess = 0;
std::function<void(const Info_t &, bool)> onFailure = 0;
std::function<void(const Info_t &)> onFailure = 0;
};
template<class Info_t = AVoid, class Result_t = AVoid>
@ -110,9 +114,9 @@ namespace Aurora::Async
{
onSuccess(in, a);
};
ret.onFailure = [=](const Info_t &a, bool neverDispatched)
ret.onFailure = [=](const Info_t &a)
{
onFailure(a, neverDispatched);
onFailure(a, true);
};
return ret;
}
@ -126,7 +130,7 @@ namespace Aurora::Async
{
onSuccess(in, a);
};
ret.onFailure = [=](const Info_t &a, bool neverDispatched)
ret.onFailure = [=](const Info_t &a)
{
onFailure(a);
};
@ -138,59 +142,57 @@ namespace Aurora::Async
template<class Info_t = AVoid, class Result_t = AVoid>
struct CJob
{
void(* onSuccess)(const Info_t &, const Result_t &); //
void(* onFailure)(const Info_t &, bool taskNeverDispatched); // called from caller thread if taskNeverDispatched
void(* onSuccess)(const Info_t &, const Result_t &);
void(* onFailure)(const Info_t &);
};
template<class Info_t = AVoid, class Result_t = AVoid>
struct FTask
{
std::function<AuOptional<Result_t>(const Info_t &)> onFrame = 0;
std::function<Result_t(const Info_t &)> onFrame = 0;
};
using FVoidTask = FTask<AVoid, AVoid>;
template<class In_t = Async::AVoid>
static inline FTask<In_t, AVoid> TaskFromConsumerRefT(const AuConsumer<const In_t &> &func)
{
FTask<In_t, AVoid> ret;
ret.onFrame = [=](const In_t &a) -> AuOptional<AVoid>
{
func(a);
return AVoid{};
};
return ret;
}
template<class In_t = Async::AVoid, class Out_t = Async::AVoid>
static inline FTask<In_t, AVoid> TaskFromConsumerRefT(const AuSupplierConsumer<AuOptional<Out_t>, const In_t &> &func)
template<class In_t = Async::AVoid, class Out_t = Async::AVoid, typename Functional_t = AuConsumer<const In_t &>>
static inline FTask<In_t, Out_t> TaskFromConsumerRefT(const Functional_t &func)
{
FTask<In_t, Out_t> ret;
ret.onFrame = [=](const In_t &a) -> AuOptional<Out_t>
ret.onFrame = [=](const In_t &a) -> Out_t
{
return func(a);
if constexpr (std::is_same_v<Functional_t, AuConsumer<const In_t &>>)
{
func(a);
return Out_t{};
}
else if constexpr (std::is_same_v<Functional_t, AuConsumer<const In_t *>>)
{
func(&a);
return Out_t{};
}
else if constexpr (std::is_same_v<Functional_t, AuVoidFunc>)
{
func();
return Out_t{};
}
else if constexpr (std::is_same_v<Functional_t, AuSupplierConsumer<Out_t, const In_t &>>)
{
return func(a);
}
else if constexpr (std::is_same_v<Functional_t, AuConsumer<const In_t &>>)
{
func(a);
return Out_t{};
}
return Out_t{};
};
return ret;
}
static inline FTask<AVoid, AVoid> TaskFromFunctional(const AuVoidFunc &func)
{
FTask<AVoid, AVoid> ret;
ret.onFrame = [=](const AVoid &a) -> AuOptional<AVoid>
{
func();
return AVoid{};
};
return ret;
}
template<class Info_t = AVoid, class Result_t = AVoid>
struct CTask
{
AuOptional<Result_t>(* onFrame)(const Info_t &);
Result_t(* onFrame)(const Info_t &);
};
class IWorkItem
@ -271,9 +273,9 @@ namespace Aurora::Async
struct BasicWorkStdFunc : IWorkItemHandler
{
std::function<void()> callback;
std::function<void()> shutdown;
std::function<void()> shutdown; // error
BasicWorkStdFunc(std::function<void()> &&callback, std::function<void()> &&error) : callback(std::move(callback)), shutdown(std::move(error))
BasicWorkStdFunc(std::function<void()> &&callback, std::function<void()> &&shutdown) : callback(std::move(callback)), shutdown(std::move(shutdown))
{}
BasicWorkStdFunc(std::function<void()> &&callback) : callback(std::move(callback))
@ -363,12 +365,22 @@ namespace Aurora::Async
caller = GetAsyncApp()->GetCurrentThread();
}
BasicWorkCallback(Task_t &&task, const Job_t &callback, const Info_t &info) : task(std::move(task)), callback(callback), input(info)
{
caller = GetAsyncApp()->GetCurrentThread();
}
BasicWorkCallback(Task_t &&task, Job_t &&callback, const Info_t &info) : task(std::move(task)), callback(std::move(callback)), input(info)
{
caller = GetAsyncApp()->GetCurrentThread();
}
BasicWorkCallback(Task_t &&task, Job_t &&callback, Info_t &&info) : task(std::move(task)), callback(std::move(callback)), input(std::move(info))
{
caller = GetAsyncApp()->GetCurrentThread();
}
BasicWorkCallback(const Task_t &task, const Job_t &callback, Info_t &&info) : task(task), callback(callback), input(std::move(info))
BasicWorkCallback(const Task_t &task, const Job_t &callback, Info_t &&info) : task(task), callback(callback), input(info)
{
caller = GetAsyncApp()->GetCurrentThread();
}
@ -398,7 +410,7 @@ namespace Aurora::Async
WorkerId_t caller;
BasicWorkCtx secretContext_;
AuOptional<Result_t> resultValue_;
Result_t resultValue_;
virtual void *GetPrivateData() override { return &secretContext_; }
@ -427,24 +439,17 @@ namespace Aurora::Async
{
try
{
if (pin->resultValue_.has_value())
pin->secretContext_.opt = &pin->resultValue_;
if constexpr (IsCallbackPtr)
{
pin->secretContext_.opt = &pin->resultValue_.value();
if constexpr (IsCallbackPtr)
{
pin->callback->onSuccess(pin->input, *pin->resultValue_);
}
else
{
if (pin->callback.onSuccess)
{
pin->callback.onSuccess(pin->input, *pin->resultValue_);
}
}
pin->callback->onSuccess(pin->input, pin->resultValue_);
}
else
{
pin->CallOnFailure(false);
if (pin->callback.onSuccess)
{
pin->callback.onSuccess(pin->input,pin->resultValue_);
}
}
}
catch (...)
@ -463,13 +468,13 @@ namespace Aurora::Async
{
std::function<void()> err = [pin]()
{
pin->CallOnFailure(false);
pin->CallOnFailure();
};
// TODO: this is somewhat evil. double alloc when we could reuse this
if (!NewWorkItem(caller, AuMakeShared<BasicWorkStdFunc>(func, err))->Dispatch())
{
pin->CallOnFailure(true);
pin->CallOnFailure();
}
}
}
@ -484,7 +489,7 @@ namespace Aurora::Async
{
try
{
CallOnFailure(true);
CallOnFailure();
}
catch (...)
{
@ -492,7 +497,7 @@ namespace Aurora::Async
}
}
void CallOnFailure(bool fail)
void CallOnFailure()
{
if constexpr (IsCallbackPtr)
{
@ -504,7 +509,7 @@ namespace Aurora::Async
}
}
callback->onFailure(input, fail);
callback->onFailure(input);
}
else
{
@ -515,7 +520,7 @@ namespace Aurora::Async
return;
}
}
callback.onFailure(input, fail);
callback.onFailure(input);
}
}
};
@ -582,13 +587,13 @@ namespace Aurora::Async
}
template<typename B = void, typename T, typename... Args, AU_TEMPLATE_ENABLE_WHEN(std::is_same_v<T, bool> || std::is_void<T>::value)>
static std::function<T(std::function<void(const B&)>, Args...)> TranslateAsyncReturnableFunctionToDispatcherWithThread(WorkerId_t id, std::function<AuOptional<B>(Args...)> func)
static std::function<T(std::function<void(const B&)>, Args...)> TranslateAsyncReturnableFunctionToDispatcherWithThread(WorkerId_t id, std::function<B(Args...)> func)
{
return [=](std::function<T(const B&)> callback, Args... in) -> T
{
auto work = AuMakeShared<BasicWorkCallback<AVoid, B>>();
if (!work) ASYNC_ERROR("can't dispatch async call; out of memory");
work.task.onProcess = [=](const AVoid &) -> AuOptional<B>
work.task.onProcess = [=](const AVoid &) -> B
{
if (!func) return B{};
return func(in...);
@ -604,26 +609,57 @@ namespace Aurora::Async
};
}
template<typename B = void, typename T, typename... Args, AU_TEMPLATE_ENABLE_WHEN(std::is_same_v<T, bool> || std::is_void<T>::value)>
static std::function<T(std::function<void(const B&)>, Args...)> TranslateAsyncReturnableFunctionToDispatcher(std::function<AuOptional<B>(Args...)> func)
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
static AuSPtr<Async::IWorkItem> NewBasicWorkCallback(const WorkerId_t &worker, const Task_t &task, const Job_t &job, bool enableWait = false)
{
return TranslateAsyncReturnableFunctionToDispatcherWithThread(GetAsyncApp()->GetCurrentThread(), func);
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t, Task_t>>(std::move(task), job), enableWait);
}
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
static AuSPtr<Async::IWorkItem> DispatchBasicWorkCallback(const WorkerId_t &worker, const Task_t &task, const Job_t &job, bool enableWait = false)
{
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t>>(task, job), enableWait)->Dispatch();
return NewBasicWorkCallback<Info_t, Result_t, Task_t, Job_t>(worker, task, job, enableWait)->Dispatch();
}
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
static AuSPtr<Async::IWorkItem> NewBasicWorkCallback(const WorkerId_t &worker, Task_t &&task, const Job_t &job, bool enableWait = false)
{
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t, Task_t>>(std::move(task), job), enableWait);
}
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
static AuSPtr<Async::IWorkItem> DispatchBasicWorkCallback(const WorkerId_t &worker, Task_t &&task, const Job_t &job, bool enableWait = false)
{
return NewBasicWorkCallback<Info_t, Result_t, Task_t, Job_t>(worker, std::move(task), job, enableWait)->Dispatch();
}
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
static AuSPtr<Async::IWorkItem> NewBasicWorkCallback(const WorkerId_t &worker, Task_t &&task, Job_t &&job, bool enableWait = false)
{
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t, Task_t>>(std::move(task), std::move(job)), enableWait);
}
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
static AuSPtr<Async::IWorkItem> NBasicWorkCallback(const WorkerId_t &worker, Task_t &&task, Job_t &&job, bool enableWait = false)
{
return NewBasicWorkCallback<Info_t, Result_t, Task_t, Job_t>(worker, std::move(task), std::move(job), enableWait)->Dispatch();
}
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
static AuSPtr<Async::IWorkItem> DispatchBasicWorkCallback(const WorkerId_t &worker, const Task_t &task, const Job_t &job, const Info_t &inputParameters, bool enableWait = false)
{
// TOOD: use faster object if job parguments are invalid
// It would be nice if we didn't have to drag the job callback pair around with us
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t>>(task, job, inputParameters), enableWait)->Dispatch();
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t, Task_t>>(task, job, inputParameters), enableWait)->Dispatch();
}
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>, typename ClazzImpl>
AuSPtr<Aurora::Async::IWorkItem> DispatchFunctional(const WorkerId_t &worker, ClazzImpl task, const Job_t &job, const Info_t &inputParameters, bool enableWait = false)
{
return Async::DispatchBasicWorkCallback<Info_t, Result_t, Task_t, Job_t>(worker, Async::TaskFromConsumerRefT<Info_t, Result_t>(task), job, inputParameters, enableWait);
}
#undef ASYNC_ERROR
#undef ASYNC_FINISH