AuroraRuntime/Include/Aurora/Async/Async.hpp

671 lines
24 KiB
C++
Raw Normal View History

2021-06-27 21:25:29 +00:00
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Async.hpp
2021-09-06 10:58:08 +00:00
Date: 2021-7-14
2021-06-27 21:25:29 +00:00
Author: Reece
***/
#pragma once
namespace Aurora::Loop
{
class ILoopSource;
}
2021-06-27 21:25:29 +00:00
namespace Aurora::Async
{
class IWorkItem;
class IAsyncApp;
using AVoid = AuUInt8;
AUKN_SYM IAsyncApp *GetAsyncApp();
/// ThreadGroup_t:
/// 0 = system main thread
/// 1+ = user defined
using ThreadGroup_t = AuUInt8;
/// ThreadId_t:
/// -1 = invalid
/// index = tid/runner id
using ThreadId_t = AuUInt16;
static const ThreadId_t kThreadIdAny = -1;
struct WorkerId_t : AuPair<ThreadGroup_t, ThreadId_t>
{
WorkerId_t() : AuPair<ThreadGroup_t, ThreadId_t>(0, 0)
{}
WorkerId_t(ThreadGroup_t group) : AuPair<ThreadGroup_t, ThreadId_t>(group, kThreadIdAny)
{}
WorkerId_t(ThreadGroup_t group, ThreadId_t id) : AuPair<ThreadGroup_t, ThreadId_t>(group, id)
{}
WorkerId_t(const WorkerId_t &cpy) : AuPair<ThreadGroup_t, ThreadId_t>(cpy.first, cpy.second)
{}
};
2021-06-27 21:25:29 +00:00
struct WorkPriv
{
AuUInt32 magic;
};
struct IWorkItemHandler
{
enum class EProcessNext
{
eInvalid = -1,
eFinished = 0,
eRerun,
eSchedule,
2021-06-27 21:25:29 +00:00
eFailed
};
2021-06-27 21:25:29 +00:00
struct ProcessInfo
{
ProcessInfo(bool finished) : type(finished ? EProcessNext::eFinished : EProcessNext::eFailed) {}
ProcessInfo(EProcessNext type) : type(type) {}
ProcessInfo(const AuList<AuSPtr<IWorkItem>> &blockedBy) : type(EProcessNext::eSchedule), waitFor(blockedBy) {}
// ...
2021-06-27 21:25:29 +00:00
EProcessNext type;
AuList<AuSPtr<IWorkItem>> waitFor;
AuUInt32 reschedMs;
2021-06-30 12:00:32 +00:00
AuUInt64 reschedNs;
};
2021-06-27 21:25:29 +00:00
virtual void DispatchFrame(ProcessInfo &info) = 0;
2021-10-18 12:53:47 +00:00
/// 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; }
};
2021-07-05 13:35:13 +00:00
template<class Info_t = AVoid, class Result_t = AVoid>
2021-06-27 21:25:29 +00:00
struct FJob
{
std::function<void(const Info_t &, const Result_t &)> onSuccess = 0;
2021-10-18 12:53:47 +00:00
std::function<void(const Info_t &)> onFailure = 0;
2021-06-27 21:25:29 +00:00
};
template<class Info_t = AVoid, class Result_t = AVoid>
static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Info_t &, const Result_t &> &onSuccess)
{
FJob<Info_t, Result_t> ret;
ret.onSuccess = [=](const Info_t &in, const Result_t &a)
{
onSuccess(in, a);
};
return ret;
}
template<class Info_t = AVoid, class Result_t = AVoid>
static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Info_t &, const Result_t &> &onSuccess, const AuConsumer<const Info_t &, bool/*neverDispatched*/> &onFailure)
{
FJob<Info_t, Result_t> ret;
ret.onSuccess = [=](const Info_t &in, const Result_t &a)
{
onSuccess(in, a);
};
2021-10-18 12:53:47 +00:00
ret.onFailure = [=](const Info_t &a)
{
2021-10-18 12:53:47 +00:00
onFailure(a, true);
};
return ret;
}
template<class Info_t = AVoid, class Result_t = AVoid>
static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Info_t &, const Result_t &> &onSuccess, const AuConsumer<const Info_t &> &onFailure)
{
FJob<Info_t, Result_t> ret;
ret.onSuccess = [=](const Info_t &in, const Result_t &a)
{
onSuccess(in, a);
};
2021-10-18 12:53:47 +00:00
ret.onFailure = [=](const Info_t &a)
{
onFailure(a);
};
return ret;
}
using FVoidJob = FJob<AVoid, AVoid>;
2021-07-05 13:35:13 +00:00
template<class Info_t = AVoid, class Result_t = AVoid>
2021-06-27 21:25:29 +00:00
struct CJob
{
2021-10-18 12:53:47 +00:00
void(* onSuccess)(const Info_t &, const Result_t &);
void(* onFailure)(const Info_t &);
2021-06-27 21:25:29 +00:00
};
2021-07-05 13:35:13 +00:00
template<class Info_t = AVoid, class Result_t = AVoid>
2021-06-27 21:25:29 +00:00
struct FTask
{
2021-10-18 12:53:47 +00:00
std::function<Result_t(const Info_t &)> onFrame = 0;
2021-06-27 21:25:29 +00:00
};
2021-09-29 08:02:27 +00:00
using FVoidTask = FTask<AVoid, AVoid>;
2021-10-18 12:53:47 +00:00
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;
2021-10-18 12:53:47 +00:00
ret.onFrame = [=](const In_t &a) -> Out_t
{
2021-10-18 12:53:47 +00:00
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;
}
2021-07-05 13:35:13 +00:00
template<class Info_t = AVoid, class Result_t = AVoid>
2021-06-27 21:25:29 +00:00
struct CTask
{
2021-10-18 12:53:47 +00:00
Result_t(* onFrame)(const Info_t &);
2021-06-27 21:25:29 +00:00
};
2021-06-27 21:25:29 +00:00
class IWorkItem
{
public:
virtual AuSPtr<IWorkItem> WaitFor(const AuSPtr<IWorkItem> &workItem) = 0;
virtual AuSPtr<IWorkItem> WaitFor(const AuList<AuSPtr<IWorkItem>> &workItem) = 0;
// ms = time relative to the current time
virtual AuSPtr<IWorkItem> SetSchedTime(AuUInt32 ms) = 0;
// ns = time relative to the current time
virtual AuSPtr<IWorkItem> SetSchedTimeNs(AuUInt64 ns) = 0;
// ms = time relative to the time at which the work item would otherwise dispatch
virtual AuSPtr<IWorkItem> AddDelayTime(AuUInt32 ms) = 0;
// ns = time relative to the time at which the work item would otherwise dispatch
virtual AuSPtr<IWorkItem> AddDelayTimeNs(AuUInt64 ns) = 0;
2021-06-27 21:25:29 +00:00
2021-07-12 14:37:05 +00:00
virtual AuSPtr<IWorkItem> Then(const AuSPtr<IWorkItem> &next) = 0;
virtual AuSPtr<IWorkItem> Dispatch() = 0;
2021-06-27 21:25:29 +00:00
virtual bool BlockUntilComplete() = 0;
virtual bool HasFinished() = 0;
virtual bool HasFailed() = 0;
2021-09-29 08:02:27 +00:00
virtual void Cancel() = 0;
virtual void *GetPrivateData() = 0;
virtual AuOptional<void *> ToWorkResultT() = 0;
2021-06-27 21:25:29 +00:00
};
AUKN_SYM AuSPtr<IWorkItem> NewWorkItem(const WorkerId_t &worker, const AuSPtr<IWorkItemHandler> &task, bool supportsBlocking = false);
AUKN_SYM AuSPtr<IWorkItem> NewFence();
2021-06-27 21:25:29 +00:00
class IAsyncApp
{
public:
// Main thread logic
virtual void Start() = 0;
virtual void Main() = 0;
virtual void Shutdown() = 0;
virtual bool Exiting() = 0;
virtual void SetConsoleCommandDispatcher(WorkerId_t id) = 0;
// Spawning
virtual bool Spawn(WorkerId_t workerId) = 0;
// Event runner threads release upon encountering a zero work condition allowing for a clean exit of event driven apps without the headache of carefully chaining together exit callbacks
// Applications that aren't designed around an event driven model should set callerOwns to true to keep the around during global work exhaustion
virtual void SetWorkerIdIsThreadRunner(WorkerId_t, bool runner) = 0;
virtual Threading::Threads::ThreadShared_t ResolveHandle(WorkerId_t) = 0;
virtual AuBST<ThreadGroup_t, AuList<ThreadId_t>> GetThreads() = 0;
virtual WorkerId_t GetCurrentThread() = 0;
// Synchronization
// Note: syncing to yourself will nullify requireSignal to prevent deadlock
virtual bool Sync(WorkerId_t group, AuUInt32 timeoutMs = 0, bool requireSignal = false) = 0;
virtual void Signal(WorkerId_t group) = 0;
virtual void SyncAllSafe() = 0;
// Features
virtual void AddFeature(WorkerId_t id, AuSPtr<Threading::Threads::IThreadFeature> feature, bool async = false) = 0;
// Debug
virtual void AssertInThreadGroup(ThreadGroup_t thread) = 0;
virtual void AssertWorker(WorkerId_t id) = 0;
virtual bool Poll(bool block) = 0;
2021-10-03 12:43:58 +00:00
virtual bool ScheduleLoopSource(const AuSPtr<Loop::ILoopSource> &loopSource, WorkerId_t workerId, AuUInt32 timeout, const AuConsumer<AuSPtr<Loop::ILoopSource>, bool> &callback) = 0;
};
#pragma region EASE_OF_READING
2021-06-27 21:25:29 +00:00
struct BasicWorkStdFunc : IWorkItemHandler
{
std::function<void()> callback;
2021-10-18 12:53:47 +00:00
std::function<void()> shutdown; // error
2021-10-18 12:53:47 +00:00
BasicWorkStdFunc(std::function<void()> &&callback, std::function<void()> &&shutdown) : callback(std::move(callback)), shutdown(std::move(shutdown))
2021-06-27 21:25:29 +00:00
{}
BasicWorkStdFunc(std::function<void()> &&callback) : callback(std::move(callback))
{}
BasicWorkStdFunc(const std::function<void()> &callback) : callback(callback)
{}
BasicWorkStdFunc(const std::function<void()> &callback, const std::function<void()> &shutdown) : callback(callback), shutdown(shutdown)
2021-06-27 21:25:29 +00:00
{}
private:
2021-09-06 10:58:08 +00:00
#if !defined(_CPPSHARP)
void DispatchFrame(ProcessInfo &info) override
{
2021-06-27 21:25:29 +00:00
try
{
callback();
2021-06-27 21:25:29 +00:00
}
catch (...)
{
Debug::PrintError();
}
}
void Shutdown() override
2021-06-27 21:25:29 +00:00
{
try
{
if (shutdown)
{
shutdown();
}
2021-06-27 21:25:29 +00:00
}
catch (...)
{
Debug::PrintError();
}
}
2021-09-06 10:58:08 +00:00
#endif
2021-06-27 21:25:29 +00:00
};
2021-09-06 10:58:08 +00:00
2021-09-06 10:58:08 +00:00
#if !defined(_CPPSHARP)
/// @hideinitializer
struct BasicWorkCtx : WorkPriv
{
BasicWorkCtx()
{
magic = AuConvertMagicTag32("BWOT");
opt = nullptr;
}
void *opt;
};
/// @hideinitializer
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>>
2021-06-27 21:25:29 +00:00
struct BasicWorkCallback : IWorkItemHandler, std::enable_shared_from_this<IWorkItemHandler>
{
BasicWorkCallback()
{
caller = GetAsyncApp()->GetCurrentThread();
}
2021-09-29 08:02:27 +00:00
BasicWorkCallback(Task_t &&task) : task(std::move(task))
{
caller = GetAsyncApp()->GetCurrentThread();
}
BasicWorkCallback(Task_t &&task, Job_t &&callback) : task(std::move(task)), callback(std::move(callback))
{
caller = GetAsyncApp()->GetCurrentThread();
}
BasicWorkCallback(const Task_t &task) : task(task)
{
caller = GetAsyncApp()->GetCurrentThread();
}
BasicWorkCallback(const Task_t &task, const Job_t &callback) : task(task), callback(callback)
{
caller = GetAsyncApp()->GetCurrentThread();
}
BasicWorkCallback(const Task_t &task, const Job_t &callback, const Info_t &info) : task(task), callback(callback), input(info)
{
caller = GetAsyncApp()->GetCurrentThread();
}
2021-10-18 12:53:47 +00:00
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();
}
2021-10-18 12:53:47 +00:00
BasicWorkCallback(const Task_t &task, const Job_t &callback, Info_t &&info) : task(task), callback(callback), input(info)
{
caller = GetAsyncApp()->GetCurrentThread();
}
2021-09-29 08:02:27 +00:00
Info_t input;
2021-06-27 21:25:29 +00:00
Task_t task;
Job_t callback;
2021-09-06 10:58:08 +00:00
BasicWorkCallback<Info_t, Result_t, Task_t, Job_t> &SetTask(const Task_t &task)
{
this->task = task;
return *this;
}
BasicWorkCallback<Info_t, Result_t, Task_t, Job_t> &SetTask(const Job_t &callback)
{
this->callback = callback;
return *this;
}
private:
2021-06-27 21:25:29 +00:00
2021-09-06 10:58:08 +00:00
static constexpr bool IsCallbackPtr = std::is_pointer_v<Job_t> || AuIsBaseOfTemplate<std::shared_ptr, Job_t>::value;
static constexpr bool IsTaskPtr = std::is_pointer_v<Task_t> || AuIsBaseOfTemplate<std::shared_ptr, Task_t>::value;
2021-06-27 21:25:29 +00:00
WorkerId_t caller;
BasicWorkCtx secretContext_;
2021-10-18 12:53:47 +00:00
Result_t resultValue_;
virtual void *GetPrivateData() override { return &secretContext_; }
2021-06-27 21:25:29 +00:00
void DispatchFrame(ProcessInfo &info) override
{
2021-09-06 10:58:08 +00:00
try
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
if constexpr (IsTaskPtr)
{
resultValue_ = task->onFrame(input);
2021-09-06 10:58:08 +00:00
}
else
{
resultValue_ = task.onFrame(input);
2021-09-06 10:58:08 +00:00
}
2021-06-27 21:25:29 +00:00
}
2021-09-06 10:58:08 +00:00
catch (...)
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
Debug::PrintError();
Shutdown();
return;
2021-06-27 21:25:29 +00:00
}
2021-06-30 09:28:52 +00:00
auto pin = std::static_pointer_cast<std::remove_pointer_t<decltype(this)>>(this->shared_from_this());
2021-06-27 21:25:29 +00:00
std::function<void()> func = [pin]()
2021-06-27 21:25:29 +00:00
{
try
{
2021-10-18 12:53:47 +00:00
pin->secretContext_.opt = &pin->resultValue_;
if constexpr (IsCallbackPtr)
2021-06-27 21:25:29 +00:00
{
2021-10-18 12:53:47 +00:00
pin->callback->onSuccess(pin->input, pin->resultValue_);
2021-06-27 21:25:29 +00:00
}
else
{
2021-10-18 12:53:47 +00:00
if (pin->callback.onSuccess)
{
pin->callback.onSuccess(pin->input,pin->resultValue_);
}
2021-06-27 21:25:29 +00:00
}
}
catch (...)
{
Debug::PrintError();
}
};
try
{
if (caller == GetAsyncApp()->GetCurrentThread())
{
func();
}
else
{
2021-06-30 09:28:52 +00:00
std::function<void()> err = [pin]()
2021-06-27 21:25:29 +00:00
{
2021-10-18 12:53:47 +00:00
pin->CallOnFailure();
2021-06-27 21:25:29 +00:00
};
// TODO: this is somewhat evil. double alloc when we could reuse this
if (!NewWorkItem(caller, AuMakeShared<BasicWorkStdFunc>(func, err))->Dispatch())
{
2021-10-18 12:53:47 +00:00
pin->CallOnFailure();
}
2021-06-27 21:25:29 +00:00
}
}
catch (...)
{
Debug::PrintError();
Shutdown();
}
}
void Shutdown() override
{
2021-06-27 21:25:29 +00:00
try
{
2021-10-18 12:53:47 +00:00
CallOnFailure();
2021-06-27 21:25:29 +00:00
}
catch (...)
{
Debug::PrintError();
}
}
2021-06-30 09:28:52 +00:00
2021-10-18 12:53:47 +00:00
void CallOnFailure()
2021-06-30 09:28:52 +00:00
{
if constexpr (IsCallbackPtr)
{
2021-09-06 10:58:08 +00:00
if constexpr (AuIsBaseOfTemplate<std::function, decltype(callback->onFailure)>::value)
2021-06-30 09:28:52 +00:00
{
if (!callback->onFailure)
{
return;
}
}
2021-10-18 12:53:47 +00:00
callback->onFailure(input);
2021-06-30 09:28:52 +00:00
}
else
{
2021-09-06 10:58:08 +00:00
if constexpr (AuIsBaseOfTemplate<std::function, decltype(callback.onFailure)>::value)
2021-06-30 09:28:52 +00:00
{
if (!callback.onFailure)
{
return;
}
}
2021-10-18 12:53:47 +00:00
callback.onFailure(input);
2021-06-30 09:28:52 +00:00
}
}
2021-06-27 21:25:29 +00:00
};
/// @hideinitializer
template<typename Frame_t = std::function<void()>, typename Cleanup_t = std::function<void()>>
struct WorkItemCallable : IWorkItemHandler
2021-06-27 21:25:29 +00:00
{
Frame_t frame;
Cleanup_t cleanup;
private:
void DispatchFrame(ProcessInfo &info) override
{
if constexpr (AuIsBaseOfTemplate<Frame_t, decltype(frame)>::value)
{
if (!frame)
{
info.type = IWorkItemHandler::EProcessNext::eFinished;
return;
}
}
2021-06-27 21:25:29 +00:00
frame();
info.type = IWorkItemHandler::EProcessNext::eFinished;
}
void Shutdown() override
{
if constexpr (AuIsBaseOfTemplate<Cleanup_t, decltype(cleanup)>::value)
{
if (!cleanup)
{
return;
}
}
2021-06-27 21:25:29 +00:00
cleanup();
}
};
2021-07-05 13:35:13 +00:00
#define ASYNC_ERROR(exp) { if constexpr (std::is_same_v<T, bool>) { SysPushErrorGen(exp); return {}; } else { throw std::string(exp); } }
#define ASYNC_FINISH { if constexpr (std::is_same_v<T, bool>) { return true; } }
2021-09-29 08:02:27 +00:00
template<typename T = void, typename... Args, AU_TEMPLATE_ENABLE_WHEN(std::is_same_v<T, bool> || std::is_void<T>::value)>
static std::function<T(Args&&...)> TranslateAsyncFunctionToDispatcherWithThread(WorkerId_t id, std::function<void(Args...)> func)
2021-06-27 21:25:29 +00:00
{
if (!func) return {};
return [=](Args&&... in) -> T
2021-07-05 13:35:13 +00:00
{
2021-09-06 10:58:08 +00:00
auto work = AuMakeShared<BasicWorkStdFunc>([=]() -> void {
2021-07-05 13:35:13 +00:00
func(in...);
});
2021-09-29 08:02:27 +00:00
if (!work) ASYNC_ERROR("can't dispatch async call; out of memory");
auto workItem = NewWorkItem(id, work);
if (!workItem) ASYNC_ERROR("can't dispatch async call; out of memory");
2021-07-05 13:35:13 +00:00
workItem->Dispatch();
2021-09-29 08:02:27 +00:00
ASYNC_FINISH;
2021-07-05 13:35:13 +00:00
};
}
2021-09-29 08:02:27 +00:00
template<typename T = void, typename... Args, AU_TEMPLATE_ENABLE_WHEN(std::is_same_v<T, bool> || std::is_void<T>::value)>
static std::function<T(Args&&...)> TranslateAsyncFunctionToDispatcher(std::function<void(Args...)> func)
2021-07-05 13:35:13 +00:00
{
return TranslateAsyncFunctionToDispatcherWithThread(GetAsyncApp()->GetCurrentThread(), func);
2021-09-29 08:02:27 +00:00
}
template<typename B = void, typename T, typename... Args, AU_TEMPLATE_ENABLE_WHEN(std::is_same_v<T, bool> || std::is_void<T>::value)>
2021-10-18 12:53:47 +00:00
static std::function<T(std::function<void(const B&)>, Args...)> TranslateAsyncReturnableFunctionToDispatcherWithThread(WorkerId_t id, std::function<B(Args...)> func)
2021-09-29 08:02:27 +00:00
{
return [=](std::function<T(const B&)> callback, Args... in) -> T
2021-07-05 13:35:13 +00:00
{
2021-09-06 10:58:08 +00:00
auto work = AuMakeShared<BasicWorkCallback<AVoid, B>>();
2021-09-29 08:02:27 +00:00
if (!work) ASYNC_ERROR("can't dispatch async call; out of memory");
2021-10-18 12:53:47 +00:00
work.task.onProcess = [=](const AVoid &) -> B
2021-07-05 13:35:13 +00:00
{
if (!func) return B{};
2021-07-05 13:35:13 +00:00
return func(in...);
};
work.callback.onSuccess = [=](const AVoid &, const B &ret)
{
callback(ret);
};
2021-09-29 08:02:27 +00:00
auto workItem = NewWorkItem(id, work);
if (!workItem) ASYNC_ERROR("can't dispatch async call; out of memory");
2021-07-05 13:35:13 +00:00
workItem->Dispatch();
2021-09-29 08:02:27 +00:00
ASYNC_FINISH;
2021-07-05 13:35:13 +00:00
};
2021-06-27 21:25:29 +00:00
}
2021-09-29 08:02:27 +00:00
2021-10-18 12:53:47 +00:00
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)
2021-09-29 08:02:27 +00:00
{
2021-10-18 12:53:47 +00:00
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t, Task_t>>(std::move(task), job), enableWait);
2021-09-29 08:02:27 +00:00
}
2021-10-18 12:53:47 +00:00
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)
{
2021-10-18 12:53:47 +00:00
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);
}
2021-10-18 12:53:47 +00:00
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
2021-10-18 12:53:47 +00:00
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t, Task_t>>(task, job, inputParameters), enableWait)->Dispatch();
}
2021-10-18 12:53:47 +00:00
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
#endif
#pragma endregion EASE_OF_READING
}