DiscordCoreAPI
A Discord bot library written in C++, with custom asynchronous coroutines.
Loading...
Searching...
No Matches
EventEntities.hpp
Go to the documentation of this file.
1/*
2 MIT License
3
4 DiscordCoreAPI, A bot library for Discord, written in C++, and featuring explicit multithreading through the usage of custom, asynchronous C++ CoRoutines.
5
6 Copyright 2022, 2023 Chris M. (RealTimeChris)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25*/
26/// EventEntities.hpp - Header for the "event-related stuff".
27/// Dec 12, 2021
28/// https://discordcoreapi.com
29/// \file EventEntities.hpp
30#pragma once
31
33
34namespace discord_core_api {
35
36 namespace discord_core_internal {
37
38 /**
39 * \addtogroup utilities
40 * @{
41 */
42
43 /// @brief Struct representing an event delegate token, associated with an event.
45 /// @brief Equality operator for comparing event_delegate_token instances.
46 /// @param rhs the right-hand side event_delegate_token to compare against.
47 /// @return bool true if the event_delegate_token instances are equal, otherwise false.
48 DCA_INLINE bool operator==(const event_delegate_token& rhs) const {
49 return handlerId == rhs.handlerId && eventId == rhs.eventId;
50 }
51
52 /// @brief Less-than operator for comparing event_delegate_token instances.
53 /// @param rhs the right-hand side event_delegate_token to compare against.
54 /// @return bool true if this event_delegate_token is less than rhs, otherwise false.
55 DCA_INLINE bool operator<(const event_delegate_token& rhs) const {
56 return handlerId < rhs.handlerId;
57 }
58
59 /// @brief Default constructor for event_delegate_token.
60 DCA_INLINE event_delegate_token() = default;
61
62 uint64_t handlerId{};///< Identifier for the handler.
63 uint64_t eventId{};///< Identifier for the event.
64 };
65
66 };
67
68 template<event_delegate_token_t value_type> struct key_hasher<value_type> {
69 DCA_INLINE static uint64_t getHashKey(const value_type& data) {
70 uint64_t values[2]{};
71 values[0] = data.eventId;
72 values[0] = data.handlerId;
73 return internalHashFunction(values, std::size(values) * sizeof(uint64_t));
74 };
75 };
76
77 namespace discord_core_internal {
78
79 /// @brief Event-delegate, representing an event function to be executed.
80 template<typename return_type, typename... arg_types> class event_delegate {
81 public:
82 template<typename rty02, typename... arg_types02> friend class event;
83
84 /// @brief Default constructor for event_delegate class.
85 event_delegate() = default;
86
87 DCA_INLINE event_delegate& operator=(const event_delegate& other) = delete;
88 DCA_INLINE event_delegate(const event_delegate& other) = delete;
89
90 /// @brief Move assignment operator for the event_delegate class.
91 /// this operator moves the contents of another event_delegate instance, 'other', into the current instance.
92 /// it swaps the 'function' member between 'other' and the current instance, and then clears 'other' function.
93 /// @param other the event_delegate instance to be moved from.
94 /// @return reference to the current event_delegate instance after the move assignment.
95 DCA_INLINE event_delegate& operator=(event_delegate&& other) noexcept {
96 if (this != &other) {
97 function.swap(other.function);
98 }
99 return *this;
100 }
101
102 /// @brief Move constructor for the event_delegate class.
103 /// this constructor moves the contents of another event_delegate instance, 'other', into the current instance.
104 /// it performs a move assignment using the 'operator=' function.
105 /// @param other the event_delegate instance to be moved from.
106 DCA_INLINE event_delegate(event_delegate&& other) noexcept {
107 // perform move assignment using the 'operator=' function.
108 *this = std::move(other);
109 }
110
111 /// @brief Assignment operator to set the delegate function.
112 /// this operator assigns a new std::function, 'functionNew', as the delegate function of the current instance.
113 /// @param functionNew the std::function to assign as the current event.
114 /// @return reference to the current event_delegate instance after the assignment.
115 DCA_INLINE event_delegate& operator=(std::function<return_type(arg_types...)> functionNew) {
116 function = functionNew;
117 return *this;
118 }
119
120 /// @brief Constructor, taking a std::function<return_type(arg_types...)> as an argument.
121 /// @param functionNew the function to construct as the current event.
122 DCA_INLINE event_delegate(std::function<return_type(arg_types...)> functionNew) {
123 *this = functionNew;
124 }
125
126 /// @brief Assignment operator to set the delegate function using a function pointer.
127 /// this operator assigns a new function pointer, 'functionNew', as the delegate function of the current instance.
128 /// @param functionNew the function pointer to assign as the current event.
129 /// @return reference to the current event_delegate instance after the assignment.
130 DCA_INLINE event_delegate& operator=(return_type (*functionNew)(arg_types...)) {
131 function = functionNew;
132 return *this;
133 }
134
135 /// @brief Constructor for the event_delegate class, taking a pointer to a function as an argument.
136 /// this constructor initializes the event_delegate instance with the provided function pointer.
137 /// it calls the assignment operator to set the delegate function using the provided function pointer.
138 /// @param functionNew the function to construct as the current event.
139 DCA_INLINE event_delegate(return_type (*functionNew)(arg_types...)) {
140 // call the assignment operator to set the delegate function using the provided function pointer.
141 *this = functionNew;
142 }
143
144 protected:
145 std::function<return_type(const arg_types&...)> function{};
146 };
147
148 /// @brief Template class representing an event that executes event functions.
149 template<typename return_type, typename... arg_types> class event {
150 public:
151 unordered_map<event_delegate_token, event_delegate<return_type, arg_types...>> functions{};
152
153 DCA_INLINE event& operator=(const event& other) = delete;
154 DCA_INLINE event(const event& other) = delete;
155
156 /// @brief Move assignment operator for the event class.
157 /// this operator moves the contents of another event instance, 'other', into the current instance.
158 /// it transfers the functions and eventId from 'other' to the current instance, clearing 'other' in the process.
159 /// @param other the event instance to be moved from.
160 /// @return reference to the current event instance after the move assignment.
161 DCA_INLINE event& operator=(event&& other) noexcept {
162 if (this != &other) {
163 std::swap(functions, other.functions);
164 std::swap(eventId, other.eventId);
165 }
166 return *this;
167 }
168
169 /// @brief Move constructor for the event class.
170 /// this constructor moves the contents of another event instance, 'other', into the current instance.
171 /// it performs a move assignment using the 'operator=' function.
172 /// @param other the event instance to be moved from.
173 DCA_INLINE event(event&& other) noexcept {
174 // perform move assignment using the 'operator=' function.
175 *this = std::move(other);
176 }
177
178 /// @brief Default constructor for event class.
179 DCA_INLINE event() {
180 std::unique_lock lock{ accessMutex };
181 eventId = std::chrono::duration_cast<std::chrono::duration<uint64_t, std::micro>>(sys_clock::now().time_since_epoch()).count();
182 }
183
184 /// @brief Add an event delegate to the event.
185 /// @param eventDelegate the event delegate to add.
186 /// @return event_delegate_token the token representing the added event delegate.
187 DCA_INLINE event_delegate_token add(event_delegate<return_type, arg_types...>&& eventDelegate) {
188 std::unique_lock lock{ accessMutex };
189 event_delegate_token eventToken{};
190 eventToken.handlerId = std::chrono::duration_cast<std::chrono::duration<uint64_t, std::micro>>(sys_clock::now().time_since_epoch()).count();
191 eventToken.eventId = eventId;
192 functions[eventToken] = std::move(eventDelegate);
193 return eventToken;
194 }
195
196 /// @brief Remove an event delegate from the event.
197 /// @param eventToken the token representing the event delegate to remove.
198 DCA_INLINE void erase(const event_delegate_token& eventToken) {
199 std::unique_lock lock{ accessMutex };
200 if (eventToken.eventId == eventId) {
201 if (functions.contains(eventToken)) {
202 functions.erase(eventToken);
203 }
204 }
205 }
206
207 /// @brief Invoke the event with provided arguments.
208 /// @param args the arguments to pass to the event delegates.
209 DCA_INLINE void operator()(const arg_types&... args) {
210 std::unique_lock lock{ accessMutex };
211 for (auto& [key, value]: functions) {
212 try {
213 value.function(args...).get();
214 } catch (const dca_exception& error) {
216 }
217 }
218 return;
219 }
220
221 ~event() {
222 {
223 std::unique_lock lock{ accessMutex };
224 lock.unlock();
225 }
226 }
227
228 protected:
229 std::mutex accessMutex{};
230 uint64_t eventId{};
231 };
232
233 /// @brief Event-delegate, for representing an event-function to be executed conditionally.
234 template<typename return_type, typename... arg_types> class trigger_event_delegate {
235 public:
236 template<typename rty02, typename... arg_types02> friend class trigger_event;
237
238 DCA_INLINE trigger_event_delegate& operator=(const trigger_event_delegate& other) = delete;
239 DCA_INLINE trigger_event_delegate(const trigger_event_delegate& other) = delete;
240
241 /// @brief Move assignment operator for trigger_event_delegate class.
242 /// this operator moves the contents of another trigger_event_delegate instance ('other') into the current instance.
243 /// @param other the trigger_event_delegate instance to be moved.
244 /// @return reference to the current trigger_event_delegate instance after the move assignment.
245 DCA_INLINE trigger_event_delegate& operator=(trigger_event_delegate&& other) noexcept {
246 if (this != &other) {
247 testFunction.swap(other.testFunction);
248 function.swap(other.function);
249 }
250 return *this;
251 }
252
253 /// @brief Move constructor for trigger_event_delegate class.
254 /// this constructor moves the contents of another trigger_event_delegate instance ('other') into the current instance.
255 /// @param other the trigger_event_delegate instance to be moved.
256 DCA_INLINE trigger_event_delegate(trigger_event_delegate&& other) noexcept {
257 *this = std::move(other);
258 }
259
260 /// @brief Assignment operator to set the delegate function using a std::function.
261 /// this operator assigns a new std::function, 'functionNew', as the delegate function of the current instance.
262 /// @param functionNew the std::function to assign as the current event.
263 /// @return reference to the current trigger_event_delegate instance after the assignment.
264 DCA_INLINE trigger_event_delegate& operator=(std::function<return_type(arg_types...)> functionNew) {
265 function = functionNew;
266 return *this;
267 }
268
269 /// @brief Constructor for the trigger_event_delegate class, taking a std::function as an argument.
270 /// this constructor initializes the trigger_event_delegate instance with the provided std::function.
271 /// it calls the assignment operator to set the delegate function using the provided std::function.
272 /// @param functionNew the function to construct as the current event.
273 DCA_INLINE trigger_event_delegate(std::function<return_type(arg_types...)> functionNew) {
274 // call the assignment operator to set the delegate function using the provided std::function.
275 *this = functionNew;
276 }
277
278 /// @brief Assignment operator to set the delegate function using a function pointer.
279 /// this operator assigns a new function pointer, 'functionNew', as the delegate function of the current instance.
280 /// @param functionNew the function pointer to assign as the current event.
281 /// @return reference to the current trigger_event_delegate instance after the assignment.
282 DCA_INLINE trigger_event_delegate& operator=(return_type (*functionNew)(arg_types...)) {
283 function = functionNew;
284 return *this;
285 }
286
287 /// @brief Constructor for trigger_event_delegate class, taking a function pointer as argument.
288 /// @param functionNew the function to construct as the current event.
289 DCA_INLINE trigger_event_delegate(return_type (*functionNew)(arg_types...)) {
290 *this = functionNew;
291 }
292
293 /// @brief Default constructor for trigger_event_delegate class.
294 DCA_INLINE trigger_event_delegate() = default;
295
296 /// @brief Sets the test function to determine conditional execution.
297 /// @param testFunctionNew the test function to set.
298 DCA_INLINE void setTestFunction(std::function<bool(arg_types...)> testFunctionNew) {
299 testFunction = testFunctionNew;
300 }
301
302 /// @brief Sets the test function using a function pointer.
303 /// @param testFunctionNew the test function to set.
304 DCA_INLINE void setTestFunction(bool (*testFunctionNew)(arg_types...)) {
305 testFunction = testFunctionNew;
306 }
307
308 protected:
309 std::function<return_type(const arg_types&...)> function{};
310 std::function<bool(const arg_types&...)> testFunction{};
311 };
312
313 /// @brief A trigger event that fires based on the result of trigger-function return value.
314 template<typename return_type, typename... arg_types> class trigger_event {
315 public:
316 unordered_map<event_delegate_token, trigger_event_delegate<return_type, arg_types...>> functions{};
317
318 DCA_INLINE trigger_event& operator=(const trigger_event& other) = delete;
319 DCA_INLINE trigger_event(const trigger_event& other) = delete;
320
321 /// @brief Move assignment operator for the trigger_event class.
322 /// this operator moves the contents of another trigger_event instance, 'other', into the current instance.
323 /// it transfers the functions and eventId from 'other' to the current instance, clearing 'other' in the process.
324 /// @param other the trigger_event instance to be moved from.
325 /// @return reference to the current trigger_event instance after the move assignment.
326 DCA_INLINE trigger_event& operator=(trigger_event&& other) noexcept {
327 if (this != &other) {
328 std::swap(functions, other.functions);
329 std::swap(eventId, other.eventId);
330 }
331 return *this;
332 }
333
334 /// @brief Move constructor for the trigger_event class.
335 /// this constructor moves the contents of another trigger_event instance, 'other', into the current instance.
336 /// it performs a move assignment using the 'operator=' function.
337 /// @param other the trigger_event instance to be moved from.
338 DCA_INLINE trigger_event(trigger_event&& other) noexcept {
339 // perform move assignment using the 'operator=' function.
340 *this = std::move(other);
341 }
342
343 /// @brief Default constructor for trigger_event class.
344 DCA_INLINE trigger_event() {
345 std::unique_lock lock{ accessMutex };
346 eventId = std::chrono::duration_cast<std::chrono::duration<uint64_t, std::micro>>(sys_clock::now().time_since_epoch()).count();
347 }
348
349 /// @brief Add an event delegate to the event.
350 /// @param eventDelegate the event delegate to add.
351 /// @return event_delegate_token the token representing the added event delegate.
352 DCA_INLINE event_delegate_token add(trigger_event_delegate<return_type, arg_types...>&& eventDelegate) {
353 std::unique_lock lock{ accessMutex };
354 event_delegate_token eventToken{};
355 eventToken.handlerId = std::chrono::duration_cast<std::chrono::duration<uint64_t, std::micro>>(sys_clock::now().time_since_epoch()).count();
356 eventToken.eventId = eventId;
357 functions[eventToken] = std::move(eventDelegate);
358 return eventToken;
359 }
360
361 /// @brief Remove an event delegate from the event.
362 /// @param eventToken the token representing the event delegate to remove.
363 DCA_INLINE void erase(const event_delegate_token& eventToken) {
364 std::unique_lock lock{ accessMutex };
365 if (eventToken.eventId == eventId) {
366 if (functions.contains(eventToken)) {
367 functions.erase(eventToken);
368 }
369 }
370 }
371
372 /// @brief Invoke the trigger event with provided arguments.
373 /// @param args the arguments to pass to the trigger event delegates.
374 DCA_INLINE void operator()(const arg_types&... args) {
375 std::unique_lock lock{ accessMutex };
376 for (auto iterator = functions.begin(); iterator != functions.end(); ++iterator) {
377 try {
378 if (iterator.operator*().second.testFunction(args...)) {
379 iterator.operator*().second.function(args...);
380 iterator = functions.erase(iterator->first);
381 }
382 } catch (const dca_exception& error) {
384 }
385 }
386 return;
387 }
388
389 ~trigger_event() {
390 {
391 std::unique_lock lock{ accessMutex };
392 lock.unlock();
393 }
394 }
395
396 protected:
397 std::mutex accessMutex{};
398 uint64_t eventId{};
399 };
400
401 /**@}*/
402
403 }
404}
Event-delegate, representing an event function to be executed.
DCA_INLINE event_delegate & operator=(return_type(*functionNew)(arg_types...))
Assignment operator to set the delegate function using a function pointer. this operator assigns a ne...
DCA_INLINE event_delegate(return_type(*functionNew)(arg_types...))
Constructor for the event_delegate class, taking a pointer to a function as an argument....
DCA_INLINE event_delegate(std::function< return_type(arg_types...)> functionNew)
Constructor, taking a std::function<return_type(arg_types...)> as an argument.
DCA_INLINE event_delegate & operator=(std::function< return_type(arg_types...)> functionNew)
Assignment operator to set the delegate function. this operator assigns a new std::function,...
DCA_INLINE event_delegate & operator=(event_delegate &&other) noexcept
Move assignment operator for the event_delegate class. this operator moves the contents of another ev...
DCA_INLINE event_delegate(event_delegate &&other) noexcept
Move constructor for the event_delegate class. this constructor moves the contents of another event_d...
event_delegate()=default
Default constructor for event_delegate class.
Template class representing an event that executes event functions.
DCA_INLINE event & operator=(event &&other) noexcept
Move assignment operator for the event class. this operator moves the contents of another event insta...
DCA_INLINE void erase(const event_delegate_token &eventToken)
Remove an event delegate from the event.
DCA_INLINE void operator()(const arg_types &... args)
Invoke the event with provided arguments.
DCA_INLINE event_delegate_token add(event_delegate< return_type, arg_types... > &&eventDelegate)
Add an event delegate to the event.
DCA_INLINE event(event &&other) noexcept
Move constructor for the event class. this constructor moves the contents of another event instance,...
DCA_INLINE event()
Default constructor for event class.
Event-delegate, for representing an event-function to be executed conditionally.
DCA_INLINE trigger_event_delegate(trigger_event_delegate &&other) noexcept
Move constructor for trigger_event_delegate class. this constructor moves the contents of another tri...
DCA_INLINE trigger_event_delegate & operator=(trigger_event_delegate &&other) noexcept
Move assignment operator for trigger_event_delegate class. this operator moves the contents of anothe...
DCA_INLINE trigger_event_delegate(return_type(*functionNew)(arg_types...))
Constructor for trigger_event_delegate class, taking a function pointer as argument.
DCA_INLINE trigger_event_delegate & operator=(return_type(*functionNew)(arg_types...))
Assignment operator to set the delegate function using a function pointer. this operator assigns a ne...
DCA_INLINE trigger_event_delegate()=default
Default constructor for trigger_event_delegate class.
DCA_INLINE trigger_event_delegate & operator=(std::function< return_type(arg_types...)> functionNew)
Assignment operator to set the delegate function using a std::function. this operator assigns a new s...
DCA_INLINE void setTestFunction(std::function< bool(arg_types...)> testFunctionNew)
Sets the test function to determine conditional execution.
DCA_INLINE trigger_event_delegate(std::function< return_type(arg_types...)> functionNew)
Constructor for the trigger_event_delegate class, taking a std::function as an argument....
DCA_INLINE void setTestFunction(bool(*testFunctionNew)(arg_types...))
Sets the test function using a function pointer.
A trigger event that fires based on the result of trigger-function return value.
DCA_INLINE trigger_event & operator=(trigger_event &&other) noexcept
Move assignment operator for the trigger_event class. this operator moves the contents of another tri...
DCA_INLINE void erase(const event_delegate_token &eventToken)
Remove an event delegate from the event.
DCA_INLINE void operator()(const arg_types &... args)
Invoke the trigger event with provided arguments.
DCA_INLINE event_delegate_token add(trigger_event_delegate< return_type, arg_types... > &&eventDelegate)
Add an event delegate to the event.
DCA_INLINE trigger_event()
Default constructor for trigger_event class.
DCA_INLINE trigger_event(trigger_event &&other) noexcept
Move constructor for the trigger_event class. this constructor moves the contents of another trigger_...
static DCA_INLINE void printError(const string_type &what, std::source_location where=std::source_location::current())
Print an error message of the specified type.
Definition Base.hpp:252
DCA_INLINE bool operator==(const event_delegate_token &rhs) const
Equality operator for comparing event_delegate_token instances.
DCA_INLINE bool operator<(const event_delegate_token &rhs) const
Less-than operator for comparing event_delegate_token instances.
DCA_INLINE event_delegate_token()=default
Default constructor for event_delegate_token.
The main namespace for the forward-facing interfaces.
Struct representing an event delegate token, associated with an event.