Add TagEventBus

This commit is contained in:
Dawid Drozd 2019-10-30 17:44:52 +01:00
parent 890eaff178
commit 2bb9c3e679
5 changed files with 196 additions and 0 deletions

View File

@ -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)

View File

@ -0,0 +1,121 @@
//
// Created by gelldur on 30.10.2019.
//
#pragma once
#include <map>
#include <memory>
#include <string>
#include "dexode/EventBus.hpp"
namespace dexode::eventbus
{
template <class Strategy>
class TagEventBus
{
template <typename>
friend class dexode::eventbus::internal::ListenerAttorney;
using EventBus_t = EventBus<Strategy>;
public:
using ListenerAll = eventbus::Listener<TagEventBus<Strategy>>;
using Listener = typename EventBus<Strategy>::Listener; // alias
TagEventBus(const std::vector<std::string>& tags)
{
for(const auto& tag : tags)
{
_tagToBus.emplace(tag, std::make_shared<EventBus_t>());
}
}
~TagEventBus() = default;
TagEventBus(const TagEventBus&) = delete;
TagEventBus(TagEventBus&&) = delete;
TagEventBus& operator=(TagEventBus&&) = delete;
TagEventBus& operator=(const TagEventBus&) = delete;
template <typename Event>
void post(const Event& event)
{
_allBus.post(event);
for(auto& element : _tagToBus)
{
element.second->post(event);
}
}
template <typename Event>
void postpone(Event event)
{
_allBus.postpone(event);
for(auto& element : _tagToBus)
{
element.second->postpone(event);
}
}
template <typename Event>
void post(const std::string& tag, const Event& event)
{
_allBus.post(event);
_tagToBus.at(tag)->post(event);
}
template <typename Event>
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<std::size_t>::max());
}
constexpr std::size_t processLimit(const std::size_t maxCountOfEvents)
{
return _allBus.processLimit(maxCountOfEvents);
}
std::shared_ptr<EventBus<Strategy>>& get(const std::string& tag)
{
return _tagToBus.at(tag);
}
private:
EventBus_t _allBus;
std::map<std::string, std::shared_ptr<EventBus_t>> _tagToBus;
constexpr std::uint32_t newListenerID()
{
return internal::ListenerAttorney<EventBus_t>::newListenerID(_allBus);
}
template <class Event>
constexpr void listen(const std::uint32_t listenerID,
std::function<void(const Event&)> callback)
{
internal::ListenerAttorney<EventBus_t>::template listen<Event>(
_allBus, listenerID, std::move(callback));
}
constexpr void unlistenAll(const std::uint32_t listenerID)
{
internal::ListenerAttorney<EventBus_t>::unlistenAll(_allBus, listenerID);
}
template <typename Event>
constexpr void unlisten(const std::uint32_t listenerID)
{
internal::ListenerAttorney<EventBus_t>::template unlisten<Event>(_allBus, listenerID);
}
};
} // namespace dexode::eventbus

View File

@ -9,6 +9,9 @@ namespace dexode::eventbus
{
template <typename>
class Listener;
template <typename>
class TagEventBus;
} // namespace dexode::eventbus
namespace dexode::eventbus::internal
@ -20,6 +23,9 @@ class ListenerAttorney
template <typename>
friend class dexode::eventbus::Listener;
template <typename>
friend class eventbus::TagEventBus;
private:
static constexpr std::uint32_t newListenerID(EventBus_t& bus)
{

View File

@ -20,6 +20,7 @@ add_executable(EventBusTest
src/EventCollectorTest.cpp
src/EventIdTest.cpp
src/NotifierTest.cpp
src/TestTagEventBus.cpp
)
target_compile_options(EventBusTest PUBLIC

View File

@ -0,0 +1,67 @@
//
// Created by gelldur on 30.10.2019.
//
#include <string>
#include <catch2/catch.hpp>
#include "dexode/eventbus/TagEventBus.hpp"
#include "dexode/eventbus/strategy/Protected.hpp"
using TagEventBus = dexode::eventbus::TagEventBus<dexode::eventbus::strategy::Protected>;
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<EventWithMessage>([&](const EventWithMessage& event) {
INFO("[Global listener] Received: EventWithMessage:" << event.message);
++counterGlobalListener;
});
TagEventBus::Listener guiListener{bus.get("gui")};
guiListener.listen<EventWithMessage>([&](const EventWithMessage& event) {
INFO("[GUI listener] Received: EventWithMessage:" << event.message);
++counterTagGUIListener;
});
TagEventBus::Listener backendListener{bus.get("backend")};
backendListener.listen<EventWithMessage>([&](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);
}
}