129 lines
3.6 KiB
C++
129 lines
3.6 KiB
C++
#ifndef EVENT_H
|
|
#define EVENT_H
|
|
#include <functional>
|
|
#include <cstdint>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
class EventListener;
|
|
|
|
class BaseEvent {
|
|
public:
|
|
BaseEvent() = default;
|
|
virtual ~BaseEvent() = default;
|
|
|
|
virtual void RemoveListener(EventListener* listener) = 0;
|
|
};
|
|
|
|
class EventListener {
|
|
template <typename... EventArgs>
|
|
friend class Event;
|
|
|
|
public:
|
|
virtual ~EventListener() {
|
|
for (auto* event: m_Events)
|
|
event->RemoveListener(this);
|
|
}
|
|
|
|
EventListener(EventListener&&) = delete;
|
|
EventListener(const EventListener&) = delete;
|
|
EventListener& operator=(EventListener&&) = delete;
|
|
EventListener& operator=(const EventListener&) = delete;
|
|
|
|
protected:
|
|
EventListener() = default;
|
|
|
|
private:
|
|
void AddEvent(BaseEvent* event) { m_Events.insert(event); }
|
|
|
|
void RemoveEvent(BaseEvent* event) { m_Events.erase(event); }
|
|
|
|
std::unordered_set<BaseEvent*> m_Events{};
|
|
};
|
|
|
|
template <typename... EventArgs>
|
|
class Event final: public BaseEvent {
|
|
struct EventFunction {
|
|
void* listener{nullptr};
|
|
std::uint64_t id{0};
|
|
std::function<void(EventArgs...)> callback;
|
|
};
|
|
|
|
public:
|
|
Event() = default;
|
|
|
|
~Event() override {
|
|
for (auto* eventListener: m_EventListeners)
|
|
eventListener->RemoveEvent(this);
|
|
}
|
|
|
|
Event(Event&&) = delete;
|
|
Event(const Event&) = delete;
|
|
Event& operator=(Event&&) = delete;
|
|
Event& operator=(const Event&) = delete;
|
|
|
|
|
|
//This is to allow any member function of a EventListener to be bound as a event callback
|
|
template <typename ObjectType>
|
|
requires std::derived_from<ObjectType, EventListener>
|
|
void AddListener(ObjectType* object, void (ObjectType::*memberFunction)(EventArgs...)) {
|
|
auto* listener = static_cast<EventListener*>(object);
|
|
listener->AddEvent(this);
|
|
m_EventListeners.insert(listener);
|
|
|
|
const auto id = m_NextBindingId++;
|
|
m_ActiveBindings.insert(id);
|
|
m_FunctionBinds.push_back({
|
|
listener,
|
|
id,
|
|
[object, memberFunction] (EventArgs... args) { (object->*memberFunction)(args...); }
|
|
});
|
|
}
|
|
|
|
template <typename Function>
|
|
void AddListener(Function function) {
|
|
const auto id = m_NextBindingId++;
|
|
m_ActiveBindings.insert(id);
|
|
m_FunctionBinds.push_back({
|
|
nullptr,
|
|
id,
|
|
[function] (EventArgs... args) { function(args...); }
|
|
});
|
|
}
|
|
|
|
template <typename... Args>
|
|
void Invoke(Args&&... args) {
|
|
// Callbacks are allowed to unregister themselves or register another
|
|
// callback. Iterate over a snapshot so those mutations cannot
|
|
// invalidate this invocation.
|
|
const auto listeners = m_FunctionBinds;
|
|
for (const auto& listenerFunction: listeners) {
|
|
if (m_ActiveBindings.contains(listenerFunction.id)) {
|
|
listenerFunction.callback(args...);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RemoveListener(EventListener* listener) override {
|
|
m_EventListeners.erase(listener);
|
|
|
|
for (auto it = m_FunctionBinds.begin(); it != m_FunctionBinds.end();) {
|
|
if (it->listener == static_cast<void*>(listener)) {
|
|
m_ActiveBindings.erase(it->id);
|
|
it = m_FunctionBinds.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::vector<EventFunction> m_FunctionBinds{};
|
|
std::unordered_set<EventListener*> m_EventListeners{};
|
|
std::unordered_set<std::uint64_t> m_ActiveBindings{};
|
|
std::uint64_t m_NextBindingId{1};
|
|
};
|
|
|
|
|
|
#endif //EVENT_H
|