2026-08-06 00:19:08 +02:00 | | | //+------------------------------------------------------------------+
|
| | | //| 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"
|
| | |
|
2026-08-10 20:23:58 +02:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-06 00:19:08 +02:00 | | | class EventBus
|
2026-08-10 20:23:58 +02:00 | | | {
|
2026-08-06 00:19:08 +02:00 | | | private:
|
| | | // Subscription record
|
| | | struct Subscription
|
2026-08-10 20:23:58 +02:00 | | | {
|
2026-08-06 00:19:08 +02:00 | | | EventType type;
|
| | | IEventListener* listener;
|
2026-08-10 20:23:58 +02:00 | | | };
|
2026-08-06 00:19:08 +02:00 | | |
|
| | | // Circular buffer for event pointers
|
| | | AbstractEvent* m_queue[512];
|
2026-08-10 20:23:58 +02:00 | | | int m_head;
|
| | | int m_tail;
|
2026-08-06 00:19:08 +02:00 | | |
|
| | | // Dynamic array of subscriptions
|
2026-08-10 20:23:58 +02:00 | | | Subscription m_subscriptions[];
|
| | | int m_subCount;
|
2026-08-06 00:19:08 +02:00 | | |
|
| | | // Find index of a specific subscription, or -1
|
2026-08-10 20:23:58 +02:00 | | | int FindSubscription(EventType type, IEventListener* listener) const
|
| | | {
|
2026-08-06 00:19:08 +02:00 | | | for(int i = 0; i < m_subCount; i++)
|
2026-08-10 20:23:58 +02:00 | | | {
|
2026-08-06 00:19:08 +02:00 | | | if(m_subscriptions[i].type == type && m_subscriptions[i].listener == listener)
|
| | | return i;
|
2026-08-10 20:23:58 +02:00 | | | }
|
2026-08-06 00:19:08 +02:00 | | | return -1;
|
2026-08-10 20:23:58 +02:00 | | | }
|
2026-08-06 00:19:08 +02:00 | | |
|
| | | public:
|
2026-08-10 20:23:58 +02:00 | | | EventBus() : m_head(0), m_tail(0), m_subCount(0) {}
|
2026-08-06 00:19:08 +02:00 | | |
|
| | | // Subscribe a listener for a specific event type
|
2026-08-10 20:23:58 +02:00 | | | void Subscribe(EventType type, IEventListener* listener)
|
| | | {
|
2026-08-06 00:19:08 +02:00 | | | 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;
|
2026-08-10 20:23:58 +02:00 | | | }
|
2026-08-06 00:19:08 +02:00 | | |
|
| | | // Unsubscribe
|
2026-08-10 20:23:58 +02:00 | | | void Unsubscribe(EventType type, IEventListener* listener)
|
| | | {
|
2026-08-06 00:19:08 +02:00 | | | int idx = FindSubscription(type, listener);
|
2026-08-10 20:23:58 +02:00 | | | if(idx < 0)
|
| | | return;
|
2026-08-06 00:19:08 +02:00 | | |
|
| | | // Shift remaining elements
|
| | | for(int i = idx; i < m_subCount - 1; i++)
|
2026-08-10 20:23:58 +02:00 | | | m_subscriptions[i] = m_subscriptions[i + 1];
|
2026-08-06 00:19:08 +02:00 | | | m_subCount--;
|
| | | ArrayResize(m_subscriptions, m_subCount);
|
2026-08-10 20:23:58 +02:00 | | | }
|
2026-08-06 00:19:08 +02:00 | | |
|
2026-08-10 20:23:58 +02:00 | | | bool IsEmpty() const { return m_head == m_tail; }
|
| | | bool IsFull() const { return ((m_tail + 1) % 512) == m_head; }
|
2026-08-06 00:19:08 +02:00 | | |
|
| | | // Push an event (takes ownership of the pointer)
|
2026-08-10 20:23:58 +02:00 | | | void Push(AbstractEvent* event)
|
| | | {
|
2026-08-06 00:19:08 +02:00 | | | if(IsFull())
|
2026-08-10 20:23:58 +02:00 | | | {
|
| | |
|
2026-08-06 00:19:08 +02:00 | | | delete event;
|
| | | return;
|
2026-08-10 20:23:58 +02:00 | | | }
|
| | |
|
2026-08-06 00:19:08 +02:00 | | | m_queue[m_tail] = event;
|
| | | m_tail = (m_tail + 1) % 512;
|
2026-08-10 20:23:58 +02:00 | | | }
|
| | | void Dispatch()
|
| | | {
|
2026-08-06 00:19:08 +02:00 | | | while(!IsEmpty())
|
2026-08-10 20:23:58 +02:00 | | | {
|
2026-08-06 00:19:08 +02:00 | | | AbstractEvent* event = m_queue[m_head];
|
| | | m_head = (m_head + 1) % 512;
|
| | | EventType type = event.GetType();
|
2026-08-10 20:23:58 +02:00 | | |
|
2026-08-06 00:19:08 +02:00 | | |
|
2026-08-10 20:23:58 +02:00 | | | int matchCount = 0;
|
2026-08-06 00:19:08 +02:00 | | | for(int i = 0; i < m_subCount; i++)
|
2026-08-10 20:23:58 +02:00 | | | {
|
2026-08-06 00:19:08 +02:00 | | | if(m_subscriptions[i].type == type)
|
2026-08-10 20:23:58 +02:00 | | | {
|
| | | matchCount++;
|
2026-08-06 00:19:08 +02:00 | | | m_subscriptions[i].listener.OnEvent(event);
|
2026-08-10 20:23:58 +02:00 | | | }
|
| | | }
|
| | |
|
| | | delete event;
|
| | | }
|
| | | }
|
| | |
|
2026-08-06 00:19:08 +02:00 | | | // Clean up any remaining events (e.g., on shutdown)
|
2026-08-10 20:23:58 +02:00 | | | void Clear()
|
| | | {
|
2026-08-06 00:19:08 +02:00 | | | while(!IsEmpty())
|
2026-08-10 20:23:58 +02:00 | | | {
|
2026-08-06 00:19:08 +02:00 | | | AbstractEvent* event = m_queue[m_head];
|
| | | m_head = (m_head + 1) % 512;
|
| | | delete event;
|
2026-08-10 20:23:58 +02:00 | | | }
|
| | | }
|
2026-08-06 00:19:08 +02:00 | | |
|
2026-08-10 20:23:58 +02:00 | | | ~EventBus()
|
| | | {
|
2026-08-06 00:19:08 +02:00 | | | Clear();
|
2026-08-10 20:23:58 +02:00 | | | }
|
| | | };
|
| | | //+------------------------------------------------------------------+
|
| | | //+------------------------------------------------------------------+
|