Samchon Framework for CPP  1.0.0
EventDispatcher.hpp
1 #pragma once
2 #include <samchon/API.hpp>
3 
4 #include <queue>
5 #include <unordered_set>
6 #include <unordered_map>
7 
8 #include <memory>
9 #include <functional>
10 #include <condition_variable>
11 #include <mutex>
12 
13 #include <samchon/library/RWMutex.hpp>
14 #include <samchon/library/Event.hpp>
15 
16 namespace samchon
17 {
18 namespace library
19 {
51  {
52  public:
53  typedef void(*Listener)(std::shared_ptr<Event>, void*);
54  // typedef std::function<void(std::shared_ptr<Event>, void*)> Listener;
55 
56  private:
60  std::unordered_map<int, std::unordered_map<Listener, std::unordered_set<void*>>> listeners;
61 
66 
67  public:
68  /* ----------------------------------------------------------
69  CONSTRUCTORS
70  ---------------------------------------------------------- */
75  {
76  };
77 
88  {
89  // DO NOT COPY LISTENERS
90  };
91 
98  {
99  UniqueWriteLock obj_uk(obj.mtx);
100  {
101  listeners = move(obj.listeners);
102  }
103  obj_uk.unlock();
104 
105  std::unique_lock<std::mutex> s_uk(sMtx());
106 
107  for (auto it = eventMap().begin(); it != eventMap().end(); it++)
108  if (it->first == &obj)
109  {
110  auto event = it->second;
111 
112  it = eventMap().erase(it);
113  eventMap().insert(it, { this, event });
114  }
115  };
116 
121  {
122  UniqueWriteLock my_uk(mtx);
123  std::unique_lock<std::mutex> s_uk(sMtx());
124 
125  for (auto it = eventMap().begin(); it != eventMap().end();)
126  if (it->first == this)
127  eventMap().erase(it++);
128  else
129  it++;
130  };
131 
132  /* ----------------------------------------------------------
133  ADD-REMOVE EVENT LISTENERS
134  ---------------------------------------------------------- */
154  void addEventListener(int type, Listener listener, void *addiction = nullptr)
155  {
156  UniqueWriteLock uk(mtx);
157 
158  listeners[type][listener].insert(addiction);
159  };
160 
172  void removeEventListener(int type, Listener listener, void *addiction = nullptr)
173  {
174  UniqueWriteLock uk(mtx);
175  if (listeners.count(type) == 0)
176  return;
177 
178  // TEST WHETHER HAS THE LISTENER
179  if (listeners.count(type) == 0 ||
180  listeners[type].count(listener) == 0 ||
181  listeners[type][listener].count(addiction) == 0)
182  return;
183 
184  listeners[type][listener].erase(addiction);
185 
186  if (listeners[type][listener].empty() == true)
187  listeners[type].erase(listener);
188 
189  if (listeners[type].empty() == true)
190  listeners.erase(type);
191 
192  // NEED TO DELETE FROM EVENT MAP
193  };
194 
205  void dispatch(std::shared_ptr<Event> event)
206  {
207  // STARTS BACK-GROUND PROCESS IF NOT STARTED
208  start();
209 
210  UniqueReadLock my_uk(mtx);
211  if (listeners.count(event->getType()) == 0)
212  return;
213 
214  my_uk.unlock();
215 
216  std::unique_lock<std::mutex> s_uk(sMtx());
217  eventMap().insert({ this, event });
218 
219  cv().notify_all();
220  };
221 
222  private:
223  void deliver(std::shared_ptr<Event> event)
224  {
225  UniqueReadLock my_uk(mtx);
226  if (listeners.count(event->getType()) == 0)
227  return;
228 
229  auto listenerMap = listeners[event->getType()];
230  my_uk.unlock();
231 
232  for (auto it = listenerMap.begin(); it != listenerMap.end(); it++)
233  {
234  Listener listener = it->first;
235 
236  for (auto s_it = it->second.begin(); s_it != it->second.end(); s_it++)
237  {
238  void *addiction = *s_it;
239 
240  listener(event, addiction);
241  }
242  }
243  };
244 
245  /* ----------------------------------------------------------
246  MEMBERS OF STATIC
247  ---------------------------------------------------------- */
248  static bool& started()
249  {
250  static bool flag = false;
251  return flag;
252  };
253  static std::condition_variable& cv()
254  {
255  static std::condition_variable obj;
256  return obj;
257  };
258  static std::mutex& cv_mtx()
259  {
260  static std::mutex obj;
261  return obj;
262  };
263 
264  static std::unordered_multimap<EventDispatcher*, std::shared_ptr<Event>>& eventMap()
265  {
266  static std::unordered_multimap<EventDispatcher*, std::shared_ptr<Event>> map;
267  return map;
268  };
269 
270  static std::mutex& sMtx()
271  {
272  static std::mutex obj;
273  return obj;
274  };
275 
276  static void start()
277  {
278  std::unique_lock<std::mutex> uk(sMtx());
279  if (started() == true)
280  return;
281 
282  started() = true;
283  uk.unlock();
284 
285  for (size_t i = 0; i < THREAD_SIZE(); i++)
286  std::thread([]()
287  {
288  while (true)
289  {
290  while (true)
291  {
292  std::unique_lock<std::mutex> uk(sMtx());
293  if (eventMap().empty() == true)
294  break;
295 
296  auto pair = *eventMap().begin();
297  eventMap().erase(eventMap().begin());
298 
299  uk.unlock();
300 
301  EventDispatcher *obj = pair.first;
302  std::shared_ptr<Event> &event = pair.second;
303 
304  obj->deliver(event);
305  }
306 
307  std::unique_lock<std::mutex> cv_uk(cv_mtx());
308  cv().wait(cv_uk);
309  }
310  }).detach();
311  };
312 
313  public:
317  static size_t& THREAD_SIZE()
318  {
319  static size_t val = 2;
320  return val;
321  };
322  };
323 };
324 };
static size_t & THREAD_SIZE()
Numer of threads for background.
void dispatch(std::shared_ptr< Event > event)
Dispatches an event to all listeners.
EventDispatcher(EventDispatcher &&obj)
Move Constructor.
std::unordered_map< int, std::unordered_map< Listener, std::unordered_set< void * > > > listeners
A container storing listeners.
EventDispatcher(const EventDispatcher &)
Copy Constructor.
void unlock() const
Unlock of read.
Unique lock for reading.
Unique lock for writing.
void removeEventListener(int type, Listener listener, void *addiction=nullptr)
Remove a registered event listener.
void unlock()
Unlock on writing.
Abstract class for dispatching Event.
virtual ~EventDispatcher()
Default Destructor.
EventDispatcher()
Default Constructor.
void addEventListener(int type, Listener listener, void *addiction=nullptr)
Register an event listener.
RWMutex mtx
A rw_mutex for concurrency.