113 lines
2.9 KiB
C++
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;
|
|
};
|
|
|
|
}
|
|
}
|