//+------------------------------------------------------------------+ //| 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(); } }; //+------------------------------------------------------------------+ //+------------------------------------------------------------------+