Last active
October 5, 2021 14:51
-
-
Save DanilAndreev/99ad6d1e27fc7e9def279ed78a46a97c to your computer and use it in GitHub Desktop.
C++ basic event system example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef EVENT_EMITTER_HPP | |
#define EVENT_EMITTER_HPP | |
#include <string> | |
#include <map> | |
#include <unordered_set> | |
namespace events { | |
class event_emitter; | |
/** | |
* event_base - base abstract class for events. | |
* Has propagation setting and abstract copy method. | |
* @class | |
*/ | |
class event_base { | |
friend event_emitter; | |
private: | |
/// _propagation_stopped - it true, event will stop propagation after last handler. | |
bool _propagation_stopped; | |
public: | |
event_base() noexcept { | |
_propagation_stopped = false; | |
} | |
virtual ~event_base() noexcept = default; | |
public: | |
/** | |
* Stops event propagation. | |
* Next handlers in chain won't be executed. | |
*/ | |
void stop_propagation() noexcept { | |
this->_propagation_stopped = true; | |
} | |
[[nodiscard]] virtual event_base *copy() const noexcept = 0; | |
}; | |
/** | |
* event_emitter - class for dispatching events over the handlers. | |
* @class | |
*/ | |
class event_emitter { | |
public: | |
/// EventHandler - event handler function prototype. | |
typedef void(*EventHandler)(event_base &); | |
private: | |
/// subscribers - event subscribers. Sorted by event names. | |
std::map<std::string, std::unordered_set<EventHandler>> subscribers; | |
public: | |
event_emitter() = default; | |
~event_emitter() = default; | |
public: | |
/** | |
* emit - emits new event and propagates it over the handlers. | |
* @param eventName - Event name string. | |
* @param event - Event object. Each handler can modify it while handling. | |
*/ | |
void emit_event(const std::string &eventName, const event_base &event) { | |
auto eventSubscribers = this->subscribers.find(eventName); | |
if (eventSubscribers == this->subscribers.end()) return; | |
event_base *eventCopy = event.copy(); | |
for (EventHandler handler : eventSubscribers->second) { | |
if (event._propagation_stopped) break; | |
handler(*eventCopy); | |
} | |
delete eventCopy; | |
} | |
/** | |
* add_listener - binds handler function to event. | |
* @param eventName - Event name string. | |
* @param handler - Handler function pointer. | |
*/ | |
void add_listener(const std::string &eventName, EventHandler handler) { | |
auto iterator = this->subscribers.find(eventName); | |
if (iterator == this->subscribers.end()) { | |
std::unordered_set<EventHandler> handlers; | |
handlers.insert(handler); | |
this->subscribers.insert(std::make_pair(eventName, handlers)); | |
} else { | |
iterator->second.insert(handler); | |
} | |
} | |
/** | |
* remove_listener - unbinds handler function from the event. | |
* @param eventName - Event name string. | |
* @param handler - Handler function pointer. | |
*/ | |
void remove_listener(const std::string &eventName, EventHandler handler) { | |
std::unordered_set<EventHandler> &eventSubscribers = this->subscribers[eventName]; | |
eventSubscribers.extract(handler); | |
} | |
}; | |
} | |
#endif //EVENT_EMITTER_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "event_emitter.hpp" | |
class event : public events::event_base { | |
public: | |
event() = default; | |
~event() = default; | |
public: | |
[[nodiscard]] event *copy() const noexcept override { | |
return new event(*this); | |
} | |
}; | |
using namespace std; | |
void handler1(events::event_base &event) { | |
cout << "handler1" << endl; | |
} | |
void handler2(events::event_base &event) { | |
cout << "handler2" << endl; | |
} | |
void handler3(events::event_base &event) { | |
event.stopPropagation(); | |
cout << "handler3" << endl; | |
} | |
int main() { | |
events::event_emitter emitter; | |
emitter.add_listener("event1", handler1); | |
emitter.add_listener("event1", handler3); | |
emitter.add_listener("event2", handler2); | |
emitter.add_listener("event2", handler1); | |
emitter.emit_event("event1", event{}); | |
emitter.emit_event("event3", event{}); | |
cout << "Removed" << endl; | |
emitter.remove_listener("event1", handler3); | |
emitter.remove_listener("event2", handler1); | |
emitter.emit_event("event1", event{}); | |
emitter.emit_event("event2", event{}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment