#pragma once #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); } }