TrinityCore
Loading...
Searching...
No Matches
TaskScheduler.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef _TASK_SCHEDULER_H_
19#define _TASK_SCHEDULER_H_
20
21#include "Duration.h"
22#include "Optional.h"
23#include "Random.h"
24#include <algorithm>
25#include <functional>
26#include <vector>
27#include <queue>
28#include <memory>
29#include <utility>
30#include <set>
31
32class TaskContext;
33
48{
49 friend class TaskContext;
50
51 // Time definitions (use steady clock)
52 typedef std::chrono::steady_clock clock_t;
53 typedef clock_t::time_point timepoint_t;
54 typedef clock_t::duration duration_t;
55
56 // Task group type
57 typedef uint32 group_t;
58 // Task repeated type
60 // Task handle type
61 typedef std::function<void(TaskContext)> task_handler_t;
62 // Predicate type
63 typedef std::function<bool()> predicate_t;
64 // Success handle type
65 typedef std::function<void()> success_t;
66
67 class Task
68 {
69 friend class TaskContext;
70 friend class TaskScheduler;
71
77
78 public:
79 // All Argument construct
80 Task(timepoint_t const& end, duration_t const& duration, Optional<group_t> const& group,
81 repeated_t const repeated, task_handler_t const& task)
82 : _end(end), _duration(duration), _group(group), _repeated(repeated), _task(task) { }
83
84 // Minimal Argument construct
85 Task(timepoint_t const& end, duration_t const& duration, task_handler_t const& task)
86 : _end(end), _duration(duration), _group(std::nullopt), _repeated(0), _task(task) { }
87
88 // Copy construct
89 Task(Task const&) = delete;
90 // Move construct
91 Task(Task&&) = delete;
92 // Copy Assign
93 Task& operator= (Task const&) = default;
94 // Move Assign
95 Task& operator= (Task&& right) = delete;
96
97 // Order tasks by its end
98 std::weak_ordering operator<=> (Task const& other) const
99 {
100 return std::compare_weak_order_fallback(_end, other._end);
101 }
102
103 // Compare tasks with its end
104 bool operator== (Task const& other) const
105 {
106 return _end == other._end;
107 }
108
109 // Returns true if the task is in the given group
110 inline bool IsInGroup(group_t const group) const
111 {
112 return _group == group;
113 }
114 };
115
116 typedef std::shared_ptr<Task> TaskContainer;
117
119 struct Compare
120 {
121 bool operator() (TaskContainer const& left, TaskContainer const& right) const
122 {
123 return (*left.get()) < (*right.get());
124 }
125 };
126
128 {
129 std::multiset<TaskContainer, Compare> container;
130
131 public:
132 // Pushes the task in the container
133 void Push(TaskContainer&& task);
134
136 TaskContainer Pop();
137
138 TaskContainer const& First() const;
139
140 void Clear();
141
142 void RemoveIf(std::function<bool(TaskContainer const&)> const& filter);
143
144 void ModifyIf(std::function<bool(TaskContainer const&)> const& filter);
145
146 bool IsEmpty() const;
147 };
148
150 std::shared_ptr<TaskScheduler> self_reference;
151
154
157
158 typedef std::queue<std::function<void()>> AsyncHolder;
159
163
165
166 static bool EmptyValidator()
167 {
168 return true;
169 }
170
171 static void EmptyCallback()
172 {
173 }
174
175public:
177 : self_reference(this, [](TaskScheduler const*) { }), _now(clock_t::now()), _predicate(EmptyValidator) { }
178
179 template<typename P>
180 TaskScheduler(P&& predicate)
181 : self_reference(this, [](TaskScheduler const*) { }), _now(clock_t::now()), _predicate(std::forward<P>(predicate)) { }
182
183 TaskScheduler(TaskScheduler const&) = delete;
185 TaskScheduler& operator= (TaskScheduler const&) = delete;
186 TaskScheduler& operator= (TaskScheduler&&) = delete;
187
189 template<typename P>
191 {
192 _predicate = std::forward<P>(predicate);
193 return *this;
194 }
195
197 TaskScheduler& ClearValidator();
198
201 TaskScheduler& Update(success_t const& callback = EmptyCallback);
202
205 TaskScheduler& Update(size_t const milliseconds, success_t const& callback = EmptyCallback);
206
209 template<class _Rep, class _Period>
210 TaskScheduler& Update(std::chrono::duration<_Rep, _Period> const& difftime,
211 success_t const& callback = EmptyCallback)
212 {
213 _now += difftime;
214 Dispatch(callback);
215 return *this;
216 }
217
220 TaskScheduler& Async(std::function<void()> const& callable);
221
224 template<class _Rep, class _Period>
225 TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time,
226 task_handler_t const& task)
227 {
228 return ScheduleAt(_now, time, task);
229 }
230
233 template<class _Rep, class _Period>
234 TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time,
235 group_t const group, task_handler_t const& task)
236 {
237 return ScheduleAt(_now, time, group, task);
238 }
239
242 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
243 TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
244 std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task)
245 {
246 return Schedule(randtime(min, max), task);
247 }
248
251 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
252 TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
253 std::chrono::duration<_RepRight, _PeriodRight> const& max, group_t const group,
254 task_handler_t const& task)
255 {
256 return Schedule(randtime(min, max), group, task);
257 }
258
261 TaskScheduler& CancelAll();
262
265 TaskScheduler& CancelGroup(group_t const group);
266
269 TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups);
270
272 template<class _Rep, class _Period>
273 TaskScheduler& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
274 {
275 _task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool
276 {
277 task->_end += duration;
278 return true;
279 });
280 return *this;
281 }
282
284 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
285 TaskScheduler& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
286 std::chrono::duration<_RepRight, _PeriodRight> const& max)
287 {
288 return DelayAll(randtime(min, max));
289 }
290
292 template<class _Rep, class _Period>
293 TaskScheduler& DelayGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
294 {
295 _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool
296 {
297 if (task->IsInGroup(group))
298 {
299 task->_end += duration;
300 return true;
301 }
302 else
303 return false;
304 });
305 return *this;
306 }
307
309 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
311 std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
312 std::chrono::duration<_RepRight, _PeriodRight> const& max)
313 {
314 return DelayGroup(group, randtime(min, max));
315 }
316
318 template<class _Rep, class _Period>
319 TaskScheduler& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
320 {
321 auto const end = _now + duration;
322 _task_holder.ModifyIf([end](TaskContainer const& task) -> bool
323 {
324 task->_end = end;
325 return true;
326 });
327 return *this;
328 }
329
331 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
332 TaskScheduler& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
333 std::chrono::duration<_RepRight, _PeriodRight> const& max)
334 {
335 return RescheduleAll(randtime(min, max));
336 }
337
339 template<class _Rep, class _Period>
340 TaskScheduler& RescheduleGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
341 {
342 auto const end = _now + duration;
343 _task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool
344 {
345 if (task->IsInGroup(group))
346 {
347 task->_end = end;
348 return true;
349 }
350 else
351 return false;
352 });
353 return *this;
354 }
355
357 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
359 std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
360 std::chrono::duration<_RepRight, _PeriodRight> const& max)
361 {
362 return RescheduleGroup(group, randtime(min, max));
363 }
364
365private:
367 TaskScheduler& InsertTask(TaskContainer task);
368
369 template<class _Rep, class _Period>
371 std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task)
372 {
373 return InsertTask(TaskContainer(new Task(end + time, time, task)));
374 }
375
378 template<class _Rep, class _Period>
380 std::chrono::duration<_Rep, _Period> const& time,
381 group_t const group, task_handler_t const& task)
382 {
383 static repeated_t const DEFAULT_REPEATED = 0;
384 return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, task)));
385 }
386
388 void Dispatch(success_t const& callback);
389};
390
392{
393 friend class TaskScheduler;
394
397
399 std::weak_ptr<TaskScheduler> _owner;
400
402 std::shared_ptr<bool> _consumed;
403
405 TaskContext& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply);
406
407public:
408 // Empty constructor
410 : _task(), _owner(), _consumed(std::make_shared<bool>(true)) { }
411
412 // Construct from task and owner
413 explicit TaskContext(TaskScheduler::TaskContainer&& task, std::weak_ptr<TaskScheduler>&& owner)
414 : _task(task), _owner(owner), _consumed(std::make_shared<bool>(false)) { }
415
416 // Copy construct
418 : _task(right._task), _owner(right._owner), _consumed(right._consumed) { }
419
420 // Move construct
422 : _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)) { }
423
424 // Copy assign
425 TaskContext& operator= (TaskContext const& right)
426 {
427 _task = right._task;
428 _owner = right._owner;
429 _consumed = right._consumed;
430 return *this;
431 }
432
433 // Move assign
434 TaskContext& operator= (TaskContext&& right)
435 {
436 _task = std::move(right._task);
437 _owner = std::move(right._owner);
438 _consumed = std::move(right._consumed);
439 return *this;
440 }
441
443 bool IsExpired() const;
444
446 bool IsInGroup(TaskScheduler::group_t const group) const;
447
449 TaskContext& SetGroup(TaskScheduler::group_t const group);
450
452 TaskContext& ClearGroup();
453
455 TaskScheduler::repeated_t GetRepeatCounter() const;
456
461 template<class _Rep, class _Period>
462 TaskContext& Repeat(std::chrono::duration<_Rep, _Period> const& duration)
463 {
464 AssertOnConsumed();
465
466 // Set new duration, in-context timing and increment repeat counter
467 _task->_duration = duration;
468 _task->_end += duration;
469 _task->_repeated += 1;
470 (*_consumed) = true;
471 return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task));
472 }
473
478 {
479 return Repeat(_task->_duration);
480 }
481
486 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
487 TaskContext& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
488 std::chrono::duration<_RepRight, _PeriodRight> const& max)
489 {
490 return Repeat(randtime(min, max));
491 }
492
495 TaskContext& Async(std::function<void()> const& callable);
496
501 template<class _Rep, class _Period>
502 TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time,
504 {
505 auto const end = _task->_end;
506 return Dispatch([end, time, task](TaskScheduler& scheduler) -> TaskScheduler&
507 {
508 return scheduler.ScheduleAt<_Rep, _Period>(end, time, task);
509 });
510 }
511
516 template<class _Rep, class _Period>
517 TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time,
519 {
520 auto const end = _task->_end;
521 return Dispatch([end, time, group, task](TaskScheduler& scheduler) -> TaskScheduler&
522 {
523 return scheduler.ScheduleAt<_Rep, _Period>(end, time, group, task);
524 });
525 }
526
531 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
532 TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
533 std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task)
534 {
535 return Schedule(randtime(min, max), task);
536 }
537
542 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
543 TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
544 std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group,
546 {
547 return Schedule(randtime(min, max), group, task);
548 }
549
551 TaskContext& CancelAll();
552
554 TaskContext& CancelGroup(TaskScheduler::group_t const group);
555
558 TaskContext& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups);
559
561 template<class _Rep, class _Period>
562 TaskContext& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
563 {
564 return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, duration));
565 }
566
568 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
569 TaskContext& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
570 std::chrono::duration<_RepRight, _PeriodRight> const& max)
571 {
572 return DelayAll(randtime(min, max));
573 }
574
576 template<class _Rep, class _Period>
577 TaskContext& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
578 {
579 return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
580 }
581
583 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
585 std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
586 std::chrono::duration<_RepRight, _PeriodRight> const& max)
587 {
588 return DelayGroup(group, randtime(min, max));
589 }
590
592 template<class _Rep, class _Period>
593 TaskContext& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
594 {
595 return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, duration));
596 }
597
599 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
600 TaskContext& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
601 std::chrono::duration<_RepRight, _PeriodRight> const& max)
602 {
603 return RescheduleAll(randtime(min, max));
604 }
605
607 template<class _Rep, class _Period>
608 TaskContext& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
609 {
610 return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
611 }
612
614 template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
616 std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
617 std::chrono::duration<_RepRight, _PeriodRight> const& max)
618 {
619 return RescheduleGroup(group, randtime(min, max));
620 }
621
622private:
624 void AssertOnConsumed() const;
625
627 void Invoke();
628};
629
630#endif
#define TC_COMMON_API
Definition Define.h:96
uint32_t uint32
Definition Define.h:133
static bool EmptyValidator()
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
Milliseconds randtime(Milliseconds min, Milliseconds max)
Definition Random.cpp:62
std::strong_ordering operator<=>(WowTime const &left, WowTime const &right)
Definition WowTime.cpp:142
TaskContext & RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
Reschedule all tasks of a group with a random duration between min and max.
TaskContext & Repeat(std::chrono::duration< _Rep, _Period > const &duration)
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)
TaskContext(TaskContext &&right)
TaskContext & Repeat(std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
TaskContext & DelayGroup(TaskScheduler::group_t const group, std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
Delays all tasks of a group with a random duration between min and max from within the context.
TaskScheduler::TaskContainer _task
Associated task.
std::weak_ptr< TaskScheduler > _owner
Owner.
std::shared_ptr< bool > _consumed
Marks the task as consumed.
TaskContext & Schedule(std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max, TaskScheduler::task_handler_t const &task)
TaskContext & Schedule(std::chrono::duration< _Rep, _Period > const &time, TaskScheduler::group_t const group, TaskScheduler::task_handler_t const &task)
TaskContext & DelayAll(std::chrono::duration< _Rep, _Period > const &duration)
Delays all tasks with the given duration from within the context.
TaskContext & DelayGroup(TaskScheduler::group_t const group, std::chrono::duration< _Rep, _Period > const &duration)
Delays all tasks of a group with the given duration from within the context.
TaskContext & DelayAll(std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
Delays all tasks with a random duration between min and max from within the context.
TaskContext & RescheduleAll(std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
Reschedule all tasks with a random duration between min and max.
TaskContext(TaskContext const &right)
TaskContext & Schedule(std::chrono::duration< _Rep, _Period > const &time, TaskScheduler::task_handler_t const &task)
TaskContext & Repeat()
TaskContext(TaskScheduler::TaskContainer &&task, std::weak_ptr< TaskScheduler > &&owner)
TaskContext & RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration< _Rep, _Period > const &duration)
Reschedule all tasks of a group with the given duration.
TaskContext & RescheduleAll(std::chrono::duration< _Rep, _Period > const &duration)
Reschedule all tasks with the given duration.
void ModifyIf(std::function< bool(TaskContainer const &)> const &filter)
std::multiset< TaskContainer, Compare > container
bool IsInGroup(group_t const group) const
task_handler_t _task
Optional< group_t > _group
Task(timepoint_t const &end, duration_t const &duration, Optional< group_t > const &group, repeated_t const repeated, task_handler_t const &task)
Task(Task const &)=delete
Task(Task &&)=delete
Task(timepoint_t const &end, duration_t const &duration, task_handler_t const &task)
TaskScheduler & DelayAll(std::chrono::duration< _Rep, _Period > const &duration)
Delays all tasks with the given duration.
TaskScheduler & RescheduleAll(std::chrono::duration< _Rep, _Period > const &duration)
Reschedule all tasks with a given duration.
std::shared_ptr< Task > TaskContainer
TaskScheduler & Schedule(std::chrono::duration< _Rep, _Period > const &time, task_handler_t const &task)
clock_t::time_point timepoint_t
TaskScheduler & ScheduleAt(timepoint_t const &end, std::chrono::duration< _Rep, _Period > const &time, task_handler_t const &task)
TaskScheduler(TaskScheduler &&)=delete
TaskScheduler & Update(std::chrono::duration< _Rep, _Period > const &difftime, success_t const &callback=EmptyCallback)
std::function< void()> success_t
std::shared_ptr< TaskScheduler > self_reference
Contains a self reference to track if this object was deleted or not.
std::function< void(TaskContext)> task_handler_t
std::function< bool()> predicate_t
TaskScheduler & DelayAll(std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
Delays all tasks with a random duration between min and max.
AsyncHolder _asyncHolder
TaskScheduler & RescheduleGroup(group_t const group, std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
Reschedule all tasks of a group with a random duration between min and max.
TaskScheduler(P &&predicate)
TaskScheduler & DelayGroup(group_t const group, std::chrono::duration< _Rep, _Period > const &duration)
Delays all tasks of a group with the given duration.
predicate_t _predicate
clock_t::duration duration_t
TaskScheduler & Schedule(std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max, task_handler_t const &task)
TaskScheduler & Schedule(std::chrono::duration< _Rep, _Period > const &time, group_t const group, task_handler_t const &task)
TaskScheduler & InsertTask(TaskContainer task)
Insert a new task to the enqueued tasks.
TaskScheduler & Schedule(std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max, group_t const group, task_handler_t const &task)
TaskScheduler(TaskScheduler const &)=delete
timepoint_t _now
The current time point (now)
std::queue< std::function< void()> > AsyncHolder
std::chrono::steady_clock clock_t
TaskScheduler & DelayGroup(group_t const group, std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
Delays all tasks of a group with a random duration between min and max.
static bool EmptyValidator()
TaskScheduler & ScheduleAt(timepoint_t const &end, std::chrono::duration< _Rep, _Period > const &time, group_t const group, task_handler_t const &task)
TaskQueue _task_holder
The Task Queue which contains all task objects.
TaskScheduler & SetValidator(P &&predicate)
Sets a validator which is asked if tasks are allowed to be executed.
static void EmptyCallback()
TaskScheduler & RescheduleGroup(group_t const group, std::chrono::duration< _Rep, _Period > const &duration)
Reschedule all tasks of a group with the given duration.
TaskScheduler & RescheduleAll(std::chrono::duration< _RepLeft, _PeriodLeft > const &min, std::chrono::duration< _RepRight, _PeriodRight > const &max)
Reschedule all tasks with a random duration between min and max.
STL namespace.
Container which provides Task order, insert and reschedule operations.