diff --git a/openVulkanoCpp/Base/Event.hpp b/openVulkanoCpp/Base/Event.hpp new file mode 100644 index 0000000..722e16d --- /dev/null +++ b/openVulkanoCpp/Base/Event.hpp @@ -0,0 +1,362 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace openVulkanoCpp +{ + template + class Event final + { + public: + typedef std::function Function; + + private: + enum class EventHandlerType { STATIC, INSTANCED, INSTANCED_SHARED_PTR, INSTANCED_WEAK_PTR, FUNCTIONAL }; + + class EventHandler + { + const EventHandlerType type; + protected: + EventHandler(EventHandlerType type) : type(type) {} + virtual bool ShouldDelete(EventHandler* other) const = 0; + + public: + virtual ~EventHandler() = default; + + bool ShouldBeDelete(EventHandler* other) const + { + if (other == this) return true; + if (!other || other->type != type) return false; + return ShouldDelete(other); + } + + virtual void Notify(Arguments... args) const = 0; + }; + + 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...); + } + } + + 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; + }; + + 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]; + if (handler->ShouldBeDelete(referenceHandler)) + { + size_t end = handlers.size() - 1; + if (i < end) + { + handlers[i] = handlers[end]; + } + delete handler; + handlers.pop_back(); + } + } + } + + void Add(EventHandler* handler) + { + std::unique_lock lock(mutex); + handlers.push_back(handler); + } + + public: + void NotifyAll(Arguments... args) const + { + std::shared_lock lock(mutex); + for(EventHandler* handler : handlers) + { + handler->Notify(args...); + } + } + + void operator()(Arguments... args) + { + NotifyAll(args); + } + + template + void RegisterHandler(Instance* instance, Method method) + { + Add(new InstancedEventHandler(instance, method)); + } + + template + void UnregisterHandler(Instance* instance, Method method) + { + auto handler = InstancedEventHandler(instance, method); + Remove(&handler); + } + + template + void operator +=(std::pair instancedMethodPair) + { + RegisterHandler(instancedMethodPair.first, instancedMethodPair.second); + } + + template + void operator -=(std::pair instancedMethodPair) + { + UnregisterHandler(instancedMethodPair.first, instancedMethodPair.second); + } + + template + void RegisterHandler(std::shared_ptr instance, Method method) + { + Add(new InstancedSharedPtrEventHandler(instance, method)); + } + + template + void UnregisterHandler(std::shared_ptr instance, Method method) + { + auto handler = InstancedSharedPtrEventHandler(instance, method); + Remove(&handler); + } + + template + void operator +=(std::pair, Method> instancedMethodPair) + { + RegisterHandler(instancedMethodPair.first, instancedMethodPair.second); + } + + template + void operator -=(std::pair, Method> instancedMethodPair) + { + UnregisterHandler(instancedMethodPair.first, instancedMethodPair.second); + } + + template + void RegisterHandler(std::weak_ptr instance, Method method) + { + Add(new InstancedWeakPtrEventHandler(instance, method)); + } + + template + void UnregisterHandler(std::weak_ptr instance, Method method) + { + auto handler = InstancedWeakPtrEventHandler(instance, method); + Remove(&handler); + } + + template + void RegisterHandlerWeak(std::weak_ptr instance, Method method) + { + Add(new InstancedWeakPtrEventHandler(instance, method)); + } + + template + void UnregisterHandlerWeak(std::weak_ptr instance, Method method) + { + auto handler = InstancedWeakPtrEventHandler(instance, method); + Remove(&handler); + } + + template + void operator +=(std::pair, Method> instancedMethodPair) + { + RegisterHandlerWeak(instancedMethodPair.first, instancedMethodPair.second); + } + + template + void operator -=(std::pair, Method> instancedMethodPair) + { + RegisterHandlerWeak(instancedMethodPair.first, instancedMethodPair.second); + } + + void RegisterHandler(void (*method)(Arguments...)) + { + handlers.push_back(new StaticEventHandler(method)); + } + + void UnregisterHandler(void (*method)(Arguments...)) + { + auto handler = StaticEventHandler(method); + Remove(&handler); + } + + void operator +=(void (*method)(Arguments...)) + { + RegisterHandler(method); + } + + void operator -=(void (*method)(Arguments...)) + { + UnregisterHandler(method); + } + + EventHandler* RegisterHandler(Function function) + { + FunctionalEventHandler* handler = new FunctionalEventHandler(function); + Add(handler); + return handler; + } + + void UnregisterHandler(EventHandler* handler) + { + Remove(handler); + } + + EventHandler* operator +=(Function function) + { + return RegisterHandler(function); + } + + void operator -=(EventHandler* handler) + { + Remove(handler); + } + }; + + template + constexpr std::pair EventHandler(Instance* instance, Method method) + { + return std::pair(instance, method); + } + + template + constexpr std::pair, Method> EventHandler(std::shared_ptr instance, Method method) + { + return std::pair, Method>(instance, method); + } + + template + constexpr std::pair, Method> EventHandler(std::weak_ptr instance, Method method) + { + return std::pair, Method>(instance, method); + } + + template + constexpr std::pair, Method> EventHandlerWeak(std::weak_ptr instance, Method method) + { + return std::pair, Method>(instance, method); + } +} \ No newline at end of file diff --git a/openVulkanoCpp/openVulkanoCpp.vcxproj b/openVulkanoCpp/openVulkanoCpp.vcxproj index efda132..2299cf0 100644 --- a/openVulkanoCpp/openVulkanoCpp.vcxproj +++ b/openVulkanoCpp/openVulkanoCpp.vcxproj @@ -105,6 +105,7 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\" +