From 2bb9c3e6791df7fea620781d1513bec35b35938e Mon Sep 17 00:00:00 2001 From: Dawid Drozd Date: Wed, 30 Oct 2019 17:44:52 +0100 Subject: [PATCH] Add TagEventBus --- lib/CMakeLists.txt | 1 + lib/src/dexode/eventbus/TagEventBus.hpp | 121 ++++++++++++++++++ .../eventbus/internal/ListenerAttorney.hpp | 6 + test/CMakeLists.txt | 1 + test/src/TestTagEventBus.cpp | 67 ++++++++++ 5 files changed, 196 insertions(+) create mode 100644 lib/src/dexode/eventbus/TagEventBus.hpp create mode 100644 test/src/TestTagEventBus.cpp diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index fc4137a..36048bb 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -44,6 +44,7 @@ add_library(EventBus src/dexode/eventbus/Listener.hpp src/dexode/eventbus/strategy/Protected.cpp src/dexode/eventbus/strategy/Protected.hpp src/dexode/eventbus/strategy/Transaction.hpp + src/dexode/eventbus/TagEventBus.hpp ) add_library(Dexode::EventBus ALIAS EventBus) diff --git a/lib/src/dexode/eventbus/TagEventBus.hpp b/lib/src/dexode/eventbus/TagEventBus.hpp new file mode 100644 index 0000000..7e01a27 --- /dev/null +++ b/lib/src/dexode/eventbus/TagEventBus.hpp @@ -0,0 +1,121 @@ +// +// Created by gelldur on 30.10.2019. +// +#pragma once + +#include +#include +#include + +#include "dexode/EventBus.hpp" + +namespace dexode::eventbus +{ + +template +class TagEventBus +{ + template + friend class dexode::eventbus::internal::ListenerAttorney; + + using EventBus_t = EventBus; + +public: + using ListenerAll = eventbus::Listener>; + using Listener = typename EventBus::Listener; // alias + + TagEventBus(const std::vector& tags) + { + for(const auto& tag : tags) + { + _tagToBus.emplace(tag, std::make_shared()); + } + } + + ~TagEventBus() = default; + + TagEventBus(const TagEventBus&) = delete; + TagEventBus(TagEventBus&&) = delete; + + TagEventBus& operator=(TagEventBus&&) = delete; + TagEventBus& operator=(const TagEventBus&) = delete; + + template + void post(const Event& event) + { + _allBus.post(event); + for(auto& element : _tagToBus) + { + element.second->post(event); + } + } + + template + void postpone(Event event) + { + _allBus.postpone(event); + for(auto& element : _tagToBus) + { + element.second->postpone(event); + } + } + + template + void post(const std::string& tag, const Event& event) + { + _allBus.post(event); + _tagToBus.at(tag)->post(event); + } + + template + void postpone(const std::string& tag, Event event) + { + _allBus.postpone(event); + _tagToBus.at(tag)->postpone(event); + } + + constexpr std::size_t processAll() + { + return processLimit(std::numeric_limits::max()); + } + + constexpr std::size_t processLimit(const std::size_t maxCountOfEvents) + { + return _allBus.processLimit(maxCountOfEvents); + } + + std::shared_ptr>& get(const std::string& tag) + { + return _tagToBus.at(tag); + } + +private: + EventBus_t _allBus; + std::map> _tagToBus; + + constexpr std::uint32_t newListenerID() + { + return internal::ListenerAttorney::newListenerID(_allBus); + } + + template + constexpr void listen(const std::uint32_t listenerID, + std::function callback) + { + internal::ListenerAttorney::template listen( + _allBus, listenerID, std::move(callback)); + } + + constexpr void unlistenAll(const std::uint32_t listenerID) + { + internal::ListenerAttorney::unlistenAll(_allBus, listenerID); + } + + template + constexpr void unlisten(const std::uint32_t listenerID) + { + internal::ListenerAttorney::template unlisten(_allBus, listenerID); + } +}; + +} // namespace dexode::eventbus diff --git a/lib/src/dexode/eventbus/internal/ListenerAttorney.hpp b/lib/src/dexode/eventbus/internal/ListenerAttorney.hpp index 71ab0c8..7a27618 100644 --- a/lib/src/dexode/eventbus/internal/ListenerAttorney.hpp +++ b/lib/src/dexode/eventbus/internal/ListenerAttorney.hpp @@ -9,6 +9,9 @@ namespace dexode::eventbus { template class Listener; + +template +class TagEventBus; } // namespace dexode::eventbus namespace dexode::eventbus::internal @@ -20,6 +23,9 @@ class ListenerAttorney template friend class dexode::eventbus::Listener; + template + friend class eventbus::TagEventBus; + private: static constexpr std::uint32_t newListenerID(EventBus_t& bus) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 64de19c..e0a4959 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(EventBusTest src/EventCollectorTest.cpp src/EventIdTest.cpp src/NotifierTest.cpp + src/TestTagEventBus.cpp ) target_compile_options(EventBusTest PUBLIC diff --git a/test/src/TestTagEventBus.cpp b/test/src/TestTagEventBus.cpp new file mode 100644 index 0000000..0b63c9b --- /dev/null +++ b/test/src/TestTagEventBus.cpp @@ -0,0 +1,67 @@ +// +// Created by gelldur on 30.10.2019. +// +#include + +#include + +#include "dexode/eventbus/TagEventBus.hpp" +#include "dexode/eventbus/strategy/Protected.hpp" + +using TagEventBus = dexode::eventbus::TagEventBus; + +namespace +{ + +struct EventWithMessage +{ + std::string message = "no-msg"; +}; + +} // namespace + +TEST_CASE("Should notify only listeners with specific tag When using TagEventBus", "[TagEventBus]") +{ + TagEventBus bus{{"gui", "backend"}}; + auto listenerGlobal = TagEventBus::ListenerAll::createNotOwning(bus); + + int counterGlobalListener = 0; + int counterTagGUIListener = 0; + int counterTagBackendListener = 0; + + listenerGlobal.listen([&](const EventWithMessage& event) { + INFO("[Global listener] Received: EventWithMessage:" << event.message); + ++counterGlobalListener; + }); + + TagEventBus::Listener guiListener{bus.get("gui")}; + guiListener.listen([&](const EventWithMessage& event) { + INFO("[GUI listener] Received: EventWithMessage:" << event.message); + ++counterTagGUIListener; + }); + + TagEventBus::Listener backendListener{bus.get("backend")}; + backendListener.listen([&](const EventWithMessage& event) { + INFO("[Backend listener] Received: EventWithMessage:" << event.message); + ++counterTagBackendListener; + }); + + { + bus.post(EventWithMessage{"everyone should get this message (global listeners included)"}); + REQUIRE(counterGlobalListener == 1); + REQUIRE(counterTagGUIListener == 1); + REQUIRE(counterTagBackendListener == 1); + } + { + bus.post("gui", EventWithMessage{"gui + global should get this message"}); + REQUIRE(counterGlobalListener == 2); + REQUIRE(counterTagGUIListener == 2); + REQUIRE(counterTagBackendListener == 1); + } + { + bus.post("backend", EventWithMessage{"backend + global should get this message"}); + REQUIRE(counterGlobalListener == 3); + REQUIRE(counterTagGUIListener == 2); + REQUIRE(counterTagBackendListener == 2); + } +}