Last active
January 13, 2019 22:53
-
-
Save muit/b24c108fe38bac55648f82a2b2b5c703 to your computer and use it in GitHub Desktop.
A multithreading task manager in compile time. Ensures no memory leaks and correct completion of tasks.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2015-2018 Piperift. All Rights Reserved. | |
#pragma once | |
#include <Async/AsyncWork.h> | |
#include "Misc/TypeTraits.h" | |
template<class TaskType> | |
class FTaskHolder : public FAsyncTask<TaskType> { | |
using Super = FAsyncTask<TaskType>; | |
public: | |
using Callback = TFunction<void(FTaskHolder<TaskType>&)>; | |
Callback _OnFinished; | |
FTaskHolder() : Super() {} | |
template <typename... ArgTypes> | |
FTaskHolder(ArgTypes&&... CtrArgs) : Super(Forward<ArgTypes>(CtrArgs)...) {} | |
auto& OnFinished(Callback&& Delegate) { | |
_OnFinished = Delegate; | |
return *this; | |
} | |
TaskType* operator->() { | |
return &Super::GetTask(); | |
} | |
}; | |
/** Use TScopedTaskList. Manages the lifetime of an array of multi-threaded tasks */ | |
template<class TaskType> | |
struct TScopedTaskListType { | |
using Callback = TFunction<void(FTaskHolder<TaskType>&)>; | |
private: | |
TArray<FTaskHolder<TaskType>*> Tasks; | |
public: | |
TScopedTaskListType() : Tasks{} {} | |
TScopedTaskListType(TScopedTaskListType&& other) { | |
Tasks = MoveTemp(other.Tasks); | |
} | |
template <typename... ArgTypes> | |
FTaskHolder<TaskType>& CreateTask(ArgTypes&&... CtrArgs) | |
{ | |
auto* NewTask = new FTaskHolder<TaskType>(Forward<ArgTypes>(CtrArgs)...); | |
Tasks.Add(NewTask); | |
return *NewTask; | |
} | |
void Tick() { | |
Tasks.RemoveAllSwap([this](auto* Task) { | |
if (Task->IsDone()) | |
{ | |
Task->_OnFinished(*Task); | |
delete Task; | |
return true; | |
} | |
return false; | |
}); | |
} | |
void CancelAll() | |
{ | |
for (auto* Task : Tasks) | |
{ | |
if (!Task->IsIdle()) | |
{ | |
Task->EnsureCompletion(false); | |
Task->_OnFinished(*Task); | |
} | |
delete Task; | |
} | |
Tasks.Empty(); | |
} | |
~TScopedTaskListType() { | |
CancelAll(); | |
} | |
}; | |
/** Manages the lifetime of an array of multi-threaded tasks */ | |
template<class ...Args> | |
struct TScopedTaskList { | |
static constexpr uint32 TypesCount = sizeof...(Args); | |
TTuple<TScopedTaskListType<Args>...> SingleManagers; | |
public: | |
TScopedTaskList() {} | |
TScopedTaskList(TScopedTaskList&& other) {} | |
template<class Type, typename... ArgTypes> | |
inline FTaskHolder<Type>& CreateTask(ArgTypes&&... CtrArgs) { | |
static_assert(VariadicContainsType<Type, Args...>(), "Can't create a task of this type"); | |
constexpr uint32 I = GetVariadicTypeIndex<0, Type, Args...>(); | |
return SingleManagers.Get<I>().CreateTask(Forward<ArgTypes>(CtrArgs)...); | |
} | |
void Tick() { | |
TickForEachId(); | |
} | |
void CancelAll() { | |
CancelForEachId(); | |
} | |
private: | |
template<uint32 I = 0> | |
void TickForEachId() { | |
SingleManagers.Get<I>().Tick(); | |
TickForEachId<I + 1>(); | |
} | |
template<> | |
void TickForEachId<TypesCount>() {} | |
template<uint32 I = 0> | |
void CancelForEachId() { | |
SingleManagers.Get<I>().CancelAll(); | |
CancelForEachId<I + 1>(); | |
} | |
template<> | |
void CancelForEachId<TypesCount>() {} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment