#pragma once #include #include #include #include "subscriber.hpp" #include "thread_pool.hpp" template class Subscribable { using TSubscriber = Subscriber; private: std::unordered_map>> subscribersMap_; public: void subscribe(const TEventId& eventId, std::shared_ptr subscriber) { subscribersMap_[eventId].push_back(subscriber); } void unsubscribe(const TEventId& eventId, std::shared_ptr subscriber) { auto entry = subscribersMap_.find(eventId); if (entry == subscribersMap_.end()) { return; } std::erase(entry->second, subscriber); if (entry->second.empty()) { subscribersMap_.erase(entry); } } void notify(const TEventId& eventId, const TEventInfo& eventInfo, ThreadPool& threadPool) const { auto entry = subscribersMap_.find(eventId); if (entry == subscribersMap_.end()) { return; } // edge case: if a subscriber unsubscribes itself during notification // this modifies the vector and makes my iterators invalid auto subscribersCopy = entry->second; for (auto& subscriber : subscribersCopy) { // Enqueue each notification as a separate task in the thread pool // capture by value next to copy the shared_ptr threadPool.enqueue([subscriber, eventId, eventInfo]() { subscriber->onNotification(eventId, eventInfo); }); } } };