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 TRINITYCORE_TASK_SCHEDULER_H
19#define TRINITYCORE_TASK_SCHEDULER_H
20
21#include "Duration.h"
22#include "Optional.h"
23#include "Random.h"
24#include "Types.h"
25#include <algorithm>
26#include <functional>
27#include <memory>
28#include <set>
29#include <span>
30#include <utility>
31#include <variant>
32
33class TaskContext;
34
49{
50 friend class TaskContext;
51
52 class TaskHandler;
53
54 // Time definitions (use steady clock)
55 typedef std::chrono::steady_clock clock_t;
56 typedef clock_t::time_point timepoint_t;
57 typedef clock_t::duration duration_t;
58
59 // Task group type
60 typedef uint32 group_t;
61 // Task repeated type
63 // Task handler type
65 // Predicate type
66 typedef std::function<bool()> predicate_t;
67 // Success handle type
68 typedef std::function<void()> success_t;
69
70 // Task handler function wrapper designed to support both TaskContext& and TaskContext arguments
72 {
73 public:
74 template <typename InnerHandler> requires (!std::same_as<InnerHandler, TaskHandler>)
75 TaskHandler(InnerHandler&& handler) : _handler(TaskHandler::Wrap(std::forward<InnerHandler>(handler))) { }
76
77 void operator()(TaskContext& context) const { _handler(context); }
78
79 private:
80 template <typename InnerHandler>
81 static decltype(auto) Wrap(InnerHandler&& handler)
82 {
83 if constexpr (std::invocable<InnerHandler, TaskContext&>)
84 {
85 return std::forward<InnerHandler>(handler);
86 }
87 else if constexpr (std::invocable<InnerHandler, TaskContext&&>)
88 {
89 // support legacy signature
90 return [inner = std::forward<InnerHandler>(handler)](TaskContext& context)
91 {
92 inner(static_cast<TaskContext&&>(context));
93 };
94 }
95 else
96 {
97 static_assert(Trinity::dependant_false_v<InnerHandler>, "Unsupported task argument type, must be TaskContext& or TaskContext const&");
98 }
99 }
100
101 std::function<void(TaskContext&)> _handler;
102 };
103
104 class Task
105 {
106 friend class TaskContext;
107 friend class TaskScheduler;
108
114
115 public:
116 // All Argument construct
118 repeated_t const repeated, task_handler_t task)
119 : _end(end), _duration(duration), _group(group), _repeated(repeated), _task(std::move(task)) { }
120
121 // Minimal Argument construct
123 : _end(end), _duration(duration), _group(std::nullopt), _repeated(0), _task(std::move(task)) { }
124
125 // Copy construct
126 Task(Task const&) = delete;
127 // Move construct
128 Task(Task&&) = delete;
129 // Copy Assign
130 Task& operator= (Task const&) = delete;
131 // Move Assign
132 Task& operator= (Task&& right) = delete;
133
134 ~Task() = default;
135
136 // Order tasks by its end
137 std::weak_ordering operator<=> (Task const& other) const
138 {
139 return std::compare_weak_order_fallback(_end, other._end);
140 }
141
142 // Compare tasks with its end
143 bool operator== (Task const& other) const
144 {
145 return _end == other._end;
146 }
147
148 // Returns true if the task is in the given group
149 inline bool IsInGroup(group_t const group) const
150 {
151 return _group == group;
152 }
153 };
154
155 typedef std::shared_ptr<Task> TaskContainer;
156
158 struct Compare
159 {
160 bool operator() (TaskContainer const& left, TaskContainer const& right) const
161 {
162 return (*left.get()) < (*right.get());
163 }
164 };
165
167 {
168 public:
169 typedef std::multiset<TaskContainer, Compare> Container;
170
171 private:
173
174 public:
175 // Pushes the task in the container
176 void Push(TaskContainer&& task);
177
178 // Pushes the task in the container
179 void Push(Container::node_type&& node);
180
182 Container::node_type Pop();
183
184 TaskContainer const& First() const;
185
186 void Clear();
187
188 void RemoveIf(std::function<bool(TaskContainer const&)> const& filter);
189
190 void ModifyIf(std::function<bool(TaskContainer const&)> const& filter);
191
192 bool IsEmpty() const;
193 };
194
196 std::shared_ptr<TaskScheduler> self_reference;
197
200
203
205
206 static bool EmptyValidator()
207 {
208 return true;
209 }
210
211public:
213
214 template<typename P>
215 explicit TaskScheduler(P&& predicate)
216 : self_reference(this, [](TaskScheduler const*) { }), _now(clock_t::now()), _predicate(std::forward<P>(predicate)) { }
217
218 TaskScheduler(TaskScheduler const&) = delete;
220 TaskScheduler& operator= (TaskScheduler const&) = delete;
221 TaskScheduler& operator= (TaskScheduler&&) = delete;
222
224
226 template<typename P>
228 {
229 _predicate = std::forward<P>(predicate);
230 return *this;
231 }
232
234 TaskScheduler& ClearValidator();
235
237
239 TaskScheduler& Update();
240
243 TaskScheduler& Update(success_t callback);
244
246 TaskScheduler& Update(size_t milliseconds);
247
250 TaskScheduler& Update(size_t milliseconds, success_t callback);
251
253 TaskScheduler& Update(duration_t difftime);
254
257 TaskScheduler& Update(duration_t difftime, success_t callback);
258
261 TaskScheduler& Async(std::function<void()> callable);
262
266 task_handler_t task)
267 {
268 return this->ScheduleAt(_now, time, std::move(task));
269 }
270
274 group_t group, task_handler_t task)
275 {
276 return this->ScheduleAt(_now, time, group, std::move(task));
277 }
278
281 TaskScheduler& Schedule(std::chrono::milliseconds min,
282 std::chrono::milliseconds max, task_handler_t task)
283 {
284 return this->Schedule(::randtime(min, max), std::move(task));
285 }
286
289 TaskScheduler& Schedule(std::chrono::milliseconds min,
290 std::chrono::milliseconds max, group_t group,
291 task_handler_t task)
292 {
293 return this->Schedule(::randtime(min, max), group, std::move(task));
294 }
295
298 TaskScheduler& CancelAll();
299
302 TaskScheduler& CancelGroup(group_t group);
303
306 TaskScheduler& CancelGroupsOf(std::span<group_t> groups);
307
309 TaskScheduler& DelayAll(duration_t duration);
310
312 TaskScheduler& DelayAll(std::chrono::milliseconds min,
313 std::chrono::milliseconds max)
314 {
315 return this->DelayAll(::randtime(min, max));
316 }
317
319 TaskScheduler& DelayGroup(group_t group, duration_t duration);
320
323 std::chrono::milliseconds min,
324 std::chrono::milliseconds max)
325 {
326 return this->DelayGroup(group, ::randtime(min, max));
327 }
328
330 TaskScheduler& RescheduleAll(duration_t duration);
331
333 TaskScheduler& RescheduleAll(std::chrono::milliseconds min, std::chrono::milliseconds max)
334 {
335 return this->RescheduleAll(::randtime(min, max));
336 }
337
339 TaskScheduler& RescheduleGroup(group_t group, duration_t duration);
340
343 std::chrono::milliseconds min,
344 std::chrono::milliseconds max)
345 {
346 return this->RescheduleGroup(group, ::randtime(min, max));
347 }
348
349private:
351 TaskScheduler& InsertTask(TaskContainer&& task);
352
354 TaskScheduler& InsertTask(TaskQueue::Container::node_type&& node);
355
356 TaskScheduler& ScheduleAt(timepoint_t end,
357 duration_t time, task_handler_t task);
358
361 TaskScheduler& ScheduleAt(timepoint_t end,
362 duration_t time,
363 group_t group, task_handler_t task);
364
366 void Dispatch(success_t const& callback);
367};
368
370{
371 friend class TaskScheduler;
372
374 std::variant<TaskScheduler::TaskQueue::Container::node_type /*not consumed*/,
376
378 std::weak_ptr<TaskScheduler> _owner;
379
380public:
381 // Empty constructor
382 TaskContext() noexcept
383 : _task(), _owner() { }
384
385 // Construct from task and owner
386 explicit TaskContext(TaskScheduler::TaskQueue::Container::node_type&& task, std::weak_ptr<TaskScheduler>&& owner) noexcept;
387
388 // Copy construct
389 TaskContext(TaskContext const& right) = delete;
390
391 // Move construct
392 TaskContext(TaskContext&& right) noexcept;
393
394 // Copy assign
395 TaskContext& operator=(TaskContext const& right) = delete;
396
397 // Move assign
398 TaskContext& operator=(TaskContext&& right) noexcept;
399
401
403 bool IsExpired() const;
404
406 bool IsInGroup(TaskScheduler::group_t group) const;
407
409 TaskContext& SetGroup(TaskScheduler::group_t group);
410
412 TaskContext& ClearGroup();
413
415 TaskScheduler::repeated_t GetRepeatCounter() const;
416
421 TaskContext& Repeat(TaskScheduler::duration_t duration);
422
426 TaskContext& Repeat();
427
432 TaskContext& Repeat(std::chrono::milliseconds min,
433 std::chrono::milliseconds max)
434 {
435 return this->Repeat(::randtime(min, max));
436 }
437
440 TaskContext& Async(std::function<void()> callable);
441
448
455
460 TaskContext& Schedule(std::chrono::milliseconds min,
461 std::chrono::milliseconds max, TaskScheduler::task_handler_t task)
462 {
463 return this->Schedule(::randtime(min, max), std::move(task));
464 }
465
470 TaskContext& Schedule(std::chrono::milliseconds min,
471 std::chrono::milliseconds max, TaskScheduler::group_t group,
473 {
474 return this->Schedule(::randtime(min, max), group, std::move(task));
475 }
476
478 TaskContext& CancelAll();
479
481 TaskContext& CancelGroup(TaskScheduler::group_t group);
482
485 TaskContext& CancelGroupsOf(std::span<TaskScheduler::group_t> groups);
486
488 TaskContext& DelayAll(TaskScheduler::duration_t duration);
489
491 TaskContext& DelayAll(std::chrono::milliseconds min,
492 std::chrono::milliseconds max)
493 {
494 return this->DelayAll(::randtime(min, max));
495 }
496
499
502 std::chrono::milliseconds min,
503 std::chrono::milliseconds max)
504 {
505 return this->DelayGroup(group, ::randtime(min, max));
506 }
507
509 TaskContext& RescheduleAll(TaskScheduler::duration_t duration);
510
512 TaskContext& RescheduleAll(std::chrono::milliseconds min,
513 std::chrono::milliseconds max)
514 {
515 return this->RescheduleAll(::randtime(min, max));
516 }
517
519 TaskContext& RescheduleGroup(TaskScheduler::group_t group, TaskScheduler::duration_t duration);
520
523 std::chrono::milliseconds min,
524 std::chrono::milliseconds max)
525 {
526 return this->RescheduleGroup(group, ::randtime(min, max));
527 }
528
529private:
531 void Invoke();
532
533 TaskScheduler::TaskContainer& GetTaskContainer() noexcept;
534
535 TaskScheduler::Task* GetTask() const noexcept;
536};
537
538#endif
#define TC_COMMON_API
Definition Define.h:99
uint32_t uint32
Definition Define.h:154
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 group, std::chrono::milliseconds min, std::chrono::milliseconds max)
Reschedule all tasks of a group with a random duration between min and max.
TaskContext & Schedule(std::chrono::milliseconds min, std::chrono::milliseconds max, TaskScheduler::task_handler_t task)
TaskContext & Repeat(std::chrono::milliseconds min, std::chrono::milliseconds max)
TaskContext & RescheduleAll(std::chrono::milliseconds min, std::chrono::milliseconds max)
Reschedule all tasks with a random duration between min and max.
std::variant< TaskScheduler::TaskQueue::Container::node_type, TaskScheduler::TaskContainer > _task
Associated task.
std::weak_ptr< TaskScheduler > _owner
Owner.
TaskContext(TaskContext const &right)=delete
TaskContext & DelayGroup(TaskScheduler::group_t group, std::chrono::milliseconds min, std::chrono::milliseconds max)
Delays all tasks of a group with a random duration between min and max from within the context.
TaskContext & operator=(TaskContext const &right)=delete
TaskContext & Schedule(std::chrono::milliseconds min, std::chrono::milliseconds max, TaskScheduler::group_t group, TaskScheduler::task_handler_t task)
TaskContext & DelayAll(std::chrono::milliseconds min, std::chrono::milliseconds max)
Delays all tasks with a random duration between min and max from within the context.
TaskContext() noexcept
std::function< void(TaskContext &)> _handler
static decltype(auto) Wrap(InnerHandler &&handler)
void operator()(TaskContext &context) const
TaskHandler(InnerHandler &&handler)
std::multiset< TaskContainer, Compare > Container
bool IsInGroup(group_t const group) const
task_handler_t _task
Task(timepoint_t end, duration_t duration, task_handler_t task)
Optional< group_t > _group
Task(Task const &)=delete
Task(Task &&)=delete
Task(timepoint_t end, duration_t duration, Optional< group_t > group, repeated_t const repeated, task_handler_t task)
std::shared_ptr< Task > TaskContainer
clock_t::time_point timepoint_t
TaskScheduler(TaskScheduler &&)=delete
std::function< void()> success_t
TaskScheduler & DelayGroup(group_t group, std::chrono::milliseconds min, std::chrono::milliseconds max)
Delays all tasks of a group with a random duration between min and max.
std::shared_ptr< TaskScheduler > self_reference
Contains a self reference to track if this object was deleted or not.
std::function< bool()> predicate_t
TaskScheduler & Schedule(std::chrono::milliseconds min, std::chrono::milliseconds max, task_handler_t task)
TaskHandler task_handler_t
TaskScheduler(P &&predicate)
TaskScheduler & Schedule(duration_t time, group_t group, task_handler_t task)
predicate_t _predicate
clock_t::duration duration_t
TaskScheduler & Schedule(duration_t time, task_handler_t task)
static success_t const EmptySuccessCallback
TaskScheduler & Schedule(std::chrono::milliseconds min, std::chrono::milliseconds max, group_t group, task_handler_t task)
TaskScheduler(TaskScheduler const &)=delete
TaskScheduler & RescheduleAll(std::chrono::milliseconds min, std::chrono::milliseconds max)
Reschedule all tasks with a random duration between min and max.
timepoint_t _now
The current time point (now)
TaskScheduler & RescheduleGroup(group_t group, std::chrono::milliseconds min, std::chrono::milliseconds max)
Reschedule all tasks of a group with a random duration between min and max.
std::chrono::steady_clock clock_t
static bool EmptyValidator()
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.
TaskScheduler & DelayAll(std::chrono::milliseconds min, std::chrono::milliseconds max)
Delays all tasks with a random duration between min and max.
STL namespace.
Container which provides Task order, insert and reschedule operations.