168 lines
4.8 KiB
MQL5
168 lines
4.8 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| EventBus.mqh |
| |
//| Copyright 2025, MetaQuotes Ltd. |
| |
//| https://www.mql5.com |
| |
//+------------------------------------------------------------------+
| |
| |
#include "../Interfaces/Listerners/IStructEventListener.mqh"
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class EventBus
| |
{
| |
private:
| |
IEventListener* m_listeners[]; // dynamic array of listeners
| |
bool m_isNotifying; // flag to prevent modification during iteration
| |
int m_pendingRemovals; // for deferred removal
| |
| |
// Helper to remove at index (shifts left)
| |
void RemoveAt(int index)
| |
{
| |
int size = ArraySize(m_listeners);
| |
for(int i = index; i < size - 1; i++)
| |
m_listeners[i] = m_listeners[i + 1];
| |
ArrayResize(m_listeners, size - 1);
| |
}
| |
| |
// Clean up null pointers from array (during iteration or after)
| |
void CleanupNullListeners()
| |
{
| |
if(m_isNotifying) return; // defer until after publish
| |
for(int i = ArraySize(m_listeners) - 1; i >= 0; i--)
| |
{
| |
if(CheckPointer(m_listeners[i]) == POINTER_INVALID)
| |
RemoveAt(i);
| |
}
| |
}
| |
| |
public:
| |
EventBus() : m_isNotifying(false) {}
| |
~EventBus() { UnsubscribeAll(); }
| |
| |
// Subscribe – adds listener if not already subscribed
| |
void Subscribe(IEventListener *listener)
| |
{
| |
if(listener == NULL) return;
| |
if(CheckPointer(listener) == POINTER_INVALID) return;
| |
| |
// Avoid duplicate subscriptions
| |
for(int i = 0; i < ArraySize(m_listeners); i++)
| |
{
| |
if(m_listeners[i] == listener)
| |
return;
| |
}
| |
| |
int size = ArraySize(m_listeners);
| |
ArrayResize(m_listeners, size + 1);
| |
m_listeners[size] = listener;
| |
}
| |
| |
// Unsubscribe by pointer
| |
void Unsubscribe(IEventListener *listener)
| |
{
| |
if(listener == NULL) return;
| |
| |
if(m_isNotifying)
| |
{
| |
// Defer removal – mark as NULL (will be cleaned after publish)
| |
for(int i = 0; i < ArraySize(m_listeners); i++)
| |
{
| |
if(m_listeners[i] == listener)
| |
{
| |
m_listeners[i] = NULL;
| |
m_pendingRemovals++;
| |
break;
| |
}
| |
}
| |
}
| |
else
| |
{
| |
for(int i = 0; i < ArraySize(m_listeners); i++)
| |
{
| |
if(m_listeners[i] == listener)
| |
{
| |
RemoveAt(i);
| |
break;
| |
}
| |
}
| |
}
| |
}
| |
| |
// Unsubscribe all listeners
| |
void UnsubscribeAll()
| |
{
| |
if(m_isNotifying) return; // prevent modification during iteration
| |
ArrayResize(m_listeners, 0);
| |
m_pendingRemovals = 0;
| |
}
| |
| |
// Publish an event (takes ownership – caller must allocate with new)
| |
void Publish(IEvent *event)
| |
{
| |
if(event == NULL) return;
| |
| |
m_isNotifying = true;
| |
int size = ArraySize(m_listeners);
| |
for(int i = 0; i < size; i++)
| |
{
| |
IEventListener* listener = m_listeners[i];
| |
if(CheckPointer(listener) == POINTER_INVALID)
| |
continue; // skip null entries (will be cleaned later)
| |
listener.OnEvent(event);
| |
}
| |
m_isNotifying = false;
| |
| |
// Clean up any null listeners that were marked during iteration
| |
if(m_pendingRemovals > 0)
| |
{
| |
CleanupNullListeners();
| |
m_pendingRemovals = 0;
| |
}
| |
| |
delete event; // event bus takes ownership
| |
}
| |
| |
// Get number of active listeners
| |
int GetListenerCount() const
| |
{
| |
int count = 0;
| |
for(int i = 0; i < ArraySize(m_listeners); i++)
| |
{
| |
if(CheckPointer(m_listeners[i]) != POINTER_INVALID)
| |
count++;
| |
}
| |
return count;
| |
}
| |
};
| |
//+-------------Stores-----------------------------------------------------+
| |
/*class EventBus
| |
{
| |
private:
| |
IEvent *events[];
| |
IEventListener *listeners[];
| |
| |
public:
| |
| |
void subscribe(IEventListener *l)
| |
{
| |
int size = ArraySize(listeners);
| |
ArrayResize(listeners, size + 1);
| |
listeners[size] = l;
| |
}
| |
| |
void publish(IEvent *e)
| |
{
| |
// store event (optional)
| |
int size = ArraySize(events);
| |
ArrayResize(events, size + 1);
| |
events[size] = e;
| |
| |
// broadcast
| |
for(int i = 0; i < ArraySize(listeners); i++)
| |
{
| |
listeners[i].onEvent(e);
| |
}
| |
}
| |
};*/
| |
//+------------------------------------------------------------------+
|