From fa32e7a9f46c7da39a527d0ebc049e3720068d8e Mon Sep 17 00:00:00 2001 From: LaG1924 <12997935+LaG1924@users.noreply.github.com> Date: Fri, 29 Dec 2017 17:09:51 +0500 Subject: Implemented new event system --- src/Event.cpp | 49 ++++++++++++++++++++++ src/Event.hpp | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/src/Event.cpp b/src/Event.cpp index 00f67c0..c857947 100644 --- a/src/Event.cpp +++ b/src/Event.cpp @@ -1 +1,50 @@ #include "Event.hpp" + +std::list EventSystem::listeners; +std::mutex EventSystem::listenersMutex; + +EventListener::EventListener() { + std::lock_guard listenersLock(EventSystem::listenersMutex); + EventSystem::listeners.push_back(this); +} + +EventListener::~EventListener() { + std::lock_guard listenersLock(EventSystem::listenersMutex); + EventSystem::listeners.remove(this); +} + +void EventListener::HandleEvent() { + std::lock_guard lock(eventsQueueMutex); + std::lock_guard lockHandlers(handlersMutex); + Event event = events.front(); + events.pop(); + if (handlers[event.id]) { + handlers[event.id](event); + } +} + +void EventListener::HandleAllEvents() { + std::lock_guard lock(eventsQueueMutex); + std::lock_guard lockHandlers(handlersMutex); + while (!events.empty()) { + Event event = events.front(); + events.pop(); + if (handlers[event.id]) { + handlers[event.id](event); + } + } +} + +bool EventListener::NotEmpty() { + std::lock_guard lock(eventsQueueMutex); + return !events.empty(); +} + +void EventListener::WaitEvent() { + eventsQueueMutex.lock(); + while (events.empty()) { + eventsQueueMutex.unlock(); + eventsQueueMutex.lock(); + } + eventsQueueMutex.unlock(); +} \ No newline at end of file diff --git a/src/Event.hpp b/src/Event.hpp index 3f59c93..752fda4 100644 --- a/src/Event.hpp +++ b/src/Event.hpp @@ -1,2 +1,132 @@ #pragma once +#include +#include +#include +#include +#include +#include +#include + + +size_t constexpr StrHash(char const *input) { + return *input ? static_cast(*input) + 33 * StrHash(input + 1) : 5381; +} + +class Event { + struct EventDataBase { + virtual ~EventDataBase() {} + virtual const std::type_info& Type() const = 0; + }; + + template + struct EventData : EventDataBase { + EventData(const T &val) : data(val) {} + + const std::type_info& Type() const override { + return typeid(data); + } + + T data; + }; + + std::shared_ptr data; + +public: + const size_t id; + + template + Event(size_t eventId, const T &value) : + id(eventId), + data(std::make_shared>(value)) {} + + ~Event() = default; + + Event(const Event &other) = default; + + Event &operator=(const Event &) = default; + + Event(Event &&) = delete; + + Event &operator=(Event &&) = delete; + + template + const T& get() const { + if (typeid(T) != data->Type()) + throw std::runtime_error(std::string("Type ") + typeid(T).name() + " encountered but " + data->Type().name() + " expected"); + return static_cast*>(data.get())->data; + } +}; + +class EventListener { + friend class EventSystem; + using HandlerType = std::function; + std::queue events; + std::map handlers; + std::mutex eventsQueueMutex; + std::mutex handlersMutex; +public: + EventListener(); + + ~EventListener(); + + void HandleEvent(); + + void HandleAllEvents(); + + bool NotEmpty(); + + void WaitEvent(); + + void RegisterHandler(size_t eventId, const HandlerType &data) { + std::lock_guard lock(handlersMutex); + handlers[eventId] = data; + } + + void RegisterHandler(const char *eventId, const HandlerType & data) { + RegisterHandler(StrHash(eventId), data); + } +}; + +class EventSystem { + friend class EventListener; + static std::list listeners; + static std::mutex listenersMutex; + +public: + template + static void PushEvent(size_t eventId, T data) { + Event event(eventId, data); + + std::lock_guard listenersLock(listenersMutex); + for (auto& listener : listeners) { + std::lock_guard lock(listener->eventsQueueMutex); + std::lock_guard lockHandlers(listener->handlersMutex); + auto it = listener->handlers.find(eventId); + if (it == listener->handlers.end()) + continue; + + listener->events.push(event); + } + } + + template + static void DirectEventCall(size_t eventId, T data) { + Event event(eventId, data); + + std::lock_guard listenersLock(listenersMutex); + for (auto & listener : listeners) { + std::lock_guard lock(listener->eventsQueueMutex); + std::lock_guard lockHandlers(listener->handlersMutex); + auto it = listener->handlers.find(eventId); + if (it == listener->handlers.end()) + continue; + + it->second(event); + } + } +}; + +#define PUSH_EVENT(eventName, data) EventSystem::PushEvent(StrHash(eventName),data) + +#define DIRECT_EVENT_CALL(eventName,data) EventSystem::DirectEventCall(StrHash(eventName),data) \ No newline at end of file -- cgit v1.2.3