132 lines
3.7 KiB
MQL5
132 lines
3.7 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| EventBus.mqh |
| |||
//| Copyright 2025, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "Copyright 2025, MetaQuotes Ltd."
| |||
#property link "https://www.mql5.com"
| |||
#property version "1.00"
| |||
| |||
#include "AbstractEvent.mqh"
| |||
#include "IEventListener.mqh"
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
class EventBus
| |||
{
| |||
private:
| |||
// Subscription record
| |||
struct Subscription
| |||
{
| |||
EventType type;
| |||
IEventListener* listener;
| |||
};
| |||
| |||
// Circular buffer for event pointers
| |||
AbstractEvent* m_queue[512];
| |||
int m_head;
| |||
int m_tail;
| |||
| |||
// Dynamic array of subscriptions
| |||
Subscription m_subscriptions[];
| |||
int m_subCount;
| |||
| |||
// Find index of a specific subscription, or -1
| |||
int FindSubscription(EventType type, IEventListener* listener) const
| |||
{
| |||
for(int i = 0; i < m_subCount; i++)
| |||
{
| |||
if(m_subscriptions[i].type == type && m_subscriptions[i].listener == listener)
| |||
return i;
| |||
}
| |||
return -1;
| |||
}
| |||
| |||
public:
| |||
EventBus() : m_head(0), m_tail(0), m_subCount(0) {}
| |||
| |||
// Subscribe a listener for a specific event type
| |||
void Subscribe(EventType type, IEventListener* listener)
| |||
{
| |||
if(FindSubscription(type, listener) >= 0)
| |||
return; // already subscribed
| |||
| |||
int size = ArraySize(m_subscriptions);
| |||
ArrayResize(m_subscriptions, size + 1);
| |||
m_subscriptions[size].type = type;
| |||
m_subscriptions[size].listener = listener;
| |||
m_subCount = size + 1;
| |||
}
| |||
| |||
// Unsubscribe
| |||
void Unsubscribe(EventType type, IEventListener* listener)
| |||
{
| |||
int idx = FindSubscription(type, listener);
| |||
if(idx < 0)
| |||
return;
| |||
| |||
// Shift remaining elements
| |||
for(int i = idx; i < m_subCount - 1; i++)
| |||
m_subscriptions[i] = m_subscriptions[i + 1];
| |||
m_subCount--;
| |||
ArrayResize(m_subscriptions, m_subCount);
| |||
}
| |||
| |||
bool IsEmpty() const { return m_head == m_tail; }
| |||
bool IsFull() const { return ((m_tail + 1) % 512) == m_head; }
| |||
| |||
// Push an event (takes ownership of the pointer)
| |||
void Push(AbstractEvent* event)
| |||
{
| |||
if(IsFull())
| |||
{
| |||
| |||
delete event;
| |||
return;
| |||
}
| |||
| |||
m_queue[m_tail] = event;
| |||
m_tail = (m_tail + 1) % 512;
| |||
}
| |||
void Dispatch()
| |||
{
| |||
while(!IsEmpty())
| |||
{
| |||
AbstractEvent* event = m_queue[m_head];
| |||
m_head = (m_head + 1) % 512;
| |||
EventType type = event.GetType();
| |||
| |||
| |||
int matchCount = 0;
| |||
for(int i = 0; i < m_subCount; i++)
| |||
{
| |||
if(m_subscriptions[i].type == type)
| |||
{
| |||
matchCount++;
| |||
m_subscriptions[i].listener.OnEvent(event);
| |||
}
| |||
}
| |||
| |||
delete event;
| |||
}
| |||
}
| |||
| |||
// Clean up any remaining events (e.g., on shutdown)
| |||
void Clear()
| |||
{
| |||
while(!IsEmpty())
| |||
{
| |||
AbstractEvent* event = m_queue[m_head];
| |||
m_head = (m_head + 1) % 512;
| |||
delete event;
| |||
}
| |||
}
| |||
| |||
~EventBus()
| |||
{
| |||
Clear();
| |||
}
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//+------------------------------------------------------------------+
|