event.h (4164B)
1 #pragma once 2 3 #include <functional> 4 #include <map> 5 #include <cassert> 6 #include <optional> 7 8 namespace baseLib 9 { 10 template<typename ...Ts> 11 class Event 12 { 13 public: 14 using ListenerId = size_t; 15 using Callback = std::function<void(const Ts&...)>; 16 using MyTuple = std::tuple<std::decay_t<Ts>...>; 17 18 static constexpr ListenerId InvalidListenerId = ~0; 19 20 ListenerId addListener(const Callback& _callback) 21 { 22 ListenerId id; 23 24 if(m_listeners.empty()) 25 { 26 id = 0; 27 } 28 else 29 { 30 id = m_listeners.rbegin()->first + 1; 31 32 // ReSharper disable once CppUseAssociativeContains - wrong, exists in cpp20+ only 33 while(m_listeners.find(id) != m_listeners.end()) 34 ++id; 35 } 36 addListener(id, _callback); 37 return id; 38 } 39 40 void addListener(ListenerId _id, const Callback& _callback) 41 { 42 m_listeners.insert(std::make_pair(_id, _callback)); 43 44 if(m_hasRetainedValue) 45 std::apply(_callback, m_retainedValue); 46 } 47 48 void removeListener(const ListenerId _id) 49 { 50 m_listeners.erase(_id); 51 } 52 53 std::optional<Callback> getListener(const ListenerId _id) const 54 { 55 const auto it = m_listeners.find(_id); 56 if(it != m_listeners.end()) 57 return it->second; 58 return {}; 59 } 60 61 void clear() 62 { 63 m_listeners.clear(); 64 } 65 66 void invoke(const Ts& ..._args) const 67 { 68 for (const auto& it : m_listeners) 69 it.second(_args...); 70 } 71 72 void operator ()(const Ts& ..._args) const 73 { 74 invoke(_args...); 75 } 76 77 void retain(Ts ..._args) 78 { 79 invoke(_args...); 80 m_hasRetainedValue = true; 81 m_retainedValue = MyTuple(_args...); 82 } 83 84 void clearRetained() 85 { 86 m_hasRetainedValue = false; 87 } 88 89 private: 90 std::map<ListenerId, Callback> m_listeners; 91 92 bool m_hasRetainedValue = false; 93 MyTuple m_retainedValue; 94 }; 95 96 template<typename ...Ts> 97 class EventListener 98 { 99 public: 100 using MyEvent = Event<Ts...>; 101 using MyCallback = typename MyEvent::Callback; 102 using MyListenerId = typename MyEvent::ListenerId; 103 104 static constexpr MyListenerId InvalidListenerId = MyEvent::InvalidListenerId; 105 106 EventListener() = default; 107 108 explicit EventListener(MyEvent& _event) : m_event(&_event), m_listenerId(InvalidListenerId) 109 { 110 } 111 112 EventListener(MyEvent& _event, const MyCallback& _callback) : m_event(&_event), m_listenerId(_event.addListener(_callback)) 113 { 114 } 115 116 EventListener(EventListener&& _listener) noexcept : m_event(_listener.m_event), m_listenerId(_listener.m_listenerId) 117 { 118 _listener.m_listenerId = InvalidListenerId; 119 } 120 121 EventListener(const EventListener&) = delete; 122 EventListener& operator = (const EventListener&) = delete; 123 124 EventListener& operator = (EventListener&& _source) noexcept 125 { 126 if(&_source == this) 127 return *this; 128 129 removeListener(); 130 131 m_event = _source.m_event; 132 m_listenerId = _source.m_listenerId; 133 134 _source.m_listenerId = InvalidListenerId; 135 136 return *this; 137 } 138 139 ~EventListener() 140 { 141 removeListener(); 142 } 143 144 void set(const MyCallback& _func) 145 { 146 removeListener(); 147 assert(m_event); 148 if(m_event) 149 m_listenerId = m_event->addListener(_func); 150 } 151 152 void set(MyEvent& _event, const MyCallback& _func) 153 { 154 removeListener(); 155 m_event = &_event; 156 m_listenerId = _event.addListener(_func); 157 } 158 159 void set(MyEvent& _event) 160 { 161 if(&_event == m_event) 162 return; 163 164 if(isBound()) 165 { 166 if(auto callback = m_event->getListener(m_listenerId)) 167 { 168 m_event->removeListener(m_listenerId); 169 m_listenerId = _event.addListener(*callback); 170 } 171 else 172 { 173 removeListener(); 174 } 175 } 176 177 m_event = &_event; 178 } 179 180 bool isBound() const { return m_listenerId != InvalidListenerId; } 181 bool isValid() const { return m_event != nullptr; } 182 183 EventListener& operator = (const MyCallback& _callback) 184 { 185 set(_callback); 186 return *this; 187 } 188 189 EventListener& operator = (MyEvent& _event) noexcept 190 { 191 set(_event); 192 return *this; 193 } 194 195 void reset() 196 { 197 removeListener(); 198 } 199 200 private: 201 void removeListener() 202 { 203 if(m_listenerId == InvalidListenerId) 204 return; 205 206 m_event->removeListener(m_listenerId); 207 m_listenerId = InvalidListenerId; 208 } 209 210 MyEvent* m_event = nullptr; 211 MyListenerId m_listenerId = InvalidListenerId; 212 }; 213 }