From 0a1f0d96db6482ddbdfce00e923211803060ca4f Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 24 Nov 2015 10:37:21 +0100 Subject: [PATCH] Added Event Broker --- include/Engine/Core/Event.h | 10 +++ include/Engine/Core/EventBroker.h | 136 +++++++++++++++++++++++++++++ include/Engine/PrecompiledHeader.h | 26 ++++++ src/Engine/Core/EventBroker.cpp | 104 ++++++++++++++++++++++ src/Engine/PrecompiledHeader.cpp | 1 + 5 files changed, 277 insertions(+) create mode 100644 include/Engine/Core/Event.h create mode 100644 include/Engine/Core/EventBroker.h create mode 100644 include/Engine/PrecompiledHeader.h create mode 100644 src/Engine/Core/EventBroker.cpp create mode 100644 src/Engine/PrecompiledHeader.cpp diff --git a/include/Engine/Core/Event.h b/include/Engine/Core/Event.h new file mode 100644 index 00000000..65adb3a9 --- /dev/null +++ b/include/Engine/Core/Event.h @@ -0,0 +1,10 @@ +#ifndef Event_h__ +#define Event_h__ + +struct Event +{ +protected: + Event() { } +}; + +#endif diff --git a/include/Engine/Core/EventBroker.h b/include/Engine/Core/EventBroker.h new file mode 100644 index 00000000..3144ed85 --- /dev/null +++ b/include/Engine/Core/EventBroker.h @@ -0,0 +1,136 @@ +#ifndef EventBroker_h__ +#define EventBroker_h__ + +#include +#include +#include +#include +#include +#include + +#include "Event.h" + +#define EVENT_SUBSCRIBE_MEMBER(relay, handler) \ + relay = decltype(relay)(std::bind(handler, this, std::placeholders::_1)); \ + EventBroker->Subscribe(relay); + +class EventBroker; + +class BaseEventRelay +{ +friend class EventBroker; + +protected: + BaseEventRelay(std::string contextTypeName, std::string eventTypeName) + : m_ContextTypeName(contextTypeName) + , m_EventTypeName(eventTypeName) + , m_Broker(nullptr) + { } + ~BaseEventRelay(); + +public: + virtual bool Receive(const std::shared_ptr event) = 0; + +protected: + std::string m_ContextTypeName; + std::string m_EventTypeName; + EventBroker* m_Broker; +}; + +template +class EventRelay : public BaseEventRelay +{ +public: + typedef std::function CallbackType; + + EventRelay() + : m_Callback(nullptr) + , BaseEventRelay(typeid(ContextType).name(), typeid(EventType).name()) + { } + EventRelay(CallbackType callback) + : m_Callback(callback) + , BaseEventRelay(typeid(ContextType).name(), typeid(EventType).name()) + { } + +protected: + bool Receive(const std::shared_ptr event) override; + +private: + CallbackType m_Callback; +}; + +template +bool EventRelay::Receive(const std::shared_ptr event) +{ + if (m_Callback != nullptr) { + return m_Callback(*static_cast(event.get())); + } else { + return false; + } +} + +class EventBroker +{ +template friend class EventRelay; + +public: + EventBroker() + { + m_EventQueueRead = std::make_shared(); + m_EventQueueWrite = std::make_shared(); + } + + void Subscribe(BaseEventRelay &relay); + template + void Publish(const EventType &event); + /* + Process all events in a given context. + Returns: Number of events processed + */ + template + int Process(); + int Process(std::string contextTypeName); + void Swap(); + void Clear(); + void Unsubscribe(BaseEventRelay &relay); + +private: + bool m_IsProcessing = false; + + typedef std::string ContextTypeName_t; // typeid(ContextType).name() + typedef std::string EventTypeName_t; // typeid(EventType).name() + + typedef std::unordered_multimap EventRelays_t; + typedef std::unordered_map ContextRelays_t; + ContextRelays_t m_ContextRelays; + std::vector m_RelaysToSubscribe; + std::vector m_RelaysToUnsubscribe; + + typedef std::list>> EventQueue_t; + std::shared_ptr m_EventQueueRead; + std::shared_ptr m_EventQueueWrite; + + void subscribeImmediate(BaseEventRelay& relay); + void unsubscribeImmediate(BaseEventRelay& relay); +}; + +template +void EventBroker::Publish(const EventType &event) +{ + /*auto itpair = m_Subscribers.equal_range(typeid(EventType).name()); + for (auto it = itpair.first; it != itpair.second; ++it) + { + it->second->Receive(event); + }*/ + + m_EventQueueWrite->push_back(std::make_pair(typeid(EventType).name(), std::shared_ptr(new EventType(event)))); +} + +template +int EventBroker::Process() +{ + const std::string contextTypeName = typeid(ContextType).name(); + return Process(contextTypeName); +} + +#endif diff --git a/include/Engine/PrecompiledHeader.h b/include/Engine/PrecompiledHeader.h new file mode 100644 index 00000000..0ac917d2 --- /dev/null +++ b/include/Engine/PrecompiledHeader.h @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +// OpenGL +#include +#define GLFW_INCLUDE_GLU +#define NOMINMAX +#include +#include +#include "Core/Util/GLError.h" + +// GLM +#define GLM_FORCE_RADIANS +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Core/Util/Logging.h" diff --git a/src/Engine/Core/EventBroker.cpp b/src/Engine/Core/EventBroker.cpp new file mode 100644 index 00000000..a1c253dd --- /dev/null +++ b/src/Engine/Core/EventBroker.cpp @@ -0,0 +1,104 @@ +#include "PrecompiledHeader.h" +#include "Core/EventBroker.h" + +BaseEventRelay::~BaseEventRelay() +{ + if (m_Broker != nullptr) { + m_Broker->Unsubscribe(*this); + } +} + +void EventBroker::Unsubscribe(BaseEventRelay &relay) // ? +{ + if (m_IsProcessing) { + m_RelaysToUnsubscribe.push_back(&relay); + } else { + unsubscribeImmediate(relay); + } +} + +void EventBroker::Subscribe(BaseEventRelay &relay) +{ + if (m_IsProcessing) { + m_RelaysToSubscribe.push_back(&relay); + } else { + subscribeImmediate(relay); + } +} + +int EventBroker::Process(std::string contextTypeName) +{ + m_IsProcessing = true; + + auto it = m_ContextRelays.find(contextTypeName); + if (it == m_ContextRelays.end()) { + return 0; + } + + EventRelays_t &relays = it->second; + + int eventsProcessed = 0; + for (auto &pair : *m_EventQueueRead) { + std::string &eventTypeName = pair.first; + std::shared_ptr event = pair.second; + + auto itpair = relays.equal_range(eventTypeName); + for (auto it2 = itpair.first; it2 != itpair.second; it2++) + { + std::string name = it2->first; + BaseEventRelay* relay = it2->second; + relay->Receive(event); + eventsProcessed++; + } + } + + m_IsProcessing = false; + + // Process pending subscriptions + for (auto& r : m_RelaysToSubscribe) { + subscribeImmediate(*r); + } + m_RelaysToSubscribe.clear(); + + // Process pending unsubscriptions + for (auto& r : m_RelaysToUnsubscribe) { + unsubscribeImmediate(*r); + } + m_RelaysToUnsubscribe.clear(); + + return eventsProcessed; +} + +void EventBroker::Swap() +{ + std::swap(m_EventQueueRead, m_EventQueueWrite); +} + +void EventBroker::Clear() +{ + m_EventQueueWrite->clear(); +} + +void EventBroker::subscribeImmediate(BaseEventRelay& relay) +{ + relay.m_Broker = this; + m_ContextRelays[relay.m_ContextTypeName].insert(std::make_pair(relay.m_EventTypeName, &relay)); +} + +void EventBroker::unsubscribeImmediate(BaseEventRelay& relay) +{ + auto contextIt = m_ContextRelays.find(relay.m_ContextTypeName); + if (contextIt == m_ContextRelays.end()) { + return; + } + + auto eventRelays = contextIt->second; + auto itpair = eventRelays.equal_range(relay.m_EventTypeName); + for (auto it = itpair.first; it != itpair.second; ++it) { + if (it->second == &relay) { + relay.m_Broker = nullptr; + eventRelays.erase(it); + break; + } + } +} diff --git a/src/Engine/PrecompiledHeader.cpp b/src/Engine/PrecompiledHeader.cpp new file mode 100644 index 00000000..6d8a5001 --- /dev/null +++ b/src/Engine/PrecompiledHeader.cpp @@ -0,0 +1 @@ +#include "PrecompiledHeader.h"