/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include "Base/UUID.hpp" #include #include #include #include #include #include #include #include namespace OpenVulkano { class IEventHandler { public: virtual ~IEventHandler() = default; virtual void SetInvalid() = 0; }; class INamedEventProcessor { static std::vector processors; public: // Keep this in sync with all implementations! synctag: NamedEventProcessor_Parameters_SYNC_TAG typedef std::variant Parameters; static bool HasProcessor() { return !processors.empty(); } static void NotifyAll(const std::string& eventName, const std::vector& parameters) { for(const auto& processor : processors) { processor->Notify(eventName, parameters); } } INamedEventProcessor() { processors.push_back(this); } virtual ~INamedEventProcessor() { processors.erase(std::remove_if(processors.begin(), processors.end(), [this](auto v) { return v==this; }), processors.end()); } virtual void Notify(const std::string& eventName, const std::vector& parameters) const = 0; }; template class Event final { public: typedef std::function Function; private: enum class EventHandlerType { STATIC, INSTANCED, INSTANCED_SHARED_PTR, INSTANCED_WEAK_PTR, FUNCTIONAL, NAMED }; //region Event Handlers class EventHandler : public IEventHandler { const EventHandlerType type; bool invalid; protected: EventHandler(EventHandlerType type) : type(type), invalid(false) {} virtual bool ShouldDelete(EventHandler* other) const = 0; public: virtual ~EventHandler() = default; bool ShouldBeDelete(EventHandler* other) const { if (other == this) return true; if (invalid) return true; if (!other || other->type != type) return false; return ShouldDelete(other); } virtual void Notify(Arguments... args) const = 0; [[nodiscard]] bool IsInvalid() const { return invalid; } void SetInvalid() final { invalid = true; } }; class StaticEventHandler final : public EventHandler { public: typedef void (*Method)(Arguments...); StaticEventHandler(Method method) : EventHandler(EventHandlerType::STATIC), method(method) {} void Notify(Arguments... args) const override { method(args...); } protected: bool ShouldDelete(EventHandler* other) const override { return static_cast(other)->method == this->method; } private: Method method; }; template class InstancedEventHandler final : public EventHandler { public: InstancedEventHandler(Instance* instance, Method method) : EventHandler(EventHandlerType::INSTANCED), instance(instance), method(method) {} void Notify(Arguments... args) const override { (instance->*method)(args...); } protected: bool ShouldDelete(EventHandler* other) const override { InstancedEventHandler* otherHandler = static_cast(other); return otherHandler->instance == instance && otherHandler->method == this->method; } private: Instance* instance; Method method; }; template class InstancedSharedPtrEventHandler final : public EventHandler { public: InstancedSharedPtrEventHandler(std::shared_ptr instance, Method method) : EventHandler(EventHandlerType::INSTANCED_SHARED_PTR), instance(instance), method(method) {} void Notify(Arguments... args) const override { (instance.get()->*method)(args...); } protected: bool ShouldDelete(EventHandler* other) const override { InstancedSharedPtrEventHandler* otherHandler = static_cast(other); return otherHandler->instance == instance && otherHandler->method == this->method; } private: std::shared_ptr instance; Method method; }; template class InstancedWeakPtrEventHandler final : public EventHandler { public: InstancedWeakPtrEventHandler(std::weak_ptr instance, Method method) : EventHandler(EventHandlerType::INSTANCED_WEAK_PTR), instance(instance), method(method) {} void Notify(Arguments... args) const override { if (auto instancePtr = instance.lock()) { (instancePtr.get()->*method)(args...); } else { const_cast(this)->SetInvalid(); } } protected: bool ShouldDelete(EventHandler* other) const override { InstancedWeakPtrEventHandler* otherHandler = static_cast(other); if (otherHandler->method == this->method) { if (auto ptr = instance.lock()) { return ptr == otherHandler->instance.lock(); } return true; } return false; } private: std::weak_ptr instance; Method method; }; class FunctionalEventHandler final : public EventHandler { public: FunctionalEventHandler(Function function) : EventHandler(EventHandlerType::FUNCTIONAL), function(function) {} void Notify(Arguments... args) const override { function(args...); } protected: bool ShouldDelete(EventHandler* other) const override { return false; } private: Function function; }; class NamedEventHandler final : public EventHandler { std::string m_name; public: NamedEventHandler(const std::string& name) : EventHandler(EventHandlerType::NAMED), m_name(name) {} void Notify(Arguments... args) const override { NotifyImpl(std::forward(args)...); } void NotifyImpl(Arguments... args) const { if (INamedEventProcessor::HasProcessor()) { std::vector attributes; attributes.reserve(sizeof...(Arguments)); if constexpr (!std::disjunction_v>...>) { // Express if no enum class is contained in the arguments (attributes.emplace_back(args), ...); } else { auto fill = [&](auto&& arg) { if constexpr (std::is_enum_v>) attributes.emplace_back(static_cast(arg)); else attributes.emplace_back(std::forward(arg)); }; (fill(std::forward(args)), ...); } INamedEventProcessor::NotifyAll(m_name, attributes); } } protected: bool ShouldDelete(EventHandler* other) const override { return false; } }; //endregion std::vector> handlers; mutable std::shared_mutex mutex; void Remove(EventHandler* referenceHandler) { std::unique_lock lock(mutex); for(size_t i = 0; i < handlers.size(); i++) { EventHandler* handler = handlers[i].get(); if (handler->ShouldBeDelete(referenceHandler)) { size_t end = handlers.size() - 1; if (i < end) { handlers[i] = std::move(handlers[end]); } handlers.pop_back(); } } } IEventHandler* Add(EventHandler* handler) { std::unique_lock lock(mutex); handlers.emplace_back(handler); return handler; } public: Event() = default; Event(const std::string& name) { RegisterName(name); } Event(const Event& event) = delete; Event(Event&& event) = default; [[nodiscard]] bool HasHandlers() const { return !handlers.empty(); } void NotifyAll(Arguments... args) const { std::shared_lock lock(mutex); for(auto& handler : handlers) { if (!handler->IsInvalid()) handler->Notify(args...); } } void operator()(Arguments... args) const { NotifyAll(args...); } IEventHandler* RegisterName(const std::string& name) { return Add(new NamedEventHandler(name)); } template IEventHandler* RegisterHandler(Instance* instance, Method method) { return Add(new InstancedEventHandler(instance, method)); } template void UnregisterHandler(Instance* instance, Method method) { auto handler = InstancedEventHandler(instance, method); Remove(&handler); } template IEventHandler* operator +=(std::pair instancedMethodPair) { return RegisterHandler(instancedMethodPair.first, instancedMethodPair.second); } template void operator -=(std::pair instancedMethodPair) { UnregisterHandler(instancedMethodPair.first, instancedMethodPair.second); } template IEventHandler* RegisterHandler(const std::shared_ptr& instance, Method method) { return Add(new InstancedSharedPtrEventHandler(instance, method)); } template void UnregisterHandler(const std::shared_ptr& instance, Method method) { auto handler = InstancedSharedPtrEventHandler(instance, method); Remove(&handler); } template IEventHandler* operator +=(std::pair, Method> instancedMethodPair) { return RegisterHandler(instancedMethodPair.first, instancedMethodPair.second); } template void operator -=(std::pair, Method> instancedMethodPair) { UnregisterHandler(instancedMethodPair.first, instancedMethodPair.second); } template IEventHandler* RegisterHandler(const std::weak_ptr& instance, Method method) { return Add(new InstancedWeakPtrEventHandler(instance, method)); } template void UnregisterHandler(const std::weak_ptr& instance, Method method) { auto handler = InstancedWeakPtrEventHandler(instance, method); Remove(&handler); } template IEventHandler* RegisterHandlerWeak(const std::weak_ptr& instance, Method method) { return Add(new InstancedWeakPtrEventHandler(instance, method)); } template void UnregisterHandlerWeak(const std::weak_ptr& instance, Method method) { auto handler = InstancedWeakPtrEventHandler(instance, method); Remove(&handler); } template IEventHandler* operator +=(std::pair, Method> instancedMethodPair) { return RegisterHandlerWeak(instancedMethodPair.first, instancedMethodPair.second); } template void operator -=(std::pair, Method> instancedMethodPair) { UnregisterHandlerWeak(instancedMethodPair.first, instancedMethodPair.second); } IEventHandler* RegisterHandler(void (*method)(Arguments...)) { return Add(new StaticEventHandler(method)); } void UnregisterHandler(void (*method)(Arguments...)) { auto handler = StaticEventHandler(method); Remove(&handler); } IEventHandler* operator +=(void (*method)(Arguments...)) { return RegisterHandler(method); } void operator -=(void (*method)(Arguments...)) { UnregisterHandler(method); } IEventHandler* RegisterHandler(Function function) { return Add(new FunctionalEventHandler(function)); } void UnregisterHandler(EventHandler* handler) { Remove(handler); } IEventHandler* operator +=(Function function) { return RegisterHandler(function); } void operator -=(IEventHandler* handler) { if (EventHandler* handlerRef = dynamic_cast(handler)) { Remove(handlerRef); } } }; template constexpr std::pair EventHandler(Instance* instance, Method method) { return std::pair(instance, method); } template constexpr std::pair, Method> EventHandler(const std::shared_ptr& instance, Method method) { return std::pair, Method>(instance, method); } template constexpr std::pair, Method> EventHandler(const std::weak_ptr& instance, Method method) { return std::pair, Method>(instance, method); } template constexpr std::pair, Method> EventHandlerWeak(const std::weak_ptr& instance, Method method) { return std::pair, Method>(instance, method); } class EventHandle { std::weak_ptr m_owner; IEventHandler* m_handler; public: EventHandle() : m_handler(nullptr) {} EventHandle(const std::weak_ptr& owner, IEventHandler* handler) : m_owner(owner), m_handler(handler) {} EventHandle(const EventHandle& other) = delete; EventHandle(EventHandle&& other) noexcept : m_owner(other.m_owner), m_handler(other.m_handler) { other.m_owner.reset(); other.m_handler = nullptr; } template EventHandle (const std::shared_ptr& owner, Event EVENT_OWNER_T::* event, HANDLER_T&& handler) : m_owner(owner), m_handler((owner.get()->*event).operator+=(handler)) {} ~EventHandle() { if (m_handler) Close(); } void Close() { if (!m_handler) return; if (auto acquired = m_owner.lock()) { m_handler->SetInvalid(); } m_handler = nullptr; m_owner.reset(); } EventHandle& operator =(const EventHandle& other) = delete; EventHandle& operator =(EventHandle&& other) noexcept { Close(); m_owner.swap(other.m_owner); std::swap(m_handler, other.m_handler); return *this; } operator bool() const noexcept { return m_handler; } }; }