#pragma once #include #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::map handlers; std::recursive_mutex handlersMutex; std::queue events; std::recursive_mutex eventsMutex; std::queue rawEvents; std::recursive_mutex rawEventsMutex; public: EventListener(); ~EventListener(); void HandleEvent(); void HandleAllEvents(); bool NotEmpty(); void RegisterHandler(size_t eventId, const HandlerType &data); void RegisterHandler(const char *eventId, const HandlerType & data) { RegisterHandler(StrHash(eventId), data); } void PollEvents(); }; class EventSystem { friend class EventListener; static std::list listeners; static std::recursive_mutex listenersMutex; public: template static void PushEvent(size_t eventId, T data) { Event event(eventId, data); std::lock_guard lock(EventSystem::listenersMutex); for (auto& listener : listeners) { std::lock_guard rawEventLock (listener->rawEventsMutex); listener->rawEvents.push(event); } } template static void DirectEventCall(size_t eventId, T data) { Event event(eventId, data); std::lock_guard lock(EventSystem::listenersMutex); for (auto & listener : listeners) { std::lock_guard handlersLock (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) //; LOG(INFO)<<"PUSH_EVENT "<