1 // Copyright Louis Dionne 2013-2017
2 // Distributed under the Boost Software License, Version 1.0.
3
4 #include <boost/hana/assert.hpp>
5 #include <boost/hana/at_key.hpp>
6 #include <boost/hana/contains.hpp>
7 #include <boost/hana/map.hpp>
8 #include <boost/hana/pair.hpp>
9 #include <boost/hana/string.hpp>
10
11 #include <functional>
12 #include <string>
13 #include <vector>
14 namespace hana = boost::hana;
15
16
17 template <typename ...Events>
18 struct event_system {
19 using Callback = std::function<void()>;
20 hana::map<hana::pair<Events, std::vector<Callback>>...> map_;
21
22 template <typename Event, typename F>
onevent_system23 void on(Event e, F handler) {
24 auto is_known_event = hana::contains(map_, e);
25 static_assert(is_known_event,
26 "trying to add a handler to an unknown event");
27
28 map_[e].push_back(handler);
29 }
30
31 template <typename Event>
triggerevent_system32 void trigger(Event e) const {
33 auto is_known_event = hana::contains(map_, e);
34 static_assert(is_known_event,
35 "trying to trigger an unknown event");
36
37 for (auto& handler : this->map_[e])
38 handler();
39 }
40 };
41
42 template <typename ...Events>
make_event_system(Events...events)43 event_system<Events...> make_event_system(Events ...events) {
44 return {};
45 }
46
47
main()48 int main() {
49 auto events = make_event_system(
50 BOOST_HANA_STRING("foo"),
51 BOOST_HANA_STRING("bar"),
52 BOOST_HANA_STRING("baz")
53 );
54
55 std::vector<std::string> triggered_events;
56 events.on(BOOST_HANA_STRING("foo"), [&] {
57 triggered_events.push_back("foo:1");
58 });
59 events.on(BOOST_HANA_STRING("foo"), [&] {
60 triggered_events.push_back("foo:2");
61 });
62 events.on(BOOST_HANA_STRING("bar"), [&] {
63 triggered_events.push_back("bar:1");
64 });
65 events.on(BOOST_HANA_STRING("baz"), [&] {
66 triggered_events.push_back("baz:1");
67 });
68
69 events.trigger(BOOST_HANA_STRING("foo"));
70 events.trigger(BOOST_HANA_STRING("bar"));
71 events.trigger(BOOST_HANA_STRING("baz"));
72
73 BOOST_HANA_RUNTIME_CHECK(triggered_events == std::vector<std::string>{
74 "foo:1", "foo:2", "bar:1", "baz:1"
75 });
76 }
77