Files
XCEngine/editor/src/Core/EventBus.h

113 lines
2.9 KiB
C++

#pragma once
#include <functional>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <atomic>
#include <mutex>
#include <shared_mutex>
namespace XCEngine {
namespace Editor {
class EventTypeRegistry {
public:
static uint32_t NextId() {
return s_nextId.fetch_add(1, std::memory_order_relaxed);
}
private:
inline static std::atomic<uint32_t> s_nextId{0};
};
template<typename T>
struct EventTypeId {
static uint32_t Get() {
static const uint32_t id = EventTypeRegistry::NextId();
return id;
}
};
class EventBus {
public:
using EventHandler = std::function<void()>;
template<typename T>
uint64_t Subscribe(std::function<void(const T&)> handler) {
static_assert(sizeof(T) > 0, "Event type must be defined");
uint32_t typeId = EventTypeId<T>::Get();
uint64_t handlerId = 0;
{
std::lock_guard<std::shared_mutex> lock(m_mutex);
handlerId = m_nextHandlerId++;
auto it = m_handlers.find(typeId);
if (it == m_handlers.end()) {
m_handlers[typeId] = std::vector<HandlerEntry>();
}
HandlerEntry entry;
entry.id = handlerId;
entry.handler = [handler](const void* data) {
handler(*static_cast<const T*>(data));
};
m_handlers[typeId].push_back(entry);
}
return handlerId;
}
template<typename T>
void Unsubscribe(uint64_t handlerId) {
static_assert(sizeof(T) > 0, "Event type must be defined");
uint32_t typeId = EventTypeId<T>::Get();
std::lock_guard<std::shared_mutex> lock(m_mutex);
auto it = m_handlers.find(typeId);
if (it != m_handlers.end()) {
auto& handlers = it->second;
handlers.erase(
std::remove_if(handlers.begin(), handlers.end(),
[handlerId](const HandlerEntry& entry) { return entry.id == handlerId; }),
handlers.end()
);
}
}
template<typename T>
void Publish(const T& event) {
static_assert(sizeof(T) > 0, "Event type must be defined");
uint32_t typeId = EventTypeId<T>::Get();
std::shared_lock<std::shared_mutex> lock(m_mutex);
auto it = m_handlers.find(typeId);
if (it != m_handlers.end()) {
for (const auto& entry : it->second) {
entry.handler(&event);
}
}
}
void Clear() {
std::lock_guard<std::shared_mutex> lock(m_mutex);
m_handlers.clear();
}
private:
struct HandlerEntry {
uint64_t id;
std::function<void(const void*)> handler;
};
std::unordered_map<uint32_t, std::vector<HandlerEntry>> m_handlers;
uint64_t m_nextHandlerId = 0;
std::shared_mutex m_mutex;
};
}
}