mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-18 08:28:32 +01:00
Core/Shared: Hide the internal shared_ptr of the TaskContext
* use . operator instead of -> to access the TaskContext now.
* Add TaskContext::IsExpired to check whether the owner has expired.
(cherry picked from commit 151a0f5c5e)
This commit is contained in:
@@ -62,7 +62,7 @@ TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups)
|
||||
|
||||
TaskScheduler& TaskScheduler::InsertTask(TaskContainer task)
|
||||
{
|
||||
_task_holder.Push(std::forward<TaskContainer>(task));
|
||||
_task_holder.Push(std::move(task));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -82,11 +82,10 @@ void TaskScheduler::Dispatch()
|
||||
|
||||
// Perfect forward the context to the handler
|
||||
// Use weak references to catch destruction before callbacks.
|
||||
TaskContext context(new TaskContextInstance(_task_holder.Pop(),
|
||||
std::weak_ptr<TaskScheduler>(self_reference)));
|
||||
TaskContext context(_task_holder.Pop(), std::weak_ptr<TaskScheduler>(self_reference));
|
||||
|
||||
// Invoke the context
|
||||
context->Invoke();
|
||||
context.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +140,7 @@ bool TaskScheduler::TaskQueue::IsEmpty() const
|
||||
return container.empty();
|
||||
}
|
||||
|
||||
TaskContextInstance& TaskContextInstance::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
|
||||
TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
|
||||
{
|
||||
if (auto const owner = _owner.lock())
|
||||
apply(*owner);
|
||||
@@ -149,56 +148,61 @@ TaskContextInstance& TaskContextInstance::Dispatch(std::function<TaskScheduler&(
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool TaskContextInstance::IsInGroup(TaskScheduler::group_t const group) const
|
||||
bool TaskContext::IsExpired() const
|
||||
{
|
||||
return _owner.expired();
|
||||
}
|
||||
|
||||
bool TaskContext::IsInGroup(TaskScheduler::group_t const group) const
|
||||
{
|
||||
return _task->IsInGroup(group);
|
||||
}
|
||||
|
||||
TaskContextInstance& TaskContextInstance::SetGroup(TaskScheduler::group_t const group)
|
||||
TaskContext& TaskContext::SetGroup(TaskScheduler::group_t const group)
|
||||
{
|
||||
_task->_group = group;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskContextInstance& TaskContextInstance::ClearGroup()
|
||||
TaskContext& TaskContext::ClearGroup()
|
||||
{
|
||||
_task->_group = boost::none;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskScheduler::repeated_t TaskContextInstance::GetRepeatCounter() const
|
||||
TaskScheduler::repeated_t TaskContext::GetRepeatCounter() const
|
||||
{
|
||||
return _task->_repeated;
|
||||
}
|
||||
|
||||
TaskContextInstance& TaskContextInstance::Async(std::function<void()> const& callable)
|
||||
TaskContext& TaskContext::Async(std::function<void()> const& callable)
|
||||
{
|
||||
return Dispatch(std::bind(&TaskScheduler::Async, std::placeholders::_1, callable));
|
||||
}
|
||||
|
||||
TaskContextInstance& TaskContextInstance::CancelAll()
|
||||
TaskContext& TaskContext::CancelAll()
|
||||
{
|
||||
return Dispatch(std::mem_fn(&TaskScheduler::CancelAll));
|
||||
}
|
||||
|
||||
TaskContextInstance& TaskContextInstance::CancelGroup(TaskScheduler::group_t const group)
|
||||
TaskContext& TaskContext::CancelGroup(TaskScheduler::group_t const group)
|
||||
{
|
||||
return Dispatch(std::bind(&TaskScheduler::CancelGroup, std::placeholders::_1, group));
|
||||
}
|
||||
|
||||
TaskContextInstance& TaskContextInstance::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups)
|
||||
TaskContext& TaskContext::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups)
|
||||
{
|
||||
return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, groups));
|
||||
return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, std::cref(groups)));
|
||||
}
|
||||
|
||||
void TaskContextInstance::AssertOnConsumed()
|
||||
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(_task && "Bad task logic, task context was consumed already!");
|
||||
ASSERT(!(*_consumed) && "Bad task logic, task context was consumed already!");
|
||||
}
|
||||
|
||||
void TaskContextInstance::Invoke()
|
||||
void TaskContext::Invoke()
|
||||
{
|
||||
_task->_task(shared_from_this());
|
||||
_task->_task(*this);
|
||||
}
|
||||
|
||||
@@ -30,9 +30,7 @@
|
||||
|
||||
#include "Util.h"
|
||||
|
||||
class TaskContextInstance;
|
||||
|
||||
typedef std::shared_ptr<TaskContextInstance> TaskContext;
|
||||
class TaskContext;
|
||||
|
||||
/// The TaskScheduler class provides the ability to schedule std::function's in the near future.
|
||||
/// Use TaskScheduler::Update to update the scheduler.
|
||||
@@ -49,7 +47,7 @@ typedef std::shared_ptr<TaskContextInstance> TaskContext;
|
||||
/// but behave different every time (spoken event dialogs for example).
|
||||
class TaskScheduler
|
||||
{
|
||||
friend class TaskContextInstance;
|
||||
friend class TaskContext;
|
||||
|
||||
// Time definitions (use steady clock)
|
||||
typedef std::chrono::steady_clock clock_t;
|
||||
@@ -65,7 +63,7 @@ class TaskScheduler
|
||||
|
||||
class Task
|
||||
{
|
||||
friend class TaskContextInstance;
|
||||
friend class TaskContext;
|
||||
friend class TaskScheduler;
|
||||
|
||||
timepoint_t _end;
|
||||
@@ -360,8 +358,8 @@ private:
|
||||
|
||||
// Returns a random duration between min and max
|
||||
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
|
||||
std::chrono::milliseconds
|
||||
static RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
static std::chrono::milliseconds
|
||||
RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
std::chrono::duration<_RepRight, _PeriodRight> const& max)
|
||||
{
|
||||
auto const milli_min = std::chrono::duration_cast<std::chrono::milliseconds>(min);
|
||||
@@ -375,8 +373,7 @@ private:
|
||||
void Dispatch();
|
||||
};
|
||||
|
||||
class TaskContextInstance
|
||||
: public std::enable_shared_from_this<TaskContextInstance>
|
||||
class TaskContext
|
||||
{
|
||||
friend class TaskScheduler;
|
||||
|
||||
@@ -384,23 +381,60 @@ class TaskContextInstance
|
||||
TaskScheduler::TaskContainer _task;
|
||||
|
||||
/// Owner
|
||||
std::weak_ptr<TaskScheduler> const _owner;
|
||||
std::weak_ptr<TaskScheduler> _owner;
|
||||
|
||||
/// Marks the task as consumed
|
||||
std::shared_ptr<bool> _consumed;
|
||||
|
||||
/// Dispatches an action safe on the TaskScheduler
|
||||
TaskContextInstance& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply);
|
||||
TaskContext& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply);
|
||||
|
||||
public:
|
||||
explicit TaskContextInstance(TaskScheduler::TaskContainer task, std::weak_ptr<TaskScheduler>&& owner)
|
||||
: _task(task), _owner(owner) { }
|
||||
// Empty constructor
|
||||
TaskContext()
|
||||
: _task(), _owner(), _consumed(std::make_shared<bool>(true)) { }
|
||||
|
||||
// Construct from task and owner
|
||||
explicit TaskContext(TaskScheduler::TaskContainer&& task, std::weak_ptr<TaskScheduler>&& owner)
|
||||
: _task(task), _owner(owner), _consumed(std::make_shared<bool>(false)) { }
|
||||
|
||||
// Copy construct
|
||||
TaskContext(TaskContext const& right)
|
||||
: _task(right._task), _owner(right._owner), _consumed(right._consumed) { }
|
||||
|
||||
// Move construct
|
||||
TaskContext(TaskContext&& right)
|
||||
: _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)) { }
|
||||
|
||||
// Copy assign
|
||||
TaskContext& operator= (TaskContext const& right)
|
||||
{
|
||||
_task = right._task;
|
||||
_owner = right._owner;
|
||||
_consumed = right._consumed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Move assign
|
||||
TaskContext& operator= (TaskContext&& right)
|
||||
{
|
||||
_task = std::move(right._task);
|
||||
_owner = std::move(right._owner);
|
||||
_consumed = std::move(right._consumed);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Returns true if the owner was deallocated and this context has expired.
|
||||
bool IsExpired() const;
|
||||
|
||||
/// Returns true if the event is in the given group
|
||||
bool IsInGroup(TaskScheduler::group_t const group) const;
|
||||
|
||||
/// Sets the event in the given group
|
||||
TaskContextInstance& SetGroup(TaskScheduler::group_t const group);
|
||||
TaskContext& SetGroup(TaskScheduler::group_t const group);
|
||||
|
||||
/// Removes the group from the event
|
||||
TaskContextInstance& ClearGroup();
|
||||
TaskContext& ClearGroup();
|
||||
|
||||
/// Returns the repeat counter which increases every time the task is repeated.
|
||||
TaskScheduler::repeated_t GetRepeatCounter() const;
|
||||
@@ -410,7 +444,7 @@ public:
|
||||
/// This will consume the task context, its not possible to repeat the task again
|
||||
/// from the same task context!
|
||||
template<class _Rep, class _Period>
|
||||
TaskContextInstance& Repeat(std::chrono::duration<_Rep, _Period> const& duration)
|
||||
TaskContext& Repeat(std::chrono::duration<_Rep, _Period> const& duration)
|
||||
{
|
||||
AssertOnConsumed();
|
||||
|
||||
@@ -418,13 +452,14 @@ public:
|
||||
_task->_duration = duration;
|
||||
_task->_end += duration;
|
||||
_task->_repeated += 1;
|
||||
(*_consumed) = true;
|
||||
return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task));
|
||||
}
|
||||
|
||||
/// 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!
|
||||
TaskContextInstance& Repeat()
|
||||
TaskContext& Repeat()
|
||||
{
|
||||
return Repeat(_task->_duration);
|
||||
}
|
||||
@@ -434,7 +469,7 @@ public:
|
||||
/// This will consume the task context, its not possible to repeat the task again
|
||||
/// from the same task context!
|
||||
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
|
||||
TaskContextInstance& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
TaskContext& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
std::chrono::duration<_RepRight, _PeriodRight> const& max)
|
||||
{
|
||||
return Repeat(TaskScheduler::RandomDurationBetween(min, max));
|
||||
@@ -442,14 +477,14 @@ 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.
|
||||
TaskContextInstance& Async(std::function<void()> const& callable);
|
||||
TaskContext& Async(std::function<void()> const& callable);
|
||||
|
||||
/// Schedule an event with a fixed rate from within the context.
|
||||
/// Its possible that the new event is executed immediately!
|
||||
/// Use TaskScheduler::Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
template<class _Rep, class _Period>
|
||||
TaskContextInstance& Schedule(std::chrono::duration<_Rep, _Period> const& time,
|
||||
TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time,
|
||||
TaskScheduler::task_handler_t const& task)
|
||||
{
|
||||
auto const end = _task->_end;
|
||||
@@ -464,7 +499,7 @@ public:
|
||||
/// Use TaskScheduler::Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
template<class _Rep, class _Period>
|
||||
TaskContextInstance& Schedule(std::chrono::duration<_Rep, _Period> const& time,
|
||||
TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time,
|
||||
TaskScheduler::group_t const group, TaskScheduler::task_handler_t const& task)
|
||||
{
|
||||
auto const end = _task->_end;
|
||||
@@ -479,7 +514,7 @@ public:
|
||||
/// Use TaskScheduler::Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
|
||||
TaskContextInstance& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task)
|
||||
{
|
||||
return Schedule(TaskScheduler::RandomDurationBetween(min, max), task);
|
||||
@@ -490,7 +525,7 @@ public:
|
||||
/// Use TaskScheduler::Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
|
||||
TaskContextInstance& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group,
|
||||
TaskScheduler::task_handler_t const& task)
|
||||
{
|
||||
@@ -498,25 +533,25 @@ public:
|
||||
}
|
||||
|
||||
/// Cancels all tasks from within the context.
|
||||
TaskContextInstance& CancelAll();
|
||||
TaskContext& CancelAll();
|
||||
|
||||
/// Cancel all tasks of a single group from within the context.
|
||||
TaskContextInstance& CancelGroup(TaskScheduler::group_t const group);
|
||||
TaskContext& CancelGroup(TaskScheduler::group_t const group);
|
||||
|
||||
/// Cancels all groups in the given std::vector from within the context.
|
||||
/// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
|
||||
TaskContextInstance& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups);
|
||||
TaskContext& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups);
|
||||
|
||||
/// Delays all tasks with the given duration from within the context.
|
||||
template<class _Rep, class _Period>
|
||||
TaskContextInstance& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
|
||||
TaskContext& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
|
||||
{
|
||||
return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, duration));
|
||||
}
|
||||
|
||||
/// Delays all tasks with a random duration between min and max from within the context.
|
||||
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
|
||||
TaskContextInstance& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
TaskContext& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
std::chrono::duration<_RepRight, _PeriodRight> const& max)
|
||||
{
|
||||
return DelayAll(TaskScheduler::RandomDurationBetween(min, max));
|
||||
@@ -524,14 +559,14 @@ public:
|
||||
|
||||
/// Delays all tasks of a group with the given duration from within the context.
|
||||
template<class _Rep, class _Period>
|
||||
TaskContextInstance& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
|
||||
TaskContext& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
|
||||
{
|
||||
return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
|
||||
}
|
||||
|
||||
/// Delays all tasks of a group with a random duration between min and max from within the context.
|
||||
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
|
||||
TaskContextInstance& DelayGroup(TaskScheduler::group_t const group,
|
||||
TaskContext& DelayGroup(TaskScheduler::group_t const group,
|
||||
std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
std::chrono::duration<_RepRight, _PeriodRight> const& max)
|
||||
{
|
||||
@@ -540,14 +575,14 @@ public:
|
||||
|
||||
/// Reschedule all tasks with the given duration.
|
||||
template<class _Rep, class _Period>
|
||||
TaskContextInstance& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
|
||||
TaskContext& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
|
||||
{
|
||||
return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, duration));
|
||||
}
|
||||
|
||||
/// Reschedule all tasks with a random duration between min and max.
|
||||
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
|
||||
TaskContextInstance& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
TaskContext& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
std::chrono::duration<_RepRight, _PeriodRight> const& max)
|
||||
{
|
||||
return RescheduleAll(TaskScheduler::RandomDurationBetween(min, max));
|
||||
@@ -555,14 +590,14 @@ public:
|
||||
|
||||
/// Reschedule all tasks of a group with the given duration.
|
||||
template<class _Rep, class _Period>
|
||||
TaskContextInstance& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
|
||||
TaskContext& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
|
||||
{
|
||||
return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
|
||||
}
|
||||
|
||||
/// Reschedule all tasks of a group with a random duration between min and max.
|
||||
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
|
||||
TaskContextInstance& RescheduleGroup(TaskScheduler::group_t const group,
|
||||
TaskContext& RescheduleGroup(TaskScheduler::group_t const group,
|
||||
std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
|
||||
std::chrono::duration<_RepRight, _PeriodRight> const& max)
|
||||
{
|
||||
@@ -570,7 +605,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void AssertOnConsumed();
|
||||
/// Asserts if the task was consumed already.
|
||||
void AssertOnConsumed() const;
|
||||
|
||||
/// Invokes the associated hook of the task.
|
||||
void Invoke();
|
||||
|
||||
Reference in New Issue
Block a user