X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgame%2Feventbus.h;fp=source%2Fgame%2Feventbus.h;h=ce9c812e20b1593cbbe6489b537d4ad201f1f52f;hb=6a93721ab67315e916f6c649b1f7bc5447d611a4;hp=0000000000000000000000000000000000000000;hpb=b644c89c81d89f60a0d82fe208fc76ce1c278a4c;p=libs%2Fgame.git diff --git a/source/game/eventbus.h b/source/game/eventbus.h new file mode 100644 index 0000000..ce9c812 --- /dev/null +++ b/source/game/eventbus.h @@ -0,0 +1,113 @@ +#ifndef MSP_GAME_EVENTBUS_H_ +#define MSP_GAME_EVENTBUS_H_ + +#include +#include + +namespace Msp::Game { + +class EventObserver; + +template +struct EventDispatcher +{ + struct Handler + { + EventObserver *observer; + std::function callback; + }; + + std::vector handlers; + + void add_observer(EventObserver *obs, std::function &&cb) + { handlers.emplace_back(obs, std::move(cb)); } + + void remove_observer(EventObserver *obs) + { std::erase_if(handlers, [obs](const Handler &h){ return h.observer==obs; }); } + + void dispatch(const T &) const; +}; + + +class EventBus +{ +private: + using DeleteFunc = void(void *); + using RemoveFunc = void(void *, EventObserver &); + + struct Dispatcher + { + void *dispatcher = nullptr; + DeleteFunc *deleter = nullptr; + RemoveFunc *remover = nullptr; + }; + + std::vector dispatchers; + + static unsigned get_next_id(); + +public: + template + static unsigned get_event_id(); + +private: + template + EventDispatcher &get_emitter(); + +public: + template + void add_observer(EventObserver &obs, std::function cb) + { get_emitter().add_observer(obs, std::move(cb)); } + + void replace_observer(EventObserver &, EventObserver &); + void remove_observer(EventObserver &); + + template + void dispatch(const T &) const; +}; + + +template +void EventDispatcher::dispatch(const T &event) const +{ + for(const Handler &h: handlers) + h.callback(event); +} + + +template +inline unsigned EventBus::get_event_id() +{ + static unsigned id = get_next_id(); + return id; +} + +template +inline EventDispatcher &EventBus::get_emitter() +{ + unsigned id = get_event_id(); + if(dispatchers.size()<=id) + dispatchers.resize(id+1); + + Dispatcher &event = dispatchers[id]; + if(!event.dispatcher) + { + event.dispatcher = new EventDispatcher; + event.deleter = [](void *p){ delete static_cast *>(p); }; + event.remover = [](void *p, EventObserver &o){ static_cast *>(p)->remove_observer(o); }; + } + + return static_cast *>(event.dispatcher); +} + +template +inline void EventBus::dispatch(const T &event) const +{ + unsigned id = get_event_id(); + if(id *>(dispatchers[id].dispatcher)->dispatch(event); +} + +} // namespace Msp::Game + +#endif