LkEngine 0.1.2
 
Loading...
Searching...
No Matches
EventQueue.h
1#pragma once
2
3#include <mutex>
4
5#include "Event.h"
6
7
8namespace LkEngine {
9
10 template<typename InvokerType>
12 {
13 const char* Name = nullptr;
14 EEventType Type = EEventType::None;
15 std::size_t TypeHash = 0;
16 std::size_t Idx = -1;
17 InvokerType Event;
18
19 TEventQueueEntry(const char* InName,
20 const EEventType& InType,
21 const std::type_info& InTypeInfo,
22 const std::size_t InIdx,
23 const InvokerType& InEvent)
24 : Name(InName)
25 , Type(InType)
26 , TypeHash(InTypeInfo.hash_code())
27 , Idx(InIdx)
28 , Event(InEvent)
29 {
30 LK_CORE_ASSERT(Idx != -1, "No index passed to event queue entry");
31 }
32
34 : Name(Other.Name)
35 , Type(Other.Type)
36 , TypeHash(Other.TypeHash)
37 , Idx(Other.Idx)
38 , Event(std::move(Other.Event))
39 {
40 LK_CORE_ASSERT(Idx != -1, "No index passed to event queue entry");
41 }
42
43 TEventQueueEntry& operator=(const TEventQueueEntry& Other)
44 {
45 Name = Other.Name;
46 Type = Other.Type;
47 TypeHash = Other.TypeHash;
48 Idx = Other.Idx;
49 Event = Other.Event;
50 return *this;
51 }
52
53 FORCEINLINE bool operator==(const TEventQueueEntry& Other) const
54 {
55 return ((Idx == Other.Idx)
56 && (Type == Other.Type)
57 && (TypeHash == Other.TypeHash)
58 && (Name == Other.Name)
59 && (Name != nullptr));
60 }
61
62 FORCEINLINE bool operator!=(const TEventQueueEntry& Other) const
63 {
64 return !(*this == Other);
65 }
66 };
67
73 class LEventQueue : public LObject
74 {
75 using EventInvoker = std::function<void()>;
77 using EventContainer = std::vector<EventElement>;
78 public:
79 LEventQueue(std::string_view InQueueName)
80 : QueueName(InQueueName.data())
81 {
82 LK_CORE_VERIFY(!InQueueName.empty());
84 }
85 LEventQueue(std::string_view InQueueName, const FEventHandler InHandler)
86 : QueueName(InQueueName.data())
87 , Handler(InHandler)
88 {
89 LK_CORE_VERIFY(!InQueueName.empty());
90 LK_CORE_VERIFY(InHandler, "Passed invalid handler to event queue");
92 }
93 LEventQueue() = delete;
94 LEventQueue(const LEventQueue& Other) = delete;
95 LEventQueue(LEventQueue&& Other) = delete;
96 virtual ~LEventQueue() = default;
97
98 LEventQueue& operator=(const LEventQueue& Other) = delete;
99 LEventQueue& operator=(LEventQueue&& Other) = delete;
100
101 void AttachHandler(const FEventHandler InHandler)
102 {
103 LK_CORE_DEBUG_TAG(LK_FMT_LIB::format("{}", QueueName), "Attaching event handler");
104 Handler = InHandler;
105 }
106
113 FORCEINLINE void Process(const uint16_t MaxThreshold = 0)
114 {
115 std::scoped_lock<std::mutex> ScopedLock(Mutex);
116 const std::size_t EventsToProcess = (MaxThreshold == 0) ? EventQueue.size() : MaxThreshold;
117 for (int Idx = 0; Idx < EventsToProcess; Idx++)
118 {
119 auto Iter = EventQueue.begin();
120 Iter->Event();
121 EventQueue.erase(Iter);
122 }
123 }
124
131 template<typename FirstFilter, typename... RemainingFilters>
132 FORCEINLINE void ProcessFiltered(const uint16_t MaxThreshold = 0)
133 {
134 std::unique_lock<std::mutex> ScopedLock(Mutex);
135 static_assert(!std::is_enum_v<FirstFilter>, "Enum implementation not supported yet");
136
137 auto IsEntryCorrectType = [](const EventElement& Entry) -> bool
138 {
139 return (Entry.TypeHash == typeid(FirstFilter).hash_code());
140 };
141
142 EventContainer FilteredQueue;
143 std::ranges::move(
144 EventQueue | std::views::filter(IsEntryCorrectType),
145 std::back_inserter(FilteredQueue)
146 );
147 if (FilteredQueue.empty())
148 {
149 return;
150 }
151
152 const std::size_t MovedEvents = std::erase_if(EventQueue, IsEntryCorrectType);
153 if (MovedEvents > 0)
154 {
155 const std::size_t EventsToProcess = (MaxThreshold == 0) ? FilteredQueue.size() : MaxThreshold;
156 for (int Idx = 0; Idx < EventsToProcess; Idx++)
157 {
158 auto Iter = FilteredQueue.begin();
159 LK_CORE_ASSERT(Iter->Name != nullptr, "Event indexed {} is invalid in queue {}", Idx, (QueueName ? QueueName : "NULL"));
160 #if defined(LK_ENGINE_EVENTQUEUE_DEBUG)
161 LK_CORE_CONSOLE_DEBUG("[{}] Executing {}: {}", QueueName, Iter->Idx, (Iter->Name ? Iter->Name : "NULL"));
162 #endif
163 Iter->Event();
164 FilteredQueue.erase(Iter);
165 }
166 }
167
168 if constexpr (sizeof...(RemainingFilters) > 0)
169 {
170 ScopedLock.unlock();
171 ProcessFiltered<RemainingFilters...>(MaxThreshold);
172 }
173 }
174
181 template<typename EventType, typename... EventArgs>
182 FORCEINLINE void Add(EventArgs&&... Args)
183 {
184 std::scoped_lock<std::mutex> ScopedLock(Mutex);
185 std::shared_ptr<EventType> Event = std::make_shared<EventType>(std::forward<EventArgs>(Args)...);
186 #if defined(LK_ENGINE_EVENTQUEUE_DEBUG)
187 LK_CORE_DEBUG_TAG(LK_FMT_LIB::format("{}", QueueName), "Queuing: {}", Event->GetName());
188 #endif
189 EventQueue.emplace_back(Event->GetName(), Event->GetType(), typeid(*Event), EventQueue.size(), [&, Event]()
190 {
191 LK_CORE_ASSERT(Handler, "No event handler registered");
192 if (Handler)
193 {
194 LK_CORE_TRACE_TAG("EventQueue", "Handling: {}", Event->ToString());
195 /* The handler sets the event result in LEvent::bHandled. */
196 Handler(*Event);
197
198 if (!Event->IsHandled())
199 {
200 LK_CORE_ERROR_TAG(LK_FMT_LIB::format("{}", QueueName), "{}: Failed", Event->GetName());
201 }
202 }
203 });
204 }
205
209 std::size_t GetCount() const { return EventQueue.size(); }
210
214 const char* GetName() const { return QueueName; }
215
216 FORCEINLINE EventContainer::iterator begin() { return EventQueue.begin(); }
217 FORCEINLINE EventContainer::iterator end() { return EventQueue.end(); }
218
219 private:
220 const char* QueueName = nullptr;
221 EventContainer EventQueue{};
222 FEventHandler Handler{};
223 std::mutex Mutex;
224
225 LCLASS(LEventQueue);
226 };
227
228}
Definition EventQueue.h:74
FORCEINLINE void Process(const uint16_t MaxThreshold=0)
Definition EventQueue.h:113
const char * GetName() const
Definition EventQueue.h:214
std::size_t GetCount() const
Definition EventQueue.h:209
FORCEINLINE void ProcessFiltered(const uint16_t MaxThreshold=0)
Definition EventQueue.h:132
FORCEINLINE void Add(EventArgs &&... Args)
Definition EventQueue.h:182
Definition Object.h:46
#define LCLASS(Class)
Definition CoreMacros.h:226
#define LOBJECT_REGISTER(...)
Definition CoreMacros.h:297
Definition Asset.h:11
EEventType
Definition Event.h:16
Definition EventQueue.h:12