mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-13 03:32:28 -04:00
Core/Misc: TaskScheduler internal improvements
* Make TaskContext not copyable - this allowed removing shared `_consumed` state, getting rid of memory allocation per task execution * Use std::make_shared * Remove unnceccessary memory alloc/dealloc in TaskContext::Repeat * Remove std::function wrapping in every TaskContext function
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
#include "TaskScheduler.h"
|
||||
#include "Errors.h"
|
||||
|
||||
TaskScheduler::success_t const TaskScheduler::EmptySuccessCallback;
|
||||
|
||||
TaskScheduler::TaskScheduler()
|
||||
: self_reference(this, [](TaskScheduler const*) { }),
|
||||
_now(clock_t::now()),
|
||||
@@ -33,19 +35,42 @@ TaskScheduler& TaskScheduler::ClearValidator()
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::Update(success_t const& callback/* = nullptr*/)
|
||||
TaskScheduler& TaskScheduler::Update()
|
||||
{
|
||||
_now = clock_t::now();
|
||||
Dispatch(EmptySuccessCallback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::Update(success_t callback)
|
||||
{
|
||||
_now = clock_t::now();
|
||||
Dispatch(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::Update(size_t milliseconds, success_t const& callback/* = nullptr*/)
|
||||
TaskScheduler& TaskScheduler::Update(size_t milliseconds)
|
||||
{
|
||||
return Update(std::chrono::milliseconds(milliseconds), callback);
|
||||
_now += std::chrono::milliseconds(milliseconds);
|
||||
Dispatch(EmptySuccessCallback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::Update(duration_t difftime, success_t const& callback/* = nullptr*/)
|
||||
TaskScheduler& TaskScheduler::Update(size_t milliseconds, success_t callback)
|
||||
{
|
||||
_now += std::chrono::milliseconds(milliseconds);
|
||||
Dispatch(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::Update(duration_t difftime)
|
||||
{
|
||||
_now += difftime;
|
||||
Dispatch(EmptySuccessCallback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::Update(duration_t difftime, success_t callback)
|
||||
{
|
||||
_now += difftime;
|
||||
Dispatch(callback);
|
||||
@@ -54,7 +79,7 @@ TaskScheduler& TaskScheduler::Update(duration_t difftime, success_t const& callb
|
||||
|
||||
TaskScheduler& TaskScheduler::Async(std::function<void()> callable)
|
||||
{
|
||||
_asyncHolder.emplace(std::move(callable));
|
||||
Schedule(duration_t(1), [callable = std::move(callable)](TaskContext const&) { callable(); });
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -62,7 +87,6 @@ TaskScheduler& TaskScheduler::CancelAll()
|
||||
{
|
||||
/// Clear the task holder
|
||||
_task_holder.Clear();
|
||||
_asyncHolder = AsyncHolder();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -75,11 +99,12 @@ TaskScheduler& TaskScheduler::CancelGroup(group_t group)
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups)
|
||||
TaskScheduler& TaskScheduler::CancelGroupsOf(std::span<group_t> groups)
|
||||
{
|
||||
for (group_t group : groups)
|
||||
CancelGroup(group);
|
||||
|
||||
_task_holder.RemoveIf([groups](TaskContainer const& task) -> bool
|
||||
{
|
||||
return std::ranges::any_of(groups, [&](group_t group) { return task->IsInGroup(group); });
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -93,7 +118,7 @@ TaskScheduler& TaskScheduler::DelayAll(duration_t duration)
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::DelayGroup(group_t const group, duration_t duration)
|
||||
TaskScheduler& TaskScheduler::DelayGroup(group_t group, duration_t duration)
|
||||
{
|
||||
_task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool
|
||||
{
|
||||
@@ -110,7 +135,7 @@ TaskScheduler& TaskScheduler::DelayGroup(group_t const group, duration_t duratio
|
||||
|
||||
TaskScheduler& TaskScheduler::RescheduleAll(duration_t duration)
|
||||
{
|
||||
auto const end = _now + duration;
|
||||
timepoint_t end = _now + duration;
|
||||
_task_holder.ModifyIf([end](TaskContainer const& task) -> bool
|
||||
{
|
||||
task->_end = end;
|
||||
@@ -119,9 +144,9 @@ TaskScheduler& TaskScheduler::RescheduleAll(duration_t duration)
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::RescheduleGroup(group_t const group, duration_t duration)
|
||||
TaskScheduler& TaskScheduler::RescheduleGroup(group_t group, duration_t duration)
|
||||
{
|
||||
auto const end = _now + duration;
|
||||
timepoint_t end = _now + duration;
|
||||
_task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool
|
||||
{
|
||||
if (task->IsInGroup(group))
|
||||
@@ -135,21 +160,27 @@ TaskScheduler& TaskScheduler::RescheduleGroup(group_t const group, duration_t du
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::InsertTask(TaskContainer task)
|
||||
TaskScheduler& TaskScheduler::InsertTask(TaskContainer&& task)
|
||||
{
|
||||
_task_holder.Push(std::move(task));
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::InsertTask(TaskQueue::Container::node_type&& node)
|
||||
{
|
||||
_task_holder.Push(std::move(node));
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::ScheduleAt(timepoint_t end, duration_t time, task_handler_t task)
|
||||
{
|
||||
return InsertTask(TaskContainer(new Task(end + time, time, std::move(task))));
|
||||
return InsertTask(std::make_shared<Task>(end + time, time, std::move(task)));
|
||||
}
|
||||
|
||||
TaskScheduler& TaskScheduler::ScheduleAt(timepoint_t end, duration_t time, group_t const group, task_handler_t task)
|
||||
{
|
||||
static constexpr repeated_t DEFAULT_REPEATED = 0;
|
||||
return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, std::move(task))));
|
||||
return InsertTask(std::make_shared<Task>(end + time, time, group, DEFAULT_REPEATED, std::move(task)));
|
||||
}
|
||||
|
||||
void TaskScheduler::Dispatch(success_t const& callback/* = nullptr*/)
|
||||
@@ -158,17 +189,6 @@ void TaskScheduler::Dispatch(success_t const& callback/* = nullptr*/)
|
||||
if (!_predicate())
|
||||
return;
|
||||
|
||||
// Process all asyncs
|
||||
while (!_asyncHolder.empty())
|
||||
{
|
||||
_asyncHolder.front()();
|
||||
_asyncHolder.pop();
|
||||
|
||||
// If the validation failed abort the dispatching here.
|
||||
if (!_predicate())
|
||||
return;
|
||||
}
|
||||
|
||||
while (!_task_holder.IsEmpty())
|
||||
{
|
||||
if (_task_holder.First()->_end > _now)
|
||||
@@ -196,14 +216,17 @@ void TaskScheduler::TaskQueue::Push(TaskContainer&& task)
|
||||
container.emplace(std::move(task));
|
||||
}
|
||||
|
||||
auto TaskScheduler::TaskQueue::Pop() -> TaskContainer
|
||||
void TaskScheduler::TaskQueue::Push(Container::node_type&& node)
|
||||
{
|
||||
TaskContainer result = *container.begin();
|
||||
container.erase(container.begin());
|
||||
return result;
|
||||
container.insert(std::move(node));
|
||||
}
|
||||
|
||||
auto TaskScheduler::TaskQueue::First() const -> TaskContainer const&
|
||||
TaskScheduler::TaskQueue::Container::node_type TaskScheduler::TaskQueue::Pop()
|
||||
{
|
||||
return container.extract(container.begin());
|
||||
}
|
||||
|
||||
TaskScheduler::TaskContainer const& TaskScheduler::TaskQueue::First() const
|
||||
{
|
||||
return *container.begin();
|
||||
}
|
||||
@@ -224,17 +247,14 @@ void TaskScheduler::TaskQueue::RemoveIf(std::function<bool(TaskContainer const&)
|
||||
|
||||
void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter)
|
||||
{
|
||||
std::vector<TaskContainer> cache;
|
||||
Container cache;
|
||||
for (auto itr = container.begin(); itr != container.end();)
|
||||
if (filter(*itr))
|
||||
{
|
||||
cache.push_back(*itr);
|
||||
itr = container.erase(itr);
|
||||
}
|
||||
cache.insert(container.extract(itr++));
|
||||
else
|
||||
++itr;
|
||||
|
||||
container.insert(cache.begin(), cache.end());
|
||||
container.merge(cache);
|
||||
}
|
||||
|
||||
bool TaskScheduler::TaskQueue::IsEmpty() const
|
||||
@@ -242,11 +262,47 @@ bool TaskScheduler::TaskQueue::IsEmpty() const
|
||||
return container.empty();
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
|
||||
TaskScheduler::TaskContainer& TaskContext::GetTaskContainer() noexcept
|
||||
{
|
||||
if (std::shared_ptr<TaskScheduler> owner = _owner.lock())
|
||||
apply(*owner);
|
||||
static_assert(std::variant_size_v<decltype(_task)> == 2);
|
||||
switch (_task.index())
|
||||
{
|
||||
case 0: return std::get<0>(_task).value();
|
||||
case 1: return std::get<1>(_task);
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
TaskScheduler::Task* TaskContext::GetTask() const noexcept
|
||||
{
|
||||
static_assert(std::variant_size_v<decltype(_task)> == 2);
|
||||
switch (_task.index())
|
||||
{
|
||||
case 0: return std::get<0>(_task).value().get();
|
||||
case 1: return std::get<1>(_task).get();
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
TaskContext::TaskContext(TaskContext&& right) noexcept
|
||||
: _task(std::move(right._task)), _owner(std::move(right._owner))
|
||||
{
|
||||
//leave moved-from object in usable state (const qualified functions need to remain callable)
|
||||
right._task = GetTaskContainer();
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::operator=(TaskContext&& right) noexcept
|
||||
{
|
||||
if (this != &right)
|
||||
{
|
||||
_task = std::move(right._task);
|
||||
_owner = std::move(right._owner);
|
||||
|
||||
//leave moved-from object in usable state (const qualified functions need to remain callable)
|
||||
right._task = GetTaskContainer();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -255,130 +311,134 @@ bool TaskContext::IsExpired() const
|
||||
return _owner.expired();
|
||||
}
|
||||
|
||||
bool TaskContext::IsInGroup(TaskScheduler::group_t const group) const
|
||||
bool TaskContext::IsInGroup(TaskScheduler::group_t group) const
|
||||
{
|
||||
return _task->IsInGroup(group);
|
||||
return GetTask()->IsInGroup(group);
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::SetGroup(TaskScheduler::group_t const group)
|
||||
TaskContext& TaskContext::SetGroup(TaskScheduler::group_t group)
|
||||
{
|
||||
_task->_group = group;
|
||||
GetTask()->_group = group;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::ClearGroup()
|
||||
{
|
||||
_task->_group = std::nullopt;
|
||||
GetTask()->_group = std::nullopt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler::repeated_t TaskContext::GetRepeatCounter() const
|
||||
{
|
||||
return _task->_repeated;
|
||||
return GetTask()->_repeated;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::Repeat(TaskScheduler::duration_t duration)
|
||||
{
|
||||
AssertOnConsumed();
|
||||
// If you encounter this assertion check if you repeat a TaskContext more then 1 time!
|
||||
ASSERT(std::holds_alternative<TaskScheduler::TaskQueue::Container::node_type>(_task), "Bad task logic, task context was consumed already!");
|
||||
|
||||
// Set new duration, in-context timing and increment repeat counter
|
||||
_task->_duration = duration;
|
||||
_task->_end += duration;
|
||||
_task->_repeated += 1;
|
||||
(*_consumed) = true;
|
||||
return this->Dispatch([this](TaskScheduler& scheduler) -> TaskScheduler&
|
||||
{
|
||||
return scheduler.InsertTask(_task);
|
||||
});
|
||||
TaskScheduler::TaskQueue::Container::node_type& taskNode = std::get<TaskScheduler::TaskQueue::Container::node_type>(_task);
|
||||
TaskScheduler::TaskContainer task = taskNode.value();
|
||||
task->_duration = duration;
|
||||
task->_end += duration;
|
||||
task->_repeated += 1;
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->InsertTask(std::move(taskNode));
|
||||
|
||||
//leave *this in usable state (const qualified functions need to remain callable)
|
||||
_task = std::move(task);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::Async(std::function<void()> const& callable)
|
||||
TaskContext& TaskContext::Repeat()
|
||||
{
|
||||
return Dispatch([&](TaskScheduler& scheduler) -> TaskScheduler&
|
||||
{
|
||||
return scheduler.Async(callable);
|
||||
});
|
||||
return Repeat(GetTask()->_duration);
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::Async(std::function<void()> callable)
|
||||
{
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->Async(std::move(callable));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::Schedule(TaskScheduler::duration_t time, TaskScheduler::task_handler_t task)
|
||||
{
|
||||
auto const end = _task->_end;
|
||||
return this->Dispatch([end, time, task = std::move(task)](TaskScheduler& scheduler) mutable -> TaskScheduler&
|
||||
{
|
||||
return scheduler.ScheduleAt(end, time, std::move(task));
|
||||
});
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->ScheduleAt(GetTask()->_end, time, std::move(task));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::Schedule(TaskScheduler::duration_t time, TaskScheduler::group_t const group, TaskScheduler::task_handler_t task)
|
||||
TaskContext& TaskContext::Schedule(TaskScheduler::duration_t time, TaskScheduler::group_t group, TaskScheduler::task_handler_t task)
|
||||
{
|
||||
auto const end = _task->_end;
|
||||
return this->Dispatch([end, time, group, task = std::move(task)](TaskScheduler& scheduler) mutable -> TaskScheduler&
|
||||
{
|
||||
return scheduler.ScheduleAt(end, time, group, std::move(task));
|
||||
});
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->ScheduleAt(GetTask()->_end, time, group, std::move(task));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::CancelAll()
|
||||
{
|
||||
return Dispatch(&TaskScheduler::CancelAll);
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->CancelAll();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::CancelGroup(TaskScheduler::group_t const group)
|
||||
TaskContext& TaskContext::CancelGroup(TaskScheduler::group_t group)
|
||||
{
|
||||
return Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler&
|
||||
{
|
||||
return scheduler.CancelGroup(group);
|
||||
});
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->CancelGroup(group);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups)
|
||||
TaskContext& TaskContext::CancelGroupsOf(std::span<TaskScheduler::group_t> groups)
|
||||
{
|
||||
return Dispatch([&](TaskScheduler& scheduler) -> TaskScheduler&
|
||||
{
|
||||
return scheduler.CancelGroupsOf(groups);
|
||||
});
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->CancelGroupsOf(groups);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::DelayAll(TaskScheduler::duration_t duration)
|
||||
{
|
||||
return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler&
|
||||
{
|
||||
return scheduler.DelayAll(duration);
|
||||
});
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->DelayAll(duration);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::DelayGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration)
|
||||
TaskContext& TaskContext::DelayGroup(TaskScheduler::group_t group, TaskScheduler::duration_t duration)
|
||||
{
|
||||
return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler&
|
||||
{
|
||||
return scheduler.DelayGroup(group, duration);
|
||||
});
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->DelayGroup(group, duration);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::RescheduleAll(TaskScheduler::duration_t duration)
|
||||
{
|
||||
return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler&
|
||||
{
|
||||
return scheduler.RescheduleAll(duration);
|
||||
});
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->RescheduleAll(duration);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContext& TaskContext::RescheduleGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration)
|
||||
TaskContext& TaskContext::RescheduleGroup(TaskScheduler::group_t group, TaskScheduler::duration_t duration)
|
||||
{
|
||||
return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler&
|
||||
{
|
||||
return scheduler.RescheduleGroup(group, duration);
|
||||
});
|
||||
}
|
||||
if (std::shared_ptr<TaskScheduler> scheduler = _owner.lock())
|
||||
scheduler->RescheduleGroup(group, duration);
|
||||
|
||||
void TaskContext::AssertOnConsumed() const
|
||||
{
|
||||
// This was adapted to TC to prevent static analysis tools from complaining.
|
||||
// If you encounter this assertion check if you repeat a TaskContext more then 1 time!
|
||||
ASSERT(!(*_consumed) && "Bad task logic, task context was consumed already!");
|
||||
return *this;
|
||||
}
|
||||
|
||||
void TaskContext::Invoke()
|
||||
{
|
||||
_task->_task(*this);
|
||||
GetTask()->_task(std::move(*this));
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
#include "Random.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
class TaskContext;
|
||||
|
||||
@@ -58,7 +58,7 @@ class TC_COMMON_API TaskScheduler
|
||||
// Task repeated type
|
||||
typedef uint32 repeated_t;
|
||||
// Task handle type
|
||||
typedef std::function<void(TaskContext)> task_handler_t;
|
||||
typedef std::function<void(TaskContext&&)> task_handler_t;
|
||||
// Predicate type
|
||||
typedef std::function<bool()> predicate_t;
|
||||
// Success handle type
|
||||
@@ -90,7 +90,7 @@ class TC_COMMON_API TaskScheduler
|
||||
// Move construct
|
||||
Task(Task&&) = delete;
|
||||
// Copy Assign
|
||||
Task& operator= (Task const&) = default;
|
||||
Task& operator= (Task const&) = delete;
|
||||
// Move Assign
|
||||
Task& operator= (Task&& right) = delete;
|
||||
|
||||
@@ -128,14 +128,21 @@ class TC_COMMON_API TaskScheduler
|
||||
|
||||
class TC_COMMON_API TaskQueue
|
||||
{
|
||||
std::multiset<TaskContainer, Compare> container;
|
||||
public:
|
||||
typedef std::multiset<TaskContainer, Compare> Container;
|
||||
|
||||
private:
|
||||
Container container;
|
||||
|
||||
public:
|
||||
// Pushes the task in the container
|
||||
void Push(TaskContainer&& task);
|
||||
|
||||
// Pushes the task in the container
|
||||
void Push(Container::node_type&& node);
|
||||
|
||||
/// Pops the task out of the container
|
||||
TaskContainer Pop();
|
||||
Container::node_type Pop();
|
||||
|
||||
TaskContainer const& First() const;
|
||||
|
||||
@@ -157,12 +164,6 @@ class TC_COMMON_API TaskScheduler
|
||||
/// The Task Queue which contains all task objects.
|
||||
TaskQueue _task_holder;
|
||||
|
||||
typedef std::queue<std::function<void()>> AsyncHolder;
|
||||
|
||||
/// Contains all asynchronous tasks which will be invoked at
|
||||
/// the next update tick.
|
||||
AsyncHolder _asyncHolder;
|
||||
|
||||
predicate_t _predicate;
|
||||
|
||||
static bool EmptyValidator()
|
||||
@@ -195,17 +196,28 @@ public:
|
||||
/// Clears the validator which is asked if tasks are allowed to be executed.
|
||||
TaskScheduler& ClearValidator();
|
||||
|
||||
static success_t const EmptySuccessCallback;
|
||||
|
||||
/// Update the scheduler to the current time.
|
||||
TaskScheduler& Update();
|
||||
|
||||
/// Update the scheduler to the current time.
|
||||
/// Calls the optional callback on successfully finish.
|
||||
TaskScheduler& Update(success_t const& callback = nullptr);
|
||||
TaskScheduler& Update(success_t callback);
|
||||
|
||||
/// Update the scheduler with a difftime in ms.
|
||||
TaskScheduler& Update(size_t milliseconds);
|
||||
|
||||
/// Update the scheduler with a difftime in ms.
|
||||
/// Calls the optional callback on successfully finish.
|
||||
TaskScheduler& Update(size_t milliseconds, success_t const& callback = nullptr);
|
||||
TaskScheduler& Update(size_t milliseconds, success_t callback);
|
||||
|
||||
/// Update the scheduler with a difftime.
|
||||
TaskScheduler& Update(duration_t difftime);
|
||||
|
||||
/// Update the scheduler with a difftime.
|
||||
/// Calls the optional callback on successfully finish.
|
||||
TaskScheduler& Update(duration_t difftime, success_t const& callback = nullptr);
|
||||
TaskScheduler& Update(duration_t difftime, success_t callback);
|
||||
|
||||
/// Schedule an callable function that is executed at the next update tick.
|
||||
/// Its safe to modify the TaskScheduler from within the callable.
|
||||
@@ -222,7 +234,7 @@ public:
|
||||
/// Schedule an event with a fixed rate.
|
||||
/// Never call this from within a task context! Use TaskContext::Schedule instead!
|
||||
TaskScheduler& Schedule(duration_t time,
|
||||
group_t const group, task_handler_t task)
|
||||
group_t group, task_handler_t task)
|
||||
{
|
||||
return this->ScheduleAt(_now, time, group, std::move(task));
|
||||
}
|
||||
@@ -238,7 +250,7 @@ public:
|
||||
/// Schedule an event with a fixed rate.
|
||||
/// Never call this from within a task context! Use TaskContext::Schedule instead!
|
||||
TaskScheduler& Schedule(std::chrono::milliseconds min,
|
||||
std::chrono::milliseconds max, group_t const group,
|
||||
std::chrono::milliseconds max, group_t group,
|
||||
task_handler_t task)
|
||||
{
|
||||
return this->Schedule(::randtime(min, max), group, std::move(task));
|
||||
@@ -252,9 +264,9 @@ public:
|
||||
/// Never call this from within a task context! Use TaskContext::CancelGroup instead!
|
||||
TaskScheduler& CancelGroup(group_t group);
|
||||
|
||||
/// Cancels all groups in the given std::vector.
|
||||
/// Cancels all groups in the given std::span.
|
||||
/// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
|
||||
TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups);
|
||||
TaskScheduler& CancelGroupsOf(std::span<group_t> groups);
|
||||
|
||||
/// Delays all tasks with the given duration.
|
||||
TaskScheduler& DelayAll(duration_t duration);
|
||||
@@ -267,10 +279,10 @@ public:
|
||||
}
|
||||
|
||||
/// Delays all tasks of a group with the given duration.
|
||||
TaskScheduler& DelayGroup(group_t const group, duration_t duration);
|
||||
TaskScheduler& DelayGroup(group_t group, duration_t duration);
|
||||
|
||||
/// Delays all tasks of a group with a random duration between min and max.
|
||||
TaskScheduler& DelayGroup(group_t const group,
|
||||
TaskScheduler& DelayGroup(group_t group,
|
||||
std::chrono::milliseconds min,
|
||||
std::chrono::milliseconds max)
|
||||
{
|
||||
@@ -287,10 +299,10 @@ public:
|
||||
}
|
||||
|
||||
/// Reschedule all tasks of a group with the given duration.
|
||||
TaskScheduler& RescheduleGroup(group_t const group, duration_t duration);
|
||||
TaskScheduler& RescheduleGroup(group_t group, duration_t duration);
|
||||
|
||||
/// Reschedule all tasks of a group with a random duration between min and max.
|
||||
TaskScheduler& RescheduleGroup(group_t const group,
|
||||
TaskScheduler& RescheduleGroup(group_t group,
|
||||
std::chrono::milliseconds min,
|
||||
std::chrono::milliseconds max)
|
||||
{
|
||||
@@ -299,7 +311,10 @@ public:
|
||||
|
||||
private:
|
||||
/// Insert a new task to the enqueued tasks.
|
||||
TaskScheduler& InsertTask(TaskContainer task);
|
||||
TaskScheduler& InsertTask(TaskContainer&& task);
|
||||
|
||||
/// Insert a new task to the enqueued tasks.
|
||||
TaskScheduler& InsertTask(TaskQueue::Container::node_type&& node);
|
||||
|
||||
TaskScheduler& ScheduleAt(timepoint_t end,
|
||||
duration_t time, task_handler_t task);
|
||||
@@ -308,7 +323,7 @@ private:
|
||||
/// Never call this from within a task context! Use TaskContext::schedule instead!
|
||||
TaskScheduler& ScheduleAt(timepoint_t end,
|
||||
duration_t time,
|
||||
group_t const group, task_handler_t task);
|
||||
group_t group, task_handler_t task);
|
||||
|
||||
/// Dispatch remaining tasks
|
||||
void Dispatch(success_t const& callback);
|
||||
@@ -319,37 +334,36 @@ class TC_COMMON_API TaskContext
|
||||
friend class TaskScheduler;
|
||||
|
||||
/// Associated task
|
||||
TaskScheduler::TaskContainer _task;
|
||||
std::variant<TaskScheduler::TaskQueue::Container::node_type /*not consumed*/,
|
||||
TaskScheduler::TaskContainer /*consumed*/> _task;
|
||||
|
||||
/// Owner
|
||||
std::weak_ptr<TaskScheduler> _owner;
|
||||
|
||||
/// Marks the task as consumed
|
||||
std::shared_ptr<bool> _consumed;
|
||||
TaskScheduler::TaskContainer& GetTaskContainer() noexcept;
|
||||
|
||||
/// Dispatches an action safe on the TaskScheduler
|
||||
TaskContext& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply);
|
||||
TaskScheduler::Task* GetTask() const noexcept;
|
||||
|
||||
public:
|
||||
// Empty constructor
|
||||
TaskContext()
|
||||
: _task(), _owner(), _consumed(std::make_shared<bool>(true)) { }
|
||||
TaskContext() noexcept
|
||||
: _task(), _owner() { }
|
||||
|
||||
// Construct from task and owner
|
||||
explicit TaskContext(TaskScheduler::TaskContainer&& task, std::weak_ptr<TaskScheduler>&& owner)
|
||||
: _task(std::move(task)), _owner(std::move(owner)), _consumed(std::make_shared<bool>(false)) { }
|
||||
explicit TaskContext(TaskScheduler::TaskQueue::Container::node_type&& task, std::weak_ptr<TaskScheduler>&& owner) noexcept
|
||||
: _task(std::move(task)), _owner(std::move(owner)) { }
|
||||
|
||||
// Copy construct
|
||||
TaskContext(TaskContext const& right) = default;
|
||||
TaskContext(TaskContext const& right) = delete;
|
||||
|
||||
// Move construct
|
||||
TaskContext(TaskContext&& right) noexcept = default;
|
||||
TaskContext(TaskContext&& right) noexcept;
|
||||
|
||||
// Copy assign
|
||||
TaskContext& operator=(TaskContext const& right) = default;
|
||||
TaskContext& operator=(TaskContext const& right) = delete;
|
||||
|
||||
// Move assign
|
||||
TaskContext& operator=(TaskContext&& right) noexcept = default;
|
||||
TaskContext& operator=(TaskContext&& right) noexcept;
|
||||
|
||||
~TaskContext() = default;
|
||||
|
||||
@@ -357,10 +371,10 @@ public:
|
||||
bool IsExpired() const;
|
||||
|
||||
/// Returns true if the event is in the given group
|
||||
bool IsInGroup(TaskScheduler::group_t const group) const;
|
||||
bool IsInGroup(TaskScheduler::group_t group) const;
|
||||
|
||||
/// Sets the event in the given group
|
||||
TaskContext& SetGroup(TaskScheduler::group_t const group);
|
||||
TaskContext& SetGroup(TaskScheduler::group_t group);
|
||||
|
||||
/// Removes the group from the event
|
||||
TaskContext& ClearGroup();
|
||||
@@ -377,10 +391,7 @@ public:
|
||||
/// Repeats the event with the same duration.
|
||||
/// This will consume the task context, its not possible to repeat the task again
|
||||
/// from the same task context!
|
||||
TaskContext& Repeat()
|
||||
{
|
||||
return Repeat(_task->_duration);
|
||||
}
|
||||
TaskContext& Repeat();
|
||||
|
||||
/// Repeats the event and set a new duration that is randomized between min and max.
|
||||
/// std::chrono::seconds(5) for example.
|
||||
@@ -394,7 +405,7 @@ public:
|
||||
|
||||
/// Schedule a callable function that is executed at the next update tick from within the context.
|
||||
/// Its safe to modify the TaskScheduler from within the callable.
|
||||
TaskContext& Async(std::function<void()> const& callable);
|
||||
TaskContext& Async(std::function<void()> callable);
|
||||
|
||||
/// Schedule an event with a fixed rate from within the context.
|
||||
/// Its possible that the new event is executed immediately!
|
||||
@@ -408,7 +419,7 @@ public:
|
||||
/// Use TaskScheduler::Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
TaskContext& Schedule(TaskScheduler::duration_t time,
|
||||
TaskScheduler::group_t const group, TaskScheduler::task_handler_t task);
|
||||
TaskScheduler::group_t group, TaskScheduler::task_handler_t task);
|
||||
|
||||
/// Schedule an event with a randomized rate between min and max rate from within the context.
|
||||
/// Its possible that the new event is executed immediately!
|
||||
@@ -425,7 +436,7 @@ public:
|
||||
/// Use TaskScheduler::Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
TaskContext& Schedule(std::chrono::milliseconds min,
|
||||
std::chrono::milliseconds max, TaskScheduler::group_t const group,
|
||||
std::chrono::milliseconds max, TaskScheduler::group_t group,
|
||||
TaskScheduler::task_handler_t task)
|
||||
{
|
||||
return this->Schedule(::randtime(min, max), group, std::move(task));
|
||||
@@ -435,11 +446,11 @@ public:
|
||||
TaskContext& CancelAll();
|
||||
|
||||
/// Cancel all tasks of a single group from within the context.
|
||||
TaskContext& CancelGroup(TaskScheduler::group_t const group);
|
||||
TaskContext& CancelGroup(TaskScheduler::group_t group);
|
||||
|
||||
/// Cancels all groups in the given std::vector from within the context.
|
||||
/// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
|
||||
TaskContext& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups);
|
||||
TaskContext& CancelGroupsOf(std::span<TaskScheduler::group_t> groups);
|
||||
|
||||
/// Delays all tasks with the given duration from within the context.
|
||||
TaskContext& DelayAll(TaskScheduler::duration_t duration);
|
||||
@@ -452,10 +463,10 @@ public:
|
||||
}
|
||||
|
||||
/// Delays all tasks of a group with the given duration from within the context.
|
||||
TaskContext& DelayGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration);
|
||||
TaskContext& DelayGroup(TaskScheduler::group_t group, TaskScheduler::duration_t duration);
|
||||
|
||||
/// Delays all tasks of a group with a random duration between min and max from within the context.
|
||||
TaskContext& DelayGroup(TaskScheduler::group_t const group,
|
||||
TaskContext& DelayGroup(TaskScheduler::group_t group,
|
||||
std::chrono::milliseconds min,
|
||||
std::chrono::milliseconds max)
|
||||
{
|
||||
@@ -473,10 +484,10 @@ public:
|
||||
}
|
||||
|
||||
/// Reschedule all tasks of a group with the given duration.
|
||||
TaskContext& RescheduleGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration);
|
||||
TaskContext& RescheduleGroup(TaskScheduler::group_t group, TaskScheduler::duration_t duration);
|
||||
|
||||
/// Reschedule all tasks of a group with a random duration between min and max.
|
||||
TaskContext& RescheduleGroup(TaskScheduler::group_t const group,
|
||||
TaskContext& RescheduleGroup(TaskScheduler::group_t group,
|
||||
std::chrono::milliseconds min,
|
||||
std::chrono::milliseconds max)
|
||||
{
|
||||
@@ -484,9 +495,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
/// Asserts if the task was consumed already.
|
||||
void AssertOnConsumed() const;
|
||||
|
||||
/// Invokes the associated hook of the task.
|
||||
void Invoke();
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "TaskScheduler.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Vehicle.h"
|
||||
#include <queue>
|
||||
|
||||
namespace DeephaulRavine
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "SharedDefines.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "maw_of_souls.h"
|
||||
#include <queue>
|
||||
|
||||
enum YmironFallenKingSpells
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "SpellScript.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "WaypointDefines.h"
|
||||
#include <queue>
|
||||
|
||||
enum WoundedColdridgeMountaineer
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "ecodome_aldani.h"
|
||||
#include <queue>
|
||||
|
||||
enum AzhiccarSpells
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "TaskScheduler.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "CommonPredicates.h"
|
||||
#include <queue>
|
||||
|
||||
enum PriestSpells
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user