AuroraRuntime/Include/Aurora/Async/Async.hpp
2022-01-19 18:18:13 +00:00

194 lines
5.9 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Async.hpp
Date: 2021-7-14
Author: Reece
***/
#pragma once
#include "AsyncTypes.hpp"
#include "IWorkItem.hpp"
#include "IWorkItemHandler.hpp"
#include "IThreadPool.hpp"
#include "IAsyncApp.hpp"
#include "Jobs.hpp"
#include "Tasks.hpp"
namespace Aurora::Async
{
AUKN_SYM IAsyncApp *GetAsyncApp();
///
AUKN_SYM WorkerPId_t GetCurrentWorkerPId();
/// Async app only | Thread pools must use the IThreadPool::NewFence function
AUKN_SYM AuSPtr<IWorkItem> NewWorkItem(const WorkerId_t &worker, const AuSPtr<IWorkItemHandler> &task, bool supportsBlocking = false);
AUKN_SYM AuSPtr<IWorkItem> NewWorkItem(const WorkerPId_t &worker, const AuSPtr<IWorkItemHandler> &task, bool supportsBlocking = false);
/// Async app only | Thread pools must use the IThreadPool::NewFence function
AUKN_SYM AuSPtr<IWorkItem> NewFence();
/// Allocates a new thread pool for usage
AUKN_SYM AuSPtr<IThreadPool> NewThreadPool();
// TODO: move the following trash out of here
// the following is mostly old trash
#pragma region EASE_OF_READING
struct BasicWorkStdFunc : IWorkItemHandler
{
AuFunction<void()> callback;
AuFunction<void()> shutdown; // error
BasicWorkStdFunc(AuFunction<void()> &&callback, AuFunction<void()> &&shutdown) : callback(AuMove(callback)), shutdown(AuMove(shutdown))
{}
BasicWorkStdFunc(AuFunction<void()> &&callback) : callback(AuMove(callback))
{}
BasicWorkStdFunc(const AuFunction<void()> &callback) : callback(callback)
{}
BasicWorkStdFunc(const AuFunction<void()> &callback, const AuFunction<void()> &shutdown) : callback(callback), shutdown(shutdown)
{}
private:
#if !defined(_CPPSHARP)
void DispatchFrame(ProcessInfo &info) override
{
try
{
callback();
}
catch (...)
{
Debug::PrintError();
}
}
void Shutdown() override
{
try
{
if (shutdown)
{
shutdown();
}
}
catch (...)
{
Debug::PrintError();
}
}
#endif
};
#if !defined(_CPPSHARP)
/// @hideinitializer
template<typename Frame_t = AuFunction<void()>, typename Cleanup_t = AuFunction<void()>>
struct WorkItemCallable : IWorkItemHandler
{
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;
}
}
frame();
info.type = IWorkItemHandler::EProcessNext::eFinished;
}
void Shutdown() override
{
if constexpr (AuIsBaseOfTemplate<Cleanup_t, decltype(cleanup)>::value)
{
if (!cleanup)
{
return;
}
}
cleanup();
}
};
#define ASYNC_ERROR(exp) { if constexpr (AuIsSame_v<T, bool>) { SysPushErrorGen(exp); return {}; } else { throw std::string(exp); } }
#define ASYNC_FINISH { if constexpr (AuIsSame_v<T, bool>) { return true; } }
template<typename T = void, typename... Args, AU_TEMPLATE_ENABLE_WHEN(AuIsSame_v<T, bool> || AuIsVoid_v<T>)>
static AuFunction<T(Args&&...)> TranslateAsyncFunctionToDispatcherWithThread(WorkerId_t id, AuFunction<void(Args...)> func)
{
if (!func) return {};
return [=](Args&&... in) -> T
{
auto work = AuMakeShared<BasicWorkStdFunc>([=]() -> void {
func(in...);
});
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");
workItem->Dispatch();
ASYNC_FINISH;
};
}
/// Async app only
template<typename T = void, typename... Args, AU_TEMPLATE_ENABLE_WHEN(AuIsSame_v<T, bool> || AuIsVoid_v<T>)>
static AuFunction<T(Args&&...)> TranslateAsyncFunctionToDispatcher(AuFunction<void(Args...)> func)
{
return TranslateAsyncFunctionToDispatcherWithThread(GetAsyncApp()->GetCurrentThread(), func);
}
/// Async app only
template<typename B = void, typename T, typename... Args, AU_TEMPLATE_ENABLE_WHEN(AuIsSame_v<T, bool> || AuIsVoid_v<T>)>
static AuFunction<T(AuFunction<void(const B&)>, Args...)> TranslateAsyncReturnableFunctionToDispatcherWithThread(WorkerId_t id, AuFunction<B(Args...)> func)
{
return [=](AuFunction<T(const B&)> callback, Args... in) -> T
{
auto work = AuMakeShared<WorkPairImpl<AVoid, B>>();
if (!work) ASYNC_ERROR("can't dispatch async call; out of memory");
work.task.onProcess = [=](const AVoid &) -> B
{
if (!func) return B{};
return func(in...);
};
work.callback.onSuccess = [=](const AVoid &, const B &ret)
{
callback(ret);
};
auto workItem = NewWorkItem(id, work);
if (!workItem) ASYNC_ERROR("can't dispatch async call; out of memory");
workItem->Dispatch();
ASYNC_FINISH;
};
}
#undef ASYNC_ERROR
#undef ASYNC_FINISH
#endif
#pragma endregion EASE_OF_READING
}
#if !defined(_CPPSHARP)
#include "JobFrom.hpp"
#include "TaskFrom.hpp"
#include "WorkPairImpl.hpp"
#include "WorkBasic.hpp"
#endif