488 lines
13 KiB
C++
488 lines
13 KiB
C++
/*
|
|
* 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 <algorithm>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <shared_mutex>
|
|
#include <string>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
namespace OpenVulkano
|
|
{
|
|
class IEventHandler
|
|
{
|
|
public:
|
|
virtual ~IEventHandler() = default;
|
|
virtual void SetInvalid() = 0;
|
|
};
|
|
|
|
class INamedEventProcessor
|
|
{
|
|
static std::vector<INamedEventProcessor*> processors;
|
|
|
|
public:
|
|
// Keep this in sync with all implementations! synctag: NamedEventProcessor_Parameters_SYNC_TAG
|
|
typedef std::variant<std::string, bool, int, float, double, UUID> Parameters;
|
|
|
|
static bool HasProcessor() { return !processors.empty(); }
|
|
|
|
static void NotifyAll(const std::string& eventName, const std::vector<Parameters>& 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>& parameters) const = 0;
|
|
};
|
|
|
|
template<typename... Arguments>
|
|
class Event final
|
|
{
|
|
public:
|
|
typedef std::function<void(Arguments...)> 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<StaticEventHandler*>(other)->method == this->method;
|
|
}
|
|
|
|
private:
|
|
Method method;
|
|
};
|
|
|
|
template<class Instance, class Method>
|
|
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<InstancedEventHandler*>(other);
|
|
return otherHandler->instance == instance && otherHandler->method == this->method;
|
|
}
|
|
|
|
private:
|
|
Instance* instance;
|
|
Method method;
|
|
};
|
|
|
|
template<class Instance, class Method>
|
|
class InstancedSharedPtrEventHandler final : public EventHandler
|
|
{
|
|
public:
|
|
InstancedSharedPtrEventHandler(std::shared_ptr<Instance> 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<InstancedSharedPtrEventHandler*>(other);
|
|
return otherHandler->instance == instance && otherHandler->method == this->method;
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<Instance> instance;
|
|
Method method;
|
|
};
|
|
|
|
template<class Instance, class Method>
|
|
class InstancedWeakPtrEventHandler final : public EventHandler
|
|
{
|
|
public:
|
|
InstancedWeakPtrEventHandler(std::weak_ptr<Instance> 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<InstancedWeakPtrEventHandler*>(this)->SetInvalid();
|
|
}
|
|
}
|
|
|
|
protected:
|
|
bool ShouldDelete(EventHandler* other) const override
|
|
{
|
|
InstancedWeakPtrEventHandler* otherHandler = static_cast<InstancedWeakPtrEventHandler*>(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> 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<Arguments>(args)...);
|
|
}
|
|
|
|
void NotifyImpl(Arguments... args) const
|
|
{
|
|
if (INamedEventProcessor::HasProcessor())
|
|
{
|
|
std::vector<INamedEventProcessor::Parameters> attributes;
|
|
attributes.reserve(sizeof...(Arguments));
|
|
if constexpr (!std::conjunction_v<std::is_enum<std::remove_reference_t<Arguments>>...>)
|
|
{
|
|
(attributes.emplace_back(args), ...);
|
|
}
|
|
else
|
|
{
|
|
auto fill = [&](auto&& arg) {
|
|
if constexpr (std::is_enum_v<std::remove_reference_t<decltype(arg)>>)
|
|
attributes.emplace_back(static_cast<int>(arg));
|
|
else
|
|
attributes.emplace_back(std::forward<decltype(arg)>(arg));
|
|
};
|
|
(fill(std::forward<Arguments>(args)), ...);
|
|
}
|
|
INamedEventProcessor::NotifyAll(m_name, attributes);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
bool ShouldDelete(EventHandler* other) const override
|
|
{
|
|
return false;
|
|
}
|
|
};
|
|
//endregion
|
|
|
|
std::vector<std::unique_ptr<EventHandler>> handlers;
|
|
mutable std::shared_mutex mutex;
|
|
|
|
void Remove(EventHandler* referenceHandler)
|
|
{
|
|
std::unique_lock<std::shared_mutex> 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<std::shared_mutex> 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<std::shared_mutex> 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<class Instance, class Method>
|
|
IEventHandler* RegisterHandler(Instance* instance, Method method)
|
|
{
|
|
return Add(new InstancedEventHandler<Instance, Method>(instance, method));
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
void UnregisterHandler(Instance* instance, Method method)
|
|
{
|
|
auto handler = InstancedEventHandler<Instance, Method>(instance, method);
|
|
Remove(&handler);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
IEventHandler* operator +=(std::pair<Instance*, Method> instancedMethodPair)
|
|
{
|
|
return RegisterHandler(instancedMethodPair.first, instancedMethodPair.second);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
void operator -=(std::pair<Instance*, Method> instancedMethodPair)
|
|
{
|
|
UnregisterHandler(instancedMethodPair.first, instancedMethodPair.second);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
IEventHandler* RegisterHandler(const std::shared_ptr<Instance>& instance, Method method)
|
|
{
|
|
return Add(new InstancedSharedPtrEventHandler<Instance, Method>(instance, method));
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
void UnregisterHandler(const std::shared_ptr<Instance>& instance, Method method)
|
|
{
|
|
auto handler = InstancedSharedPtrEventHandler<Instance, Method>(instance, method);
|
|
Remove(&handler);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
IEventHandler* operator +=(std::pair<std::shared_ptr<Instance>, Method> instancedMethodPair)
|
|
{
|
|
return RegisterHandler(instancedMethodPair.first, instancedMethodPair.second);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
void operator -=(std::pair<std::shared_ptr<Instance>, Method> instancedMethodPair)
|
|
{
|
|
UnregisterHandler(instancedMethodPair.first, instancedMethodPair.second);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
IEventHandler* RegisterHandler(const std::weak_ptr<Instance>& instance, Method method)
|
|
{
|
|
return Add(new InstancedWeakPtrEventHandler<Instance, Method>(instance, method));
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
void UnregisterHandler(const std::weak_ptr<Instance>& instance, Method method)
|
|
{
|
|
auto handler = InstancedWeakPtrEventHandler<Instance, Method>(instance, method);
|
|
Remove(&handler);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
IEventHandler* RegisterHandlerWeak(const std::weak_ptr<Instance>& instance, Method method)
|
|
{
|
|
return Add(new InstancedWeakPtrEventHandler<Instance, Method>(instance, method));
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
void UnregisterHandlerWeak(const std::weak_ptr<Instance>& instance, Method method)
|
|
{
|
|
auto handler = InstancedWeakPtrEventHandler<Instance, Method>(instance, method);
|
|
Remove(&handler);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
IEventHandler* operator +=(std::pair<std::weak_ptr<Instance>, Method> instancedMethodPair)
|
|
{
|
|
return RegisterHandlerWeak(instancedMethodPair.first, instancedMethodPair.second);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
void operator -=(std::pair<std::weak_ptr<Instance>, 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<EventHandler*>(handler))
|
|
{
|
|
Remove(handlerRef);
|
|
}
|
|
}
|
|
};
|
|
|
|
template<class Instance, class Method>
|
|
constexpr std::pair<Instance*, Method> EventHandler(Instance* instance, Method method)
|
|
{
|
|
return std::pair<Instance*, Method>(instance, method);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
constexpr std::pair<std::shared_ptr<Instance>, Method> EventHandler(const std::shared_ptr<Instance>& instance, Method method)
|
|
{
|
|
return std::pair<std::shared_ptr<Instance>, Method>(instance, method);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
constexpr std::pair<std::weak_ptr<Instance>, Method> EventHandler(const std::weak_ptr<Instance>& instance, Method method)
|
|
{
|
|
return std::pair<std::weak_ptr<Instance>, Method>(instance, method);
|
|
}
|
|
|
|
template<class Instance, class Method>
|
|
constexpr std::pair<std::weak_ptr<Instance>, Method> EventHandlerWeak(const std::weak_ptr<Instance>& instance, Method method)
|
|
{
|
|
return std::pair<std::weak_ptr<Instance>, Method>(instance, method);
|
|
}
|
|
}
|