Samchon Framework for CPP  1.0.0
EventDispatcher.cpp
1 #include <samchon/library/EventDispatcher.hpp>
2 
3 #include <samchon/library/Event.hpp>
4 
5 using namespace std;
6 using namespace samchon;
7 using namespace samchon::library;
8 
9 /* ----------------------------------------------------------
10  CONSTRUCTORS
11 ---------------------------------------------------------- */
12 EventDispatcher::EventDispatcher()
13 {
14 }
15 EventDispatcher::EventDispatcher(const EventDispatcher &obj)
16 {
17  // DO NOT COPY LISTENERS
18 }
19 EventDispatcher::EventDispatcher(EventDispatcher &&obj)
20 {
21  UniqueWriteLock obj_uk(obj.mtx);
22  {
23  listeners = move(obj.listeners);
24  }
25  obj_uk.unlock();
26 
27  unique_lock<mutex> s_uk(sMtx);
28 
29  for (auto it = eventMap.begin(); it != eventMap.end(); it++)
30  if (it->first == &obj)
31  {
32  auto event = it->second;
33 
34  it = eventMap.erase(it);
35  eventMap.insert(it, { this, event });
36  }
37 }
38 
39 EventDispatcher::~EventDispatcher()
40 {
41  UniqueWriteLock my_uk(mtx);
42  unique_lock<mutex> s_uk(sMtx);
43 
44  for (auto it = eventMap.begin(); it != eventMap.end();)
45  if (it->first == this)
46  eventMap.erase(it++);
47  else
48  it++;
49 }
50 
51 /* ----------------------------------------------------------
52  ADD-REMOVE EVENT LISTENERS
53 ---------------------------------------------------------- */
54 void EventDispatcher::addEventListener(int type, Listener listener, void *addiction)
55 {
56  UniqueWriteLock uk(mtx);
57 
58  listeners[type][listener].insert(addiction);
59 }
60 void EventDispatcher::removeEventListener(int type, Listener listener, void *addiction)
61 {
62  UniqueWriteLock uk(mtx);
63  if (listeners.count(type) == 0)
64  return;
65 
66  // TEST WHETHER HAS THE LISTENER
67  if (listeners.count(type) == 0 ||
68  listeners[type].count(listener) == 0 ||
69  listeners[type][listener].count(addiction) == 0)
70  return;
71 
72  listeners[type][listener].erase(addiction);
73 
74  if (listeners[type][listener].empty() == true)
75  listeners[type].erase(listener);
76 
77  if (listeners[type].empty() == true)
78  listeners.erase(type);
79 
80  // NEED TO DELETE FROM EVENT MAP
81 }
82 
83 void EventDispatcher::dispatch(std::shared_ptr<Event> event)
84 {
85  // STARTS BACK-GROUND PROCESS IF NOT STARTED
86  start();
87 
88  UniqueReadLock my_uk(mtx);
89  if (listeners.count(event->getType()) == 0)
90  return;
91 
92  my_uk.unlock();
93 
94  unique_lock<mutex> s_uk(sMtx);
95  eventMap.insert({this, event});
96 
97  cv.notify_all();
98 }
99 void EventDispatcher::deliver(shared_ptr<Event> event)
100 {
101  UniqueReadLock my_uk(mtx);
102  if (listeners.count(event->getType()) == 0)
103  return;
104 
105  auto listenerMap = listeners[event->getType()];
106  my_uk.unlock();
107 
108  for (auto it = listenerMap.begin(); it != listenerMap.end(); it++)
109  {
110  Listener listener = it->first;
111 
112  for (auto s_it = it->second.begin(); s_it != it->second.end(); s_it++)
113  {
114  void *addiction = *s_it;
115 
116  listener(event, addiction);
117  }
118  }
119 }
120 
121 /* ----------------------------------------------------------
122  MEMBERS OF STATIC
123 ---------------------------------------------------------- */
124 size_t EventDispatcher::THREAD_SIZE = 2;
125 
126 bool EventDispatcher::started = false;
127 condition_variable EventDispatcher::cv;
128 mutex EventDispatcher::cv_mtx;
129 
130 unordered_multimap<EventDispatcher*, shared_ptr<Event>> EventDispatcher::eventMap;
131 mutex EventDispatcher::sMtx;
132 
133 void EventDispatcher::start()
134 {
135  unique_lock<mutex> uk(sMtx);
136  if (started == true)
137  return;
138 
139  started = true;
140  uk.unlock();
141 
142  for (size_t i = 0; i < THREAD_SIZE; i++)
143  {
144  thread([]()
145  {
146  while (true)
147  {
148  while (true)
149  {
150  unique_lock<mutex> uk(sMtx);
151  if (eventMap.empty() == true)
152  break;
153 
154  auto pair = *eventMap.begin();
155  eventMap.erase(eventMap.begin());
156 
157  uk.unlock();
158 
159  EventDispatcher *obj = pair.first;
160  shared_ptr<Event> &event = pair.second;
161 
162  obj->deliver(event);
163  }
164 
165  unique_lock<mutex> cv_uk(cv_mtx);
166  cv.wait(cv_uk);
167  }
168  }).detach();
169  }
170 }
void unlock()
Unlock on writing.
Definition: RWMutex.hpp:4
Package of libraries.
Definition: library.hpp:84
Unique lock for reading.
Unique lock for writing.
Abstract class for dispatching Event.
void unlock() const
Unlock of read.
Top level namespace of products built from samchon.
Definition: ByteArray.hpp:7