Skip to content

Instantly share code, notes, and snippets.

@DanilAndreev
Last active October 5, 2021 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DanilAndreev/99ad6d1e27fc7e9def279ed78a46a97c to your computer and use it in GitHub Desktop.
Save DanilAndreev/99ad6d1e27fc7e9def279ed78a46a97c to your computer and use it in GitHub Desktop.
C++ basic event system example
#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
#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