Created
February 5, 2019 12:59
-
-
Save Fiona-J-W/9d0da283feeda4a84a4281e61e6fb486 to your computer and use it in GitHub Desktop.
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 <algorithm> | |
#include <functional> | |
#include <iostream> | |
#include <iterator> | |
#include <string> | |
#include <unordered_map> | |
#include <vector> | |
template <typename KeyType, KeyType Key, typename Listener> | |
struct event_t { | |
using self = event_t<KeyType, Key, Listener>; | |
using listener_type = std::function<Listener>; | |
listener_type listener; | |
}; | |
// Get's the Key of an event_t | |
template <typename T> | |
struct get_key_t {}; | |
template <typename KeyType, KeyType Key, typename Listeners> | |
struct get_key_t<event_t<KeyType, Key, Listeners>> { | |
static const auto value = Key; | |
}; | |
template <typename T> | |
const auto get_key = get_key_t<T>::value; | |
// Selects the event_t that has Key as key | |
template <typename KeyType, KeyType Key, typename Head, typename... Tail> | |
struct select_event_type_t { | |
static_assert(sizeof...(Tail) > 0u, "No such Event"); | |
using type = typename select_event_type_t<KeyType, Key, Tail...>::type; | |
}; | |
template <typename KeyType, KeyType Key, typename Fun, typename... Tail> | |
struct select_event_type_t<KeyType, Key, event_t<KeyType, Key, Fun>, Tail...> { | |
using type = event_t<KeyType, Key, Fun>; | |
}; | |
template <typename KeyType, KeyType Key, typename... Events> | |
using select_event_type = typename select_event_type_t<KeyType, Key, Events...>::type; | |
// The actual listener | |
template <typename KeyType, typename... Events> | |
class event_listener { | |
private: | |
template <KeyType Event> | |
struct storage { | |
using event_type = select_event_type<KeyType, Event, Events...>; | |
using listener_type = typename event_type::listener_type; | |
std::unordered_map<unsigned, listener_type> listeners; | |
}; | |
template <KeyType Event> | |
auto& get_listeners() { | |
return std::get<storage<Event>>(m_events).listeners; | |
} | |
template <KeyType Event> | |
const auto& get_listeners() const { | |
return std::get<storage<Event>>(m_events).listeners; | |
} | |
public: | |
template <KeyType Event> | |
unsigned subscribe(typename storage<Event>::listener_type listener) { | |
const auto listener_id = m_next_id++; | |
get_listeners<Event>().insert({listener_id, std::move(listener)}); | |
return listener_id; | |
} | |
template <KeyType Event, typename... Args> | |
void execute(const Args&... args) const { | |
for (const auto& [id, listener] : get_listeners<Event>()) { | |
std::invoke(listener, args...); | |
} | |
} | |
template <KeyType Event> | |
void unsubscribe(unsigned id) { | |
get_listeners<Event>().erase(id); | |
} | |
private: | |
std::tuple<storage<get_key<Events>>...> m_events; | |
unsigned m_next_id = 0u; | |
}; | |
/////////////////////////////////////////////////////// | |
// Usage: | |
enum class event_types { foo, bar, baz, unused }; | |
template <event_types E, typename Listener> | |
using event = event_t<event_types, E, Listener>; | |
int main() { | |
auto el = event_listener<event_types, event<event_types::foo, void(int)>, | |
event<event_types::bar, void()>, | |
event<event_types::baz, void(int, double)>>{}; | |
el.subscribe<event_types::foo>([](int i) { std::cout << "foo(" << i << ")\n"; }); | |
el.subscribe<event_types::bar>([] { std::cout << "bar1()\n"; }); | |
const auto id_bar2 = el.subscribe<event_types::bar>([] { std::cout << "bar2()\n"; }); | |
el.execute<event_types::foo>(23); | |
el.execute<event_types::bar>(); | |
el.execute<event_types::baz>(23, 42.0); | |
std::cout << '\n'; | |
el.subscribe<event_types::baz>( | |
[](double d, int i) { std::cout << "baz(" << d << ", " << i << ")\n"; }); | |
el.execute<event_types::foo>(23); | |
el.execute<event_types::bar>(); | |
el.execute<event_types::baz>(23, 42.0); | |
std::cout << '\n'; | |
el.unsubscribe<event_types::bar>(id_bar2); | |
el.execute<event_types::foo>(23); | |
el.execute<event_types::bar>(); | |
el.execute<event_types::baz>(23, 42.0); | |
std::cout << '\n'; | |
el.subscribe<event_types::bar>([]() { std::cout << "unused\n"; }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment