MxEngine
EventDispatcher.h
1 // Copyright(c) 2019 - 2020, #Momo
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met :
6 //
7 // 1. Redistributions of source code must retain the above copyright notice, this
8 // list of conditions and the following disclaimer.
9 //
10 // 2. Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and /or other materials provided with the distribution.
13 //
14 // 3. Neither the name of the copyright holder nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #pragma once
30 
31 #include <memory>
32 #include <functional>
33 #include <unordered_set>
34 #include <typeindex>
35 #include <map>
36 #include <algorithm>
37 
38 #include "Utilities/Profiler/Profiler.h"
39 #include "Utilities/Memory/Memory.h"
40 #include "Utilities/String/String.h" // is used in macro, so analyzer may say it is unused, but its not
41 #include "Utilities/STL/MxVector.h"
42 
43 namespace MxEngine
44 {
45  /*
46  creates base event class and adds GetEventType() pure virtual method. Used for EventDispatcher class
47  */
48  #define MAKE_EVENT_BASE(name) struct name { inline virtual uint32_t GetEventType() const = 0; virtual ~name() = default; }
49 
50  /*
51  inserted into class body of derived classes from base event. Using compile-time hash from class name to generate type id
52  */
53  #define MAKE_EVENT(class_name) \
54  template<typename T> friend class EventDispatcher;\
55  public: inline virtual uint32_t GetEventType() const override { return eventType; } private:\
56  constexpr static uint32_t eventType = STRING_ID(#class_name)
57 
62  template<typename EventBase>
64  {
65  using CallbackBaseFunction = std::function<void(EventBase&)>;
66  using NamedCallback = std::pair<MxString, CallbackBaseFunction>;
67  using CallbackList = MxVector<NamedCallback>;
68  using EventList = MxVector<UniqueRef<EventBase>>;
69  using EventTypeIndex = uint32_t;
70 
74  EventList events;
78  std::unordered_map<EventTypeIndex, CallbackList> callbacks;
83  std::unordered_map<EventTypeIndex, CallbackList> toAddCache;
88  MxVector<MxString> toRemoveCache;
89 
94  inline void ProcessEvent(EventBase& event)
95  {
96  auto& eventCallbacks = this->callbacks[event.GetEventType()];
97  for (const auto& [name, callback] : eventCallbacks)
98  {
99  if (std::find(this->toRemoveCache.begin(), this->toRemoveCache.end(), name) == this->toRemoveCache.end())
100  {
101  callback(event);
102  }
103  }
104  }
105 
111  template<typename EventType>
112  inline void AddCallbackImpl(MxString name, CallbackBaseFunction&& func)
113  {
114  this->toAddCache[EventType::eventType].emplace_back(std::move(name), std::move(func));
115  }
116 
122  inline void RemoveEventByName(CallbackList& callbacks, const MxString& name)
123  {
124  auto it = std::remove_if(callbacks.begin(), callbacks.end(), [&name](const auto& p)
125  {
126  return p.first == name;
127  });
128  callbacks.erase(it, callbacks.end());
129  }
130  public:
134  inline void FlushEvents()
135  {
136  for (auto it = this->toRemoveCache.begin(); it != this->toRemoveCache.end(); it++)
137  {
138  for (auto& [event, callbacks] : this->callbacks)
139  {
140  RemoveEventByName(callbacks, *it);
141  }
142  }
143  this->toRemoveCache.clear();
144 
145  for (auto it = this->toAddCache.begin(); it != this->toAddCache.end(); it++)
146  {
147  auto& [event, funcs] = *it;
148  for (auto& func : funcs)
149  {
150  callbacks[event].push_back(std::move(func));
151  }
152  }
153  for (auto& list : this->toAddCache) list.second.clear();
154  }
155 
162  template<typename EventType>
163  void AddEventListener(const MxString& name, std::function<void(EventType&)> func)
164  {
165  this->template AddCallbackImpl<EventType>(name, [func = std::move(func)](EventBase& e)
166  {
167  if (e.GetEventType() == EventType::eventType)
168  func(static_cast<EventType&>(e));
169  });
170  }
171 
178  template<typename FunctionType>
179  void AddEventListener(const MxString& name, FunctionType&& func)
180  {
181  this->AddEventListener(name, std::function(std::forward<FunctionType>(func)));
182  }
183 
188  void RemoveEventListener(const MxString& name)
189  {
190  this->toRemoveCache.push_back(name);
191 
192  for (auto& [event, callbacks] : this->toAddCache)
193  {
194  RemoveEventByName(callbacks, name);
195  }
196  }
197 
202  template<typename Event>
203  void Invoke(Event& event)
204  {
205  this->FlushEvents();
206  this->ProcessEvent(event);
207  }
208 
213  void AddEvent(UniqueRef<EventBase> event)
214  {
215  this->events.push_back(std::move(event));
216  }
217 
221  void InvokeAll()
222  {
223  this->FlushEvents();
224 
225  for (size_t i = 0; i < this->events.size(); i++)
226  {
227  MAKE_SCOPE_PROFILER(typeid(*this->events[i]).name());
228  this->ProcessEvent(*this->events[i]);
229  }
230  this->events.clear();
231  }
232  };
233 }
void FlushEvents()
Definition: EventDispatcher.h:134
void AddEventListener(const MxString &name, std::function< void(EventType &)> func)
Definition: EventDispatcher.h:163
void AddEventListener(const MxString &name, FunctionType &&func)
Definition: EventDispatcher.h:179
void InvokeAll()
Definition: EventDispatcher.h:221
void Invoke(Event &event)
Definition: EventDispatcher.h:203
void AddEvent(UniqueRef< EventBase > event)
Definition: EventDispatcher.h:213
Definition: EventDispatcher.h:63
Definition: Application.cpp:49
void RemoveEventListener(const MxString &name)
Definition: EventDispatcher.h:188