Commit 65fe7acd authored by tqcq's avatar tqcq
Browse files

fix event_bus

parent bf1584c7
Loading
Loading
Loading
Loading
+19 −13
Original line number Diff line number Diff line
@@ -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>
@@ -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>
@@ -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);
@@ -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_);
+48 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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);
    }
}