3#include <Foundation/Types/ScopeExit.h>
5template <
typename EventData,
typename MutexType, plEventType EventType>
7 : m_EventHandlers(pAllocator)
9#if PL_ENABLED(PL_COMPILE_FOR_DEVELOPMENT)
14template <
typename EventData,
typename MutexType, plEventType EventType>
17#if PL_ENABLED(PL_COMPILE_FOR_DEVELOPMENT)
18 PL_ASSERT_ALWAYS(m_pSelf ==
this,
"The plEvent was relocated in memory. This is not allowed, as it breaks the Unsubscribers.");
24template <
typename EventData,
typename MutexType, plEventType EventType>
29 if constexpr (std::is_same_v<MutexType, plNoMutex>)
31 if constexpr (EventType == plEventType::Default)
33 PL_ASSERT_DEV(m_uiRecursionDepth == 0,
"Can't add or remove event handlers while broadcasting (without a mutex). Either enable the use of a mutex on this event, or switch to plCopyOnBroadcastEvent if this should be allowed. Since this event does not have a mutex, this error can also happen due to multi-threaded access.");
37 PL_ASSERT_DEV(!handler.IsComparable() || !HasEventHandler(handler),
"The same event handler cannot be added twice");
39 auto& item = m_EventHandlers.ExpandAndGetRef();
40 item.m_Handler = std::move(handler);
41 item.m_SubscriptionID = ++m_NextSubscriptionID;
43 return item.m_SubscriptionID;
46template <
typename EventData,
typename MutexType, plEventType EventType>
51 if constexpr (std::is_same_v<MutexType, plNoMutex>)
53 if constexpr (EventType == plEventType::Default)
55 PL_ASSERT_DEV(m_uiRecursionDepth == 0,
"Can't add or remove event handlers while broadcasting (without a mutex). Either enable the use of a mutex on this event, or switch to plCopyOnBroadcastEvent if this should be allowed. Since this event does not have a mutex, this error can also happen due to multi-threaded access.");
60 inout_unsubscriber.m_pEvent =
this;
61 inout_unsubscriber.m_SubscriptionID = AddEventHandler(std::move(handler));
67template <
typename EventData,
typename MutexType, plEventType EventType>
70 PL_ASSERT_DEV(handler.IsComparable(),
"Lambdas that capture data cannot be removed via function pointer. Use an plEventSubscriptionID instead.");
74 if constexpr (EventType == plEventType::Default)
76 if constexpr (std::is_same_v<MutexType, plNoMutex>)
78 PL_ASSERT_DEV(m_uiRecursionDepth == 0,
"Can't add or remove event handlers while broadcasting (without a mutex). Either enable the use of a mutex on this event, or switch to plCopyOnBroadcastEvent if this should be allowed. Since this event does not have a mutex, this error can also happen due to multi-threaded access.");
82 for (plUInt32 idx = 0; idx < m_EventHandlers.GetCount(); ++idx)
84 if (m_EventHandlers[idx].m_Handler.IsEqualIfComparable(handler))
86 if constexpr (EventType == plEventType::Default)
91 if (m_uiRecursionDepth > 0)
94 m_EventHandlers[idx].m_Handler = {};
95 m_EventHandlers[idx].m_SubscriptionID = {};
101 m_EventHandlers.RemoveAtAndCopy(idx);
106 PL_ASSERT_DEV(
false,
"plEvent::RemoveEventHandler: Handler has not been registered or already been unregistered.");
109template <
typename EventData,
typename MutexType, plEventType EventType>
115 const plEventSubscriptionID subId = inout_id;
120 if constexpr (EventType == plEventType::Default)
122 if constexpr (std::is_same_v<MutexType, plNoMutex>)
124 PL_ASSERT_DEV(m_uiRecursionDepth == 0,
"Can't add or remove event handlers while broadcasting (without a mutex). Either enable the use of a mutex on this event, or switch to plCopyOnBroadcastEvent if this should be allowed. Since this event does not have a mutex, this error can also happen due to multi-threaded access.");
128 for (plUInt32 idx = 0; idx < m_EventHandlers.GetCount(); ++idx)
130 if (m_EventHandlers[idx].m_SubscriptionID == subId)
132 if constexpr (EventType == plEventType::Default)
137 if (m_uiRecursionDepth > 0)
140 m_EventHandlers[idx].m_Handler = {};
141 m_EventHandlers[idx].m_SubscriptionID = {};
147 m_EventHandlers.RemoveAtAndCopy(idx);
152 PL_ASSERT_DEV(
false,
"plEvent::RemoveEventHandler: Invalid subscription ID '{0}'.", (plInt32)subId);
155template <
typename EventData,
typename MutexType, plEventType EventType>
158 PL_ASSERT_DEV(handler.IsComparable(),
"Lambdas that capture data cannot be checked via function pointer. Use an plEventSubscriptionID instead.");
162 for (plUInt32 i = 0; i < m_EventHandlers.GetCount(); ++i)
164 if (m_EventHandlers[i].m_Handler.IsEqualIfComparable(handler))
171template <
typename EventData,
typename MutexType, plEventType EventType>
175 m_EventHandlers.Clear();
178template <
typename EventData,
typename MutexType, plEventType EventType>
182 return m_EventHandlers.IsEmpty();
186template <
typename EventData,
typename MutexType, plEventType EventType>
189 if constexpr (EventType == plEventType::Default)
193 PL_ASSERT_DEV(m_uiRecursionDepth <= uiMaxRecursionDepth,
"The event has been triggered recursively or from several threads simultaneously.");
195 if (m_uiRecursionDepth > uiMaxRecursionDepth)
198#if PL_ENABLED(PL_COMPILE_FOR_DEVELOPMENT)
199 PL_ASSERT_ALWAYS(m_pSelf ==
this,
"The plEvent was relocated in memory. This is not allowed, as it breaks the Unsubscribers.");
202 m_uiRecursionDepth++;
205 auto scopeExit = plMakeScopeExit([&]()
206 { m_uiRecursionDepth--; });
209 plUInt32 uiMaxHandlers = m_EventHandlers.GetCount();
211 for (plUInt32 ui = 0; ui < uiMaxHandlers;)
213 if (m_EventHandlers[ui].m_Handler.IsValid())
215 m_EventHandlers[ui].m_Handler(eventData);
220 m_EventHandlers.RemoveAtAndCopy(ui);
231 if constexpr (RecursionDepthSupported)
233 PL_ASSERT_DEV(m_uiRecursionDepth <= uiMaxRecursionDepth,
"The event has been triggered recursively or from several threads simultaneously.");
235 if (m_uiRecursionDepth > uiMaxRecursionDepth)
238#if PL_ENABLED(PL_COMPILE_FOR_DEVELOPMENT)
239 PL_ASSERT_ALWAYS(m_pSelf ==
this,
"The plEvent was relocated in memory. This is not allowed, as it breaks the Unsubscribers.");
242 m_uiRecursionDepth++;
246 PL_ASSERT_DEV(uiMaxRecursionDepth == 255,
"uiMaxRecursionDepth is not supported if plEventType::CopyOnBroadcast is used and the event needs to be threadsafe.");
249#if PL_ENABLED(PL_COMPILE_FOR_DEVELOPMENT)
250 PL_ASSERT_ALWAYS(m_pSelf ==
this,
"The plEvent was relocated in memory. This is not allowed, as it breaks the Unsubscribers.");
253 eventHandlers = m_EventHandlers;
257 auto scopeExit = plMakeScopeExit([&]()
260#if PL_ENABLED(PL_COMPILER_MSVC) && _MSC_VER < 1920
261 if (RecursionDepthSupported)
263 m_uiRecursionDepth--;
266 if constexpr (RecursionDepthSupported)
268 m_uiRecursionDepth--;
273 const plUInt32 uiHandlerCount = eventHandlers.
GetCount();
274 for (plUInt32 ui = 0; ui < uiHandlerCount; ++ui)
276 eventHandlers[ui].m_Handler(eventData);
282template <
typename EventData,
typename MutexType,
typename AllocatorWrapper, plEventType EventType>
284 :
plEventBase<EventData, MutexType, EventType>(AllocatorWrapper::GetAllocator())
288template <
typename EventData,
typename MutexType,
typename AllocatorWrapper, plEventType EventType>
290 :
plEventBase<EventData, MutexType, EventType>(pAllocator)
Base class for all memory allocators.
Definition Allocator.h:23
plUInt32 GetCount() const
Returns the number of active elements in the array.
Definition ArrayBase_inl.h:172
An object that can be passed to plEvent::AddEventHandler to store the subscription information and au...
Definition Event.h:50
void Unsubscribe()
If the unsubscriber holds a valid subscription, it will be removed from the target plEvent.
Definition Event.h:73
This class propagates event information to registered event handlers.
Definition Event.h:37
bool IsEmpty() const
Returns true, if no event handlers are registered.
Definition Event_inl.h:179
plEventBase(plAllocator *pAllocator)
Constructor.
Definition Event_inl.h:6
bool HasEventHandler(const Handler &handler) const
Checks whether an event handler has already been registered.
Definition Event_inl.h:156
void Clear()
Removes all registered event handlers.
Definition Event_inl.h:172
plEventSubscriptionID AddEventHandler(Handler handler) const
Adds a function as an event handler. All handlers will be notified in the order that they were regist...
Definition Event_inl.h:25
void RemoveEventHandler(const Handler &handler) const
Removes a previously registered handler. It is an error to remove a handler that was not registered.
Definition Event_inl.h:68
void Broadcast(EventData pEventData, plUInt8 uiMaxRecursionDepth=MaxRecursionDepthDefault)
This function will broadcast to all registered users, that this event has just happened....
Definition Event_inl.h:187
A hybrid array uses in-place storage to handle the first few elements without any allocation....
Definition HybridArray.h:12