Added Event Broker

This commit is contained in:
sippeangelo
2015-11-24 10:37:21 +01:00
parent 059dee76ed
commit 0a1f0d96db
5 changed files with 277 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
#ifndef Event_h__
#define Event_h__
struct Event
{
protected:
Event() { }
};
#endif
+136
View File
@@ -0,0 +1,136 @@
#ifndef EventBroker_h__
#define EventBroker_h__
#include <typeinfo>
#include <functional>
#include <map>
#include <unordered_map>
#include <list>
#include <tuple>
#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> event) = 0;
protected:
std::string m_ContextTypeName;
std::string m_EventTypeName;
EventBroker* m_Broker;
};
template <typename ContextType, typename EventType>
class EventRelay : public BaseEventRelay
{
public:
typedef std::function<bool(const EventType&)> 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> event) override;
private:
CallbackType m_Callback;
};
template <typename ContextType, typename EventType>
bool EventRelay<ContextType, EventType>::Receive(const std::shared_ptr<Event> event)
{
if (m_Callback != nullptr) {
return m_Callback(*static_cast<const EventType*>(event.get()));
} else {
return false;
}
}
class EventBroker
{
template <typename ContextType, typename EventType> friend class EventRelay;
public:
EventBroker()
{
m_EventQueueRead = std::make_shared<EventQueue_t>();
m_EventQueueWrite = std::make_shared<EventQueue_t>();
}
void Subscribe(BaseEventRelay &relay);
template <typename EventType>
void Publish(const EventType &event);
/*
Process all events in a given context.
Returns: Number of events processed
*/
template <typename ContextType>
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<EventTypeName_t, BaseEventRelay*> EventRelays_t;
typedef std::unordered_map<ContextTypeName_t, EventRelays_t> ContextRelays_t;
ContextRelays_t m_ContextRelays;
std::vector<BaseEventRelay*> m_RelaysToSubscribe;
std::vector<BaseEventRelay*> m_RelaysToUnsubscribe;
typedef std::list<std::pair<EventTypeName_t, std::shared_ptr<Event>>> EventQueue_t;
std::shared_ptr<EventQueue_t> m_EventQueueRead;
std::shared_ptr<EventQueue_t> m_EventQueueWrite;
void subscribeImmediate(BaseEventRelay& relay);
void unsubscribeImmediate(BaseEventRelay& relay);
};
template <typename EventType>
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<EventType>(new EventType(event))));
}
template <typename ContextType>
int EventBroker::Process()
{
const std::string contextTypeName = typeid(ContextType).name();
return Process(contextTypeName);
}
#endif
+26
View File
@@ -0,0 +1,26 @@
#include <memory>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
// OpenGL
#include <GL/glew.h>
#define GLFW_INCLUDE_GLU
#define NOMINMAX
#include <GLFW/glfw3.h>
#include <glext.h>
#include "Core/Util/GLError.h"
// GLM
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/common.hpp>
#include <glm/gtc/constants.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "Core/Util/Logging.h"
+104
View File
@@ -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> 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;
}
}
}
+1
View File
@@ -0,0 +1 @@
#include "PrecompiledHeader.h"