feat: event.hpp
This commit is contained in:
71
include/window/event.hpp
Normal file
71
include/window/event.hpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef EVENT_H_
|
||||||
|
#define EVENT_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
class EventBus {
|
||||||
|
using Type = std::type_index;
|
||||||
|
using RawFn = std::function<void(const void*)>;
|
||||||
|
|
||||||
|
struct Slot { std::size_t id; RawFn fn; };
|
||||||
|
|
||||||
|
std::unordered_map<Type, std::vector<Slot>> subs_;
|
||||||
|
std::size_t next_id_ = 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Handle {
|
||||||
|
std::type_index type{typeid(void)};
|
||||||
|
std::size_t id{0};
|
||||||
|
explicit operator bool() const { return id != 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class E, class F>
|
||||||
|
Handle subscribe(F&& f) {
|
||||||
|
auto& vec = subs_[Type(typeid(E))];
|
||||||
|
Handle h{ Type(typeid(E)), next_id_++ };
|
||||||
|
// Wrap strongly typed callback into type-erased RawFn
|
||||||
|
RawFn wrapper = [fn = std::function<void(const E&)>(std::forward<F>(f))](const void* p){
|
||||||
|
fn(*static_cast<const E*>(p));
|
||||||
|
};
|
||||||
|
vec.push_back(Slot{h.id, std::move(wrapper)});
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsubscribe with handle
|
||||||
|
void unsubscribe(const Handle& h) {
|
||||||
|
auto it = subs_.find(h.type);
|
||||||
|
if (it == subs_.end()) return;
|
||||||
|
auto& vec = it->second;
|
||||||
|
vec.erase(std::remove_if(vec.begin(), vec.end(),
|
||||||
|
[&](const Slot& s){ return s.id == h.id; }),
|
||||||
|
vec.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish immediately
|
||||||
|
template<class E>
|
||||||
|
void publish(const E& e) const {
|
||||||
|
auto it = subs_.find(Type(typeid(E)));
|
||||||
|
if (it == subs_.end()) return;
|
||||||
|
for (auto& slot : it->second) slot.fn(&e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Optional RAII helper
|
||||||
|
struct ScopedSub {
|
||||||
|
EventBus* bus{};
|
||||||
|
EventBus::Handle h{};
|
||||||
|
ScopedSub() = default;
|
||||||
|
ScopedSub(EventBus& b, EventBus::Handle hh) : bus(&b), h(hh) {}
|
||||||
|
ScopedSub(ScopedSub&& o) noexcept { *this = std::move(o); }
|
||||||
|
ScopedSub& operator=(ScopedSub&& o) noexcept {
|
||||||
|
if (this != &o) { reset(); bus = o.bus; h = o.h; o.bus = nullptr; }
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
~ScopedSub(){ reset(); }
|
||||||
|
void reset(){ if (bus && h) bus->unsubscribe(h); bus=nullptr; h={}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EVENT_H_
|
Reference in New Issue
Block a user