Loading src/sled/event_bus/event_bus.h +19 −13 Original line number Diff line number Diff line Loading @@ -10,6 +10,11 @@ namespace sled { class EventBus; class Subscriber; namespace internal { template<typename Event> using RawType = typename std::remove_cv<typename std::remove_reference<Event>::type>::type; } namespace { template<typename Event> Loading @@ -36,7 +41,7 @@ public: sled::SharedMutexReadLock lock(&shared_mutex_); if (signals_.empty()) { return; } auto iter = signals_.find(bus); if (iter != signals_.end()) { iter->second(event); } if (iter != signals_.end()) { iter->second(std::forward<Event>(event)); } } template<typename C> Loading Loading @@ -113,33 +118,36 @@ public: EventBus(const EventBus &) = delete; EventBus &operator=(const EventBus &) = delete; template<typename Event> void Post(const Event &event) template<typename Event, typename U = internal::RawType<Event>> void Post(Event &&event) { EventRegistry<Event>::Instance().Post(this, event); EventRegistry<U>::Instance().Post(this, std::forward<Event>(event)); } // On<Event1> ([](const Event1 &){}) template<typename Event, typename C> template<typename Event, typename C, typename U = internal::RawType<Event>> typename std::enable_if<std::is_base_of<sigslot::has_slots_interface, C>::value>::type Subscribe(C *instance, void (C::*method)(Event)) { { sled::MutexLock lock(&mutex_); cleanup_handlers_[std::type_index(typeid(Event))] = EventRegistry<Event>::GetCleanupHandler(); auto iter = cleanup_handlers_.find(std::type_index(typeid(U))); if (iter == cleanup_handlers_.end()) { cleanup_handlers_[std::type_index(typeid(U))] = EventRegistry<U>::GetCleanupHandler(); } } EventRegistry<Event>::Instance().Subscribe(this, instance, method); EventRegistry<U>::Instance().Subscribe(this, instance, method); } template<typename Event, typename C> template<typename Event, typename C, typename U = internal::RawType<Event>> typename std::enable_if<std::is_base_of<sigslot::has_slots_interface, C>::value>::type Unsubscribe(C *instance) { EventRegistry<Event>::Instance().Unsubscribe(this, instance); EventRegistry<U>::Instance().Unsubscribe(this, instance); { sled::MutexLock lock(&mutex_); if (EventRegistry<Event>::Instance().IsEmpty(this)) { auto iter = cleanup_handlers_.find(std::type_index(typeid(Event))); if (EventRegistry<U>::Instance().IsEmpty(this)) { auto iter = cleanup_handlers_.find(std::type_index(typeid(U))); if (iter != cleanup_handlers_.end()) { iter->second(this); cleanup_handlers_.erase(iter); Loading @@ -148,8 +156,6 @@ public: } } EventBus *operator->() { return this; } private: sled::Mutex mutex_; std::unordered_map<std::type_index, std::function<void(EventBus *)>> cleanup_handlers_ GUARDED_BY(mutex_); Loading src/sled/event_bus/event_bus_test.cc +48 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,21 @@ struct Subscriber : public sled::EventBus::Subscriber<> { TEST_SUITE("EventBus") { TEST_CASE("RawType") { CHECK(std::is_same<int, sled::internal::RawType<int>>::value); CHECK(std::is_same<int, sled::internal::RawType<const int>>::value); CHECK(std::is_same<int, sled::internal::RawType<const int &>>::value); CHECK(std::is_same<int, sled::internal::RawType<int &>>::value); CHECK(std::is_same<int, sled::internal::RawType<int &&>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile int>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile const int>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile const int &>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile int &>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile int &&>>::value); } TEST_CASE("single thread") { sled::EventBus bus; Loading Loading @@ -92,7 +107,13 @@ TEST_SUITE("EventBus") struct AotmicEventSubscriber : public sled::EventBus::Subscriber<> { virtual ~AotmicEventSubscriber() = default; void OnEvent(AtomicEvent event) { event.data.fetch_add(1); } void OnEvent(AtomicEvent event) { ++a; event.data.fetch_add(1); } int a = 0; }; std::atomic<int> value(0); Loading @@ -117,4 +138,30 @@ TEST_SUITE("EventBus") CHECK_EQ(invoke_count.load(), kPublishCount); CHECK_EQ(value.load(), kPublishCount * kSubscriberCount); } TEST_CASE("same type") { struct Event { int a; }; struct Subscriber : public sled::EventBus::Subscriber<> { void OnEvent(Event event) { a += event.a; } int a = 0; }; sled::EventBus bus; Subscriber subscriber1; Subscriber subscriber2; bus.Subscribe<Event>(&subscriber1, &Subscriber::OnEvent); bus.Subscribe<Event>(&subscriber2, &Subscriber::OnEvent); bus.Post(Event{1}); CHECK_EQ(subscriber1.a, 1); CHECK_EQ(subscriber2.a, 1); Event e{1}; bus.Post(e); CHECK_EQ(subscriber1.a, 2); CHECK_EQ(subscriber2.a, 2); } } Loading
src/sled/event_bus/event_bus.h +19 −13 Original line number Diff line number Diff line Loading @@ -10,6 +10,11 @@ namespace sled { class EventBus; class Subscriber; namespace internal { template<typename Event> using RawType = typename std::remove_cv<typename std::remove_reference<Event>::type>::type; } namespace { template<typename Event> Loading @@ -36,7 +41,7 @@ public: sled::SharedMutexReadLock lock(&shared_mutex_); if (signals_.empty()) { return; } auto iter = signals_.find(bus); if (iter != signals_.end()) { iter->second(event); } if (iter != signals_.end()) { iter->second(std::forward<Event>(event)); } } template<typename C> Loading Loading @@ -113,33 +118,36 @@ public: EventBus(const EventBus &) = delete; EventBus &operator=(const EventBus &) = delete; template<typename Event> void Post(const Event &event) template<typename Event, typename U = internal::RawType<Event>> void Post(Event &&event) { EventRegistry<Event>::Instance().Post(this, event); EventRegistry<U>::Instance().Post(this, std::forward<Event>(event)); } // On<Event1> ([](const Event1 &){}) template<typename Event, typename C> template<typename Event, typename C, typename U = internal::RawType<Event>> typename std::enable_if<std::is_base_of<sigslot::has_slots_interface, C>::value>::type Subscribe(C *instance, void (C::*method)(Event)) { { sled::MutexLock lock(&mutex_); cleanup_handlers_[std::type_index(typeid(Event))] = EventRegistry<Event>::GetCleanupHandler(); auto iter = cleanup_handlers_.find(std::type_index(typeid(U))); if (iter == cleanup_handlers_.end()) { cleanup_handlers_[std::type_index(typeid(U))] = EventRegistry<U>::GetCleanupHandler(); } } EventRegistry<Event>::Instance().Subscribe(this, instance, method); EventRegistry<U>::Instance().Subscribe(this, instance, method); } template<typename Event, typename C> template<typename Event, typename C, typename U = internal::RawType<Event>> typename std::enable_if<std::is_base_of<sigslot::has_slots_interface, C>::value>::type Unsubscribe(C *instance) { EventRegistry<Event>::Instance().Unsubscribe(this, instance); EventRegistry<U>::Instance().Unsubscribe(this, instance); { sled::MutexLock lock(&mutex_); if (EventRegistry<Event>::Instance().IsEmpty(this)) { auto iter = cleanup_handlers_.find(std::type_index(typeid(Event))); if (EventRegistry<U>::Instance().IsEmpty(this)) { auto iter = cleanup_handlers_.find(std::type_index(typeid(U))); if (iter != cleanup_handlers_.end()) { iter->second(this); cleanup_handlers_.erase(iter); Loading @@ -148,8 +156,6 @@ public: } } EventBus *operator->() { return this; } private: sled::Mutex mutex_; std::unordered_map<std::type_index, std::function<void(EventBus *)>> cleanup_handlers_ GUARDED_BY(mutex_); Loading
src/sled/event_bus/event_bus_test.cc +48 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,21 @@ struct Subscriber : public sled::EventBus::Subscriber<> { TEST_SUITE("EventBus") { TEST_CASE("RawType") { CHECK(std::is_same<int, sled::internal::RawType<int>>::value); CHECK(std::is_same<int, sled::internal::RawType<const int>>::value); CHECK(std::is_same<int, sled::internal::RawType<const int &>>::value); CHECK(std::is_same<int, sled::internal::RawType<int &>>::value); CHECK(std::is_same<int, sled::internal::RawType<int &&>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile int>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile const int>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile const int &>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile int &>>::value); CHECK(std::is_same<int, sled::internal::RawType<volatile int &&>>::value); } TEST_CASE("single thread") { sled::EventBus bus; Loading Loading @@ -92,7 +107,13 @@ TEST_SUITE("EventBus") struct AotmicEventSubscriber : public sled::EventBus::Subscriber<> { virtual ~AotmicEventSubscriber() = default; void OnEvent(AtomicEvent event) { event.data.fetch_add(1); } void OnEvent(AtomicEvent event) { ++a; event.data.fetch_add(1); } int a = 0; }; std::atomic<int> value(0); Loading @@ -117,4 +138,30 @@ TEST_SUITE("EventBus") CHECK_EQ(invoke_count.load(), kPublishCount); CHECK_EQ(value.load(), kPublishCount * kSubscriberCount); } TEST_CASE("same type") { struct Event { int a; }; struct Subscriber : public sled::EventBus::Subscriber<> { void OnEvent(Event event) { a += event.a; } int a = 0; }; sled::EventBus bus; Subscriber subscriber1; Subscriber subscriber2; bus.Subscribe<Event>(&subscriber1, &Subscriber::OnEvent); bus.Subscribe<Event>(&subscriber2, &Subscriber::OnEvent); bus.Post(Event{1}); CHECK_EQ(subscriber1.a, 1); CHECK_EQ(subscriber2.a, 1); Event e{1}; bus.Post(e); CHECK_EQ(subscriber1.a, 2); CHECK_EQ(subscriber2.a, 2); } }