fix event_bus

This commit is contained in:
tqcq 2024-04-04 00:13:29 +00:00
parent bf1584c750
commit 65fe7acded
2 changed files with 67 additions and 14 deletions

View File

@ -10,6 +10,11 @@ namespace sled {
class EventBus; class EventBus;
class Subscriber; class Subscriber;
namespace internal {
template<typename Event>
using RawType = typename std::remove_cv<typename std::remove_reference<Event>::type>::type;
}
namespace { namespace {
template<typename Event> template<typename Event>
@ -36,7 +41,7 @@ public:
sled::SharedMutexReadLock lock(&shared_mutex_); sled::SharedMutexReadLock lock(&shared_mutex_);
if (signals_.empty()) { return; } if (signals_.empty()) { return; }
auto iter = signals_.find(bus); 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> template<typename C>
@ -113,33 +118,36 @@ public:
EventBus(const EventBus &) = delete; EventBus(const EventBus &) = delete;
EventBus &operator=(const EventBus &) = delete; EventBus &operator=(const EventBus &) = delete;
template<typename Event> template<typename Event, typename U = internal::RawType<Event>>
void Post(const Event &event) void Post(Event &&event)
{ {
EventRegistry<Event>::Instance().Post(this, event); EventRegistry<U>::Instance().Post(this, std::forward<Event>(event));
} }
// On<Event1> ([](const Event1 &){}) // 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 typename std::enable_if<std::is_base_of<sigslot::has_slots_interface, C>::value>::type
Subscribe(C *instance, void (C::*method)(Event)) Subscribe(C *instance, void (C::*method)(Event))
{ {
{ {
sled::MutexLock lock(&mutex_); 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) 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_); sled::MutexLock lock(&mutex_);
if (EventRegistry<Event>::Instance().IsEmpty(this)) { if (EventRegistry<U>::Instance().IsEmpty(this)) {
auto iter = cleanup_handlers_.find(std::type_index(typeid(Event))); auto iter = cleanup_handlers_.find(std::type_index(typeid(U)));
if (iter != cleanup_handlers_.end()) { if (iter != cleanup_handlers_.end()) {
iter->second(this); iter->second(this);
cleanup_handlers_.erase(iter); cleanup_handlers_.erase(iter);
@ -148,8 +156,6 @@ public:
} }
} }
EventBus *operator->() { return this; }
private: private:
sled::Mutex mutex_; sled::Mutex mutex_;
std::unordered_map<std::type_index, std::function<void(EventBus *)>> cleanup_handlers_ GUARDED_BY(mutex_); std::unordered_map<std::type_index, std::function<void(EventBus *)>> cleanup_handlers_ GUARDED_BY(mutex_);

View File

@ -37,6 +37,21 @@ struct Subscriber : public sled::EventBus::Subscriber<> {
TEST_SUITE("EventBus") 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") TEST_CASE("single thread")
{ {
sled::EventBus bus; sled::EventBus bus;
@ -92,7 +107,13 @@ TEST_SUITE("EventBus")
struct AotmicEventSubscriber : public sled::EventBus::Subscriber<> { struct AotmicEventSubscriber : public sled::EventBus::Subscriber<> {
virtual ~AotmicEventSubscriber() = default; 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); std::atomic<int> value(0);
@ -117,4 +138,30 @@ TEST_SUITE("EventBus")
CHECK_EQ(invoke_count.load(), kPublishCount); CHECK_EQ(invoke_count.load(), kPublishCount);
CHECK_EQ(value.load(), kPublishCount * kSubscriberCount); 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);
}
} }