OLD | NEW |
1 // sigslot.h: Signal/Slot classes | 1 // sigslot.h: Signal/Slot classes |
2 // | 2 // |
3 // Written by Sarah Thompson (sarah@telergy.com) 2002. | 3 // Written by Sarah Thompson (sarah@telergy.com) 2002. |
4 // | 4 // |
5 // License: Public domain. You are free to use this code however you like, with
the proviso that | 5 // License: Public domain. You are free to use this code however you like, with |
6 // the author takes on no responsibility or liability for any use. | 6 // the proviso that the author takes on no responsibility or liability for any |
| 7 // use. |
7 // | 8 // |
8 // QUICK DOCUMENTATION | 9 // QUICK DOCUMENTATION |
9 // | 10 // |
10 //» » » » (see also the full documentation at http://sigsl
ot.sourceforge.net/) | 11 // (see also the full documentation at http://sigslot.sourceforge.net/) |
11 // | 12 // |
12 //» » #define switches | 13 // #define switches |
13 //» » » SIGSLOT_PURE_ISO» » » - Define this to
force ISO C++ compliance. This also disables | 14 // SIGSLOT_PURE_ISO: |
14 //» » » » » » » » » »
all of the thread safety support on platforms where it is | 15 // Define this to force ISO C++ compliance. This also disables all of |
15 //» » » » » » » » » »
available. | 16 // the thread safety support on platforms where it is available. |
16 // | 17 // |
17 //» » » SIGSLOT_USE_POSIX_THREADS» - Force use of Posix thr
eads when using a C++ compiler other than | 18 // SIGSLOT_USE_POSIX_THREADS: |
18 //» » » » » » » » » »
gcc on a platform that supports Posix threads. (When using gcc, | 19 // Force use of Posix threads when using a C++ compiler other than gcc |
19 //» » » » » » » » » »
this is the default - use SIGSLOT_PURE_ISO to disable this if | 20 // on a platform that supports Posix threads. (When using gcc, this is |
20 //» » » » » » » » » »
necessary) | 21 // the default - use SIGSLOT_PURE_ISO to disable this if necessary) |
21 // | 22 // |
22 //» » » SIGSLOT_DEFAULT_MT_POLICY» - Where thread support i
s enabled, this defaults to multi_threaded_global. | 23 // SIGSLOT_DEFAULT_MT_POLICY: |
23 //» » » » » » » » » »
Otherwise, the default is single_threaded. #define this yourself to | 24 // Where thread support is enabled, this defaults to |
24 //» » » » » » » » » »
override the default. In pure ISO mode, anything other than | 25 // multi_threaded_global. Otherwise, the default is single_threaded. |
25 //» » » » » » » » » »
single_threaded will cause a compiler error. | 26 // #define this yourself to override the default. In pure ISO mode, |
| 27 // anything other than single_threaded will cause a compiler error. |
26 // | 28 // |
27 //» » PLATFORM NOTES | 29 // PLATFORM NOTES |
28 // | 30 // |
29 //» » » Win32» » » » » » - On Win
32, the WEBRTC_WIN symbol must be #defined. Most mainstream | 31 // Win32: |
30 //» » » » » » » » » »
compilers do this by default, but you may need to define it | 32 // On Win32, the WEBRTC_WIN symbol must be #defined. Most mainstream |
31 //» » » » » » » » » »
yourself if your build environment is less standard. This causes | 33 // compilers do this by default, but you may need to define it yourself |
32 //» » » » » » » » » »
the Win32 thread support to be compiled in and used automatically. | 34 // if your build environment is less standard. This causes the Win32 |
| 35 // thread support to be compiled in and used automatically. |
33 // | 36 // |
34 //» » » Unix/Linux/BSD, etc.» » - If you're using gcc, i
t is assumed that you have Posix threads | 37 // Unix/Linux/BSD, etc.: |
35 //» » » » » » » » » »
available, so they are used automatically. You can override this | 38 // If you're using gcc, it is assumed that you have Posix threads |
36 //» » » » » » » » » »
(as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using | 39 // available, so they are used automatically. You can override this (as |
37 //» » » » » » » » » »
something other than gcc but still want to use Posix threads, you | 40 // under Windows) with the SIGSLOT_PURE_ISO switch. If you're using |
38 //» » » » » » » » » »
need to #define SIGSLOT_USE_POSIX_THREADS. | 41 // something other than gcc but still want to use Posix threads, you |
| 42 // need to #define SIGSLOT_USE_POSIX_THREADS. |
39 // | 43 // |
40 //» » » ISO C++»» » » » » - If non
e of the supported platforms are detected, or if | 44 // ISO C++: |
41 //» » » » » » » » » »
SIGSLOT_PURE_ISO is defined, all multithreading support is turned off, | 45 // If none of the supported platforms are detected, or if |
42 //» » » » » » » » » »
along with any code that might cause a pure ISO C++ environment to | 46 // SIGSLOT_PURE_ISO is defined, all multithreading support is turned |
43 //» » » » » » » » » »
complain. Before you ask, gcc -ansi -pedantic won't compile this | 47 // off, along with any code that might cause a pure ISO C++ environment |
44 //» » » » » » » » » »
library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of | 48 // to complain. Before you ask, gcc -ansi -pedantic won't compile this |
45 //» » » » » » » » » »
errors that aren't really there. If you feel like investigating this, | 49 // library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of |
46 //» » » » » » » » » »
please contact the author. | 50 // errors that aren't really there. If you feel like investigating this, |
| 51 // please contact the author. |
47 // | 52 // |
48 // | 53 // |
49 //» » THREADING MODES | 54 // THREADING MODES |
50 // | 55 // |
51 //» » » single_threaded»» » » - Your program i
s assumed to be single threaded from the point of view | 56 // single_threaded: |
52 //» » » » » » » » » »
of signal/slot usage (i.e. all objects using signals and slots are | 57 // Your program is assumed to be single threaded from the point of view |
53 //» » » » » » » » » »
created and destroyed from a single thread). Behaviour if objects are | 58 // of signal/slot usage (i.e. all objects using signals and slots are |
54 //» » » » » » » » » »
destroyed concurrently is undefined (i.e. you'll get the occasional | 59 // created and destroyed from a single thread). Behaviour if objects are |
55 //» » » » » » » » » »
segmentation fault/memory exception). | 60 // destroyed concurrently is undefined (i.e. you'll get the occasional |
| 61 // segmentation fault/memory exception). |
56 // | 62 // |
57 //» » » multi_threaded_global» » - Your program is assume
d to be multi threaded. Objects using signals and | 63 // multi_threaded_global: |
58 //» » » » » » » » » »
slots can be safely created and destroyed from any thread, even when | 64 // Your program is assumed to be multi threaded. Objects using signals |
59 //» » » » » » » » » »
connections exist. In multi_threaded_global mode, this is achieved by a | 65 // and slots can be safely created and destroyed from any thread, even |
60 //» » » » » » » » » »
single global mutex (actually a critical section on Windows because they | 66 // when connections exist. In multi_threaded_global mode, this is |
61 //» » » » » » » » » »
are faster). This option uses less OS resources, but results in more | 67 // achieved by a single global mutex (actually a critical section on |
62 //» » » » » » » » » »
opportunities for contention, possibly resulting in more context switches | 68 // Windows because they are faster). This option uses less OS resources, |
63 //» » » » » » » » » »
than are strictly necessary. | 69 // but results in more opportunities for contention, possibly resulting |
| 70 // in more context switches than are strictly necessary. |
64 // | 71 // |
65 //» » » multi_threaded_local» » - Behaviour in this mode
is essentially the same as multi_threaded_global, | 72 // multi_threaded_local: |
66 //» » » » » » » » » »
except that each signal, and each object that inherits has_slots, all | 73 // Behaviour in this mode is essentially the same as |
67 //» » » » » » » » » »
have their own mutex/critical section. In practice, this means that | 74 // multi_threaded_global, except that each signal, and each object that |
68 //» » » » » » » » » »
mutex collisions (and hence context switches) only happen if they are | 75 // inherits has_slots, all have their own mutex/critical section. In |
69 //» » » » » » » » » »
absolutely essential. However, on some platforms, creating a lot of | 76 // practice, this means that mutex collisions (and hence context |
70 //» » » » » » » » » »
mutexes can slow down the whole OS, so use this option with care. | 77 // switches) only happen if they are absolutely essential. However, on |
| 78 // some platforms, creating a lot of mutexes can slow down the whole OS, |
| 79 // so use this option with care. |
71 // | 80 // |
72 //» » USING THE LIBRARY | 81 // USING THE LIBRARY |
73 // | 82 // |
74 //» » » See the full documentation at http://sigslot.sourceforge
.net/ | 83 // See the full documentation at http://sigslot.sourceforge.net/ |
75 // | |
76 // | 84 // |
77 // Libjingle specific: | 85 // Libjingle specific: |
| 86 // |
78 // This file has been modified such that has_slots and signalx do not have to be | 87 // This file has been modified such that has_slots and signalx do not have to be |
79 // using the same threading requirements. E.g. it is possible to connect a | 88 // using the same threading requirements. E.g. it is possible to connect a |
80 // has_slots<single_threaded> and signal0<multi_threaded_local> or | 89 // has_slots<single_threaded> and signal0<multi_threaded_local> or |
81 // has_slots<multi_threaded_local> and signal0<single_threaded>. | 90 // has_slots<multi_threaded_local> and signal0<single_threaded>. |
82 // If has_slots is single threaded the user must ensure that it is not trying | 91 // If has_slots is single threaded the user must ensure that it is not trying |
83 // to connect or disconnect to signalx concurrently or data race may occur. | 92 // to connect or disconnect to signalx concurrently or data race may occur. |
84 // If signalx is single threaded the user must ensure that disconnect, connect | 93 // If signalx is single threaded the user must ensure that disconnect, connect |
85 // or signal is not happening concurrently or data race may occur. | 94 // or signal is not happening concurrently or data race may occur. |
86 | 95 |
87 #ifndef WEBRTC_BASE_SIGSLOT_H__ | 96 #ifndef WEBRTC_BASE_SIGSLOT_H__ |
88 #define WEBRTC_BASE_SIGSLOT_H__ | 97 #define WEBRTC_BASE_SIGSLOT_H__ |
89 | 98 |
| 99 #include <stdlib.h> |
90 #include <cstring> | 100 #include <cstring> |
91 #include <list> | 101 #include <list> |
92 #include <set> | 102 #include <set> |
93 #include <stdlib.h> | |
94 | 103 |
95 // On our copy of sigslot.h, we set single threading as default. | 104 // On our copy of sigslot.h, we set single threading as default. |
96 #define SIGSLOT_DEFAULT_MT_POLICY single_threaded | 105 #define SIGSLOT_DEFAULT_MT_POLICY single_threaded |
97 | 106 |
98 #if defined(SIGSLOT_PURE_ISO) || (!defined(WEBRTC_WIN) && !defined(__GNUG__) &&
!defined(SIGSLOT_USE_POSIX_THREADS)) | 107 #if defined(SIGSLOT_PURE_ISO) || \ |
99 #» define _SIGSLOT_SINGLE_THREADED | 108 (!defined(WEBRTC_WIN) && !defined(__GNUG__) && \ |
| 109 !defined(SIGSLOT_USE_POSIX_THREADS)) |
| 110 #define _SIGSLOT_SINGLE_THREADED |
100 #elif defined(WEBRTC_WIN) | 111 #elif defined(WEBRTC_WIN) |
101 #» define _SIGSLOT_HAS_WIN32_THREADS | 112 #define _SIGSLOT_HAS_WIN32_THREADS |
102 #» if !defined(WIN32_LEAN_AND_MEAN) | 113 #if !defined(WIN32_LEAN_AND_MEAN) |
103 #» » define WIN32_LEAN_AND_MEAN | 114 #define WIN32_LEAN_AND_MEAN |
104 #» endif | 115 #endif |
105 #» include "webrtc/base/win32.h" | 116 #include "webrtc/base/win32.h" |
106 #elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) | 117 #elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) |
107 #» define _SIGSLOT_HAS_POSIX_THREADS | 118 #define _SIGSLOT_HAS_POSIX_THREADS |
108 #» include <pthread.h> | 119 #include <pthread.h> |
109 #else | 120 #else |
110 #» define _SIGSLOT_SINGLE_THREADED | 121 #define _SIGSLOT_SINGLE_THREADED |
111 #endif | 122 #endif |
112 | 123 |
113 #ifndef SIGSLOT_DEFAULT_MT_POLICY | 124 #ifndef SIGSLOT_DEFAULT_MT_POLICY |
114 #» ifdef _SIGSLOT_SINGLE_THREADED | 125 #ifdef _SIGSLOT_SINGLE_THREADED |
115 #» » define SIGSLOT_DEFAULT_MT_POLICY single_threaded | 126 #define SIGSLOT_DEFAULT_MT_POLICY single_threaded |
116 #» else | 127 #else |
117 #» » define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local | 128 #define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local |
118 #» endif | 129 #endif |
119 #endif | 130 #endif |
120 | 131 |
121 // TODO: change this namespace to rtc? | 132 // TODO: change this namespace to rtc? |
122 namespace sigslot { | 133 namespace sigslot { |
123 | 134 |
124 » class single_threaded | 135 class single_threaded { |
125 » { | 136 public: |
126 » public: | 137 void lock() {} |
127 » » void lock() {} | 138 void unlock() {} |
128 » » void unlock() {} | 139 }; |
129 » }; | |
130 | 140 |
131 #ifdef _SIGSLOT_HAS_WIN32_THREADS | 141 #ifdef _SIGSLOT_HAS_WIN32_THREADS |
132 » // The multi threading policies only get compiled in if they are enabled
. | 142 // The multi threading policies only get compiled in if they are enabled. |
133 » class multi_threaded_global | 143 class multi_threaded_global { |
134 » { | 144 public: |
135 » public: | 145 multi_threaded_global() { |
136 » » multi_threaded_global() | 146 static bool isinitialised = false; |
137 » » { | 147 |
138 » » » static bool isinitialised = false; | 148 if (!isinitialised) { |
139 | 149 InitializeCriticalSection(get_critsec()); |
140 » » » if(!isinitialised) | 150 isinitialised = true; |
141 » » » { | 151 } |
142 » » » » InitializeCriticalSection(get_critsec()); | 152 } |
143 » » » » isinitialised = true; | 153 |
144 » » » } | 154 void lock() { EnterCriticalSection(get_critsec()); } |
145 » » } | 155 |
146 | 156 void unlock() { LeaveCriticalSection(get_critsec()); } |
147 » » void lock() | 157 |
148 » » { | 158 private: |
149 » » » EnterCriticalSection(get_critsec()); | 159 CRITICAL_SECTION* get_critsec() { |
150 » » } | 160 static CRITICAL_SECTION g_critsec; |
151 | 161 return &g_critsec; |
152 » » void unlock() | 162 } |
153 » » { | 163 }; |
154 » » » LeaveCriticalSection(get_critsec()); | 164 |
155 » » } | 165 class multi_threaded_local { |
156 | 166 public: |
157 » private: | 167 multi_threaded_local() { InitializeCriticalSection(&m_critsec); } |
158 » » CRITICAL_SECTION* get_critsec() | 168 |
159 » » { | 169 multi_threaded_local(const multi_threaded_local&) { |
160 » » » static CRITICAL_SECTION g_critsec; | 170 InitializeCriticalSection(&m_critsec); |
161 » » » return &g_critsec; | 171 } |
162 » » } | 172 |
163 » }; | 173 ~multi_threaded_local() { DeleteCriticalSection(&m_critsec); } |
164 | 174 |
165 » class multi_threaded_local | 175 void lock() { EnterCriticalSection(&m_critsec); } |
166 » { | 176 |
167 » public: | 177 void unlock() { LeaveCriticalSection(&m_critsec); } |
168 » » multi_threaded_local() | 178 |
169 » » { | 179 private: |
170 » » » InitializeCriticalSection(&m_critsec); | 180 CRITICAL_SECTION m_critsec; |
171 » » } | 181 }; |
172 | 182 #endif // _SIGSLOT_HAS_WIN32_THREADS |
173 » » multi_threaded_local(const multi_threaded_local&) | |
174 » » { | |
175 » » » InitializeCriticalSection(&m_critsec); | |
176 » » } | |
177 | |
178 » » ~multi_threaded_local() | |
179 » » { | |
180 » » » DeleteCriticalSection(&m_critsec); | |
181 » » } | |
182 | |
183 » » void lock() | |
184 » » { | |
185 » » » EnterCriticalSection(&m_critsec); | |
186 » » } | |
187 | |
188 » » void unlock() | |
189 » » { | |
190 » » » LeaveCriticalSection(&m_critsec); | |
191 » » } | |
192 | |
193 » private: | |
194 » » CRITICAL_SECTION m_critsec; | |
195 » }; | |
196 #endif // _SIGSLOT_HAS_WIN32_THREADS | |
197 | 183 |
198 #ifdef _SIGSLOT_HAS_POSIX_THREADS | 184 #ifdef _SIGSLOT_HAS_POSIX_THREADS |
199 // The multi threading policies only get compiled in if they are enabled
. | 185 // The multi threading policies only get compiled in if they are enabled. |
200 class multi_threaded_global | 186 class multi_threaded_global { |
201 { | 187 public: |
202 public: | 188 void lock() { pthread_mutex_lock(get_mutex()); } |
203 void lock() | 189 void unlock() { pthread_mutex_unlock(get_mutex()); } |
204 { | 190 |
205 pthread_mutex_lock(get_mutex()); | 191 private: |
206 } | 192 static pthread_mutex_t* get_mutex(); |
207 void unlock() | 193 }; |
208 { | 194 |
209 pthread_mutex_unlock(get_mutex()); | 195 class multi_threaded_local { |
210 } | 196 public: |
211 | 197 multi_threaded_local() { pthread_mutex_init(&m_mutex, nullptr); } |
212 private: | 198 multi_threaded_local(const multi_threaded_local&) { |
213 static pthread_mutex_t* get_mutex(); | 199 pthread_mutex_init(&m_mutex, nullptr); |
214 }; | 200 } |
215 | 201 ~multi_threaded_local() { pthread_mutex_destroy(&m_mutex); } |
216 class multi_threaded_local | 202 void lock() { pthread_mutex_lock(&m_mutex); } |
217 { | 203 void unlock() { pthread_mutex_unlock(&m_mutex); } |
218 public: | 204 |
219 multi_threaded_local() { pthread_mutex_init(&m_mutex, nullptr);
} | 205 private: |
220 multi_threaded_local(const multi_threaded_local&) { | 206 pthread_mutex_t m_mutex; |
221 pthread_mutex_init(&m_mutex, nullptr); | 207 }; |
222 } | 208 #endif // _SIGSLOT_HAS_POSIX_THREADS |
223 ~multi_threaded_local() | 209 |
224 { | 210 template <class mt_policy> |
225 pthread_mutex_destroy(&m_mutex); | 211 class lock_block { |
226 } | 212 public: |
227 void lock() | 213 mt_policy* m_mutex; |
228 { | 214 |
229 pthread_mutex_lock(&m_mutex); | 215 lock_block(mt_policy* mtx) : m_mutex(mtx) { m_mutex->lock(); } |
230 } | 216 |
231 void unlock() | 217 ~lock_block() { m_mutex->unlock(); } |
232 { | 218 }; |
233 pthread_mutex_unlock(&m_mutex); | 219 |
234 } | 220 class _signal_base_interface; |
235 | 221 |
236 private: | 222 class has_slots_interface { |
237 pthread_mutex_t m_mutex; | 223 private: |
238 }; | 224 typedef void (*signal_connect_t)(has_slots_interface* self, |
239 #endif // _SIGSLOT_HAS_POSIX_THREADS | 225 _signal_base_interface* sender); |
240 | 226 typedef void (*signal_disconnect_t)(has_slots_interface* self, |
241 template<class mt_policy> | 227 _signal_base_interface* sender); |
242 class lock_block | 228 typedef void (*disconnect_all_t)(has_slots_interface* self); |
243 { | 229 |
244 public: | 230 const signal_connect_t m_signal_connect; |
245 mt_policy *m_mutex; | 231 const signal_disconnect_t m_signal_disconnect; |
246 | 232 const disconnect_all_t m_disconnect_all; |
247 lock_block(mt_policy *mtx) | 233 |
248 : m_mutex(mtx) | 234 protected: |
249 { | 235 has_slots_interface(signal_connect_t conn, |
250 m_mutex->lock(); | 236 signal_disconnect_t disc, |
251 } | 237 disconnect_all_t disc_all) |
252 | 238 : m_signal_connect(conn), |
253 ~lock_block() | 239 m_signal_disconnect(disc), |
254 { | 240 m_disconnect_all(disc_all) {} |
255 m_mutex->unlock(); | 241 |
256 } | 242 // Doesn't really need to be virtual, but is for backwards compatibility |
257 }; | 243 // (it was virtual in a previous version of sigslot). |
258 | 244 virtual ~has_slots_interface() {} |
259 class _signal_base_interface; | 245 |
260 | 246 public: |
261 class has_slots_interface | 247 void signal_connect(_signal_base_interface* sender) { |
262 { | 248 m_signal_connect(this, sender); |
263 private: | 249 } |
264 typedef void (*signal_connect_t)(has_slots_interface* self, _sig
nal_base_interface* sender); | 250 |
265 typedef void (*signal_disconnect_t)(has_slots_interface* self, _
signal_base_interface* sender); | 251 void signal_disconnect(_signal_base_interface* sender) { |
266 typedef void (*disconnect_all_t)(has_slots_interface* self); | 252 m_signal_disconnect(this, sender); |
267 | 253 } |
268 const signal_connect_t m_signal_connect; | 254 |
269 const signal_disconnect_t m_signal_disconnect; | 255 void disconnect_all() { m_disconnect_all(this); } |
270 const disconnect_all_t m_disconnect_all; | 256 }; |
271 | 257 |
272 protected: | 258 class _signal_base_interface { |
273 has_slots_interface(signal_connect_t conn, signal_disconnect_t d
isc, disconnect_all_t disc_all) : | 259 private: |
274 m_signal_connect(conn), m_signal_disconnect(disc), m_dis
connect_all(disc_all) | 260 typedef void (*slot_disconnect_t)(_signal_base_interface* self, |
275 { | 261 has_slots_interface* pslot); |
276 } | 262 typedef void (*slot_duplicate_t)(_signal_base_interface* self, |
277 | 263 const has_slots_interface* poldslot, |
278 // Doesn't really need to be virtual, but is for backwards compa
tibility | 264 has_slots_interface* pnewslot); |
279 // (it was virtual in a previous version of sigslot). | 265 |
280 virtual ~has_slots_interface() {} | 266 const slot_disconnect_t m_slot_disconnect; |
281 | 267 const slot_duplicate_t m_slot_duplicate; |
282 public: | 268 |
283 void signal_connect(_signal_base_interface* sender) | 269 protected: |
284 { | 270 _signal_base_interface(slot_disconnect_t disc, slot_duplicate_t dupl) |
285 m_signal_connect(this, sender); | 271 : m_slot_disconnect(disc), m_slot_duplicate(dupl) {} |
286 } | 272 |
287 | 273 ~_signal_base_interface() {} |
288 void signal_disconnect(_signal_base_interface* sender) | 274 |
289 { | 275 public: |
290 m_signal_disconnect(this, sender); | 276 void slot_disconnect(has_slots_interface* pslot) { |
291 } | 277 m_slot_disconnect(this, pslot); |
292 | 278 } |
293 void disconnect_all() | 279 |
294 { | 280 void slot_duplicate(const has_slots_interface* poldslot, |
295 m_disconnect_all(this); | 281 has_slots_interface* pnewslot) { |
296 } | 282 m_slot_duplicate(this, poldslot, pnewslot); |
297 }; | 283 } |
298 | 284 }; |
299 class _signal_base_interface | 285 |
300 { | 286 class _opaque_connection { |
301 private: | 287 private: |
302 typedef void (*slot_disconnect_t)(_signal_base_interface* self,
has_slots_interface* pslot); | 288 typedef void (*emit_t)(const _opaque_connection*); |
303 typedef void (*slot_duplicate_t)(_signal_base_interface* self, c
onst has_slots_interface* poldslot, has_slots_interface* pnewslot); | 289 template <typename FromT, typename ToT> |
304 | 290 union union_caster { |
305 const slot_disconnect_t m_slot_disconnect; | 291 FromT from; |
306 const slot_duplicate_t m_slot_duplicate; | 292 ToT to; |
307 | 293 }; |
308 protected: | 294 |
309 _signal_base_interface(slot_disconnect_t disc, slot_duplicate_t
dupl) : | 295 emit_t pemit; |
310 m_slot_disconnect(disc), m_slot_duplicate(dupl) | 296 has_slots_interface* pdest; |
311 { | 297 // Pointers to member functions may be up to 16 bytes for virtual classes, |
312 } | 298 // so make sure we have enough space to store it. |
313 | 299 unsigned char pmethod[16]; |
314 ~_signal_base_interface() {} | 300 |
315 | 301 public: |
316 public: | 302 template <typename DestT, typename... Args> |
317 void slot_disconnect(has_slots_interface* pslot) | 303 _opaque_connection(DestT* pd, void (DestT::*pm)(Args...)) : pdest(pd) { |
318 { | 304 typedef void (DestT::*pm_t)(Args...); |
319 m_slot_disconnect(this, pslot); | 305 static_assert(sizeof(pm_t) <= sizeof(pmethod), |
320 } | 306 "Size of slot function pointer too large."); |
321 | 307 |
322 void slot_duplicate(const has_slots_interface* poldslot, has_slo
ts_interface* pnewslot) | 308 std::memcpy(pmethod, &pm, sizeof(pm_t)); |
323 { | 309 |
324 m_slot_duplicate(this, poldslot, pnewslot); | 310 typedef void (*em_t)(const _opaque_connection* self, Args...); |
325 } | 311 union_caster<em_t, emit_t> caster2; |
326 }; | 312 caster2.from = &_opaque_connection::emitter<DestT, Args...>; |
327 | 313 pemit = caster2.to; |
328 class _opaque_connection | 314 } |
329 { | 315 |
330 private: | 316 has_slots_interface* getdest() const { return pdest; } |
331 typedef void (*emit_t)(const _opaque_connection*); | 317 |
332 template< typename FromT, typename ToT > | 318 _opaque_connection duplicate(has_slots_interface* newtarget) const { |
333 union union_caster | 319 _opaque_connection res = *this; |
334 { | 320 res.pdest = newtarget; |
335 FromT from; | 321 return res; |
336 ToT to; | 322 } |
337 }; | 323 |
338 | 324 // Just calls the stored "emitter" function pointer stored at construction |
339 emit_t pemit; | 325 // time. |
340 has_slots_interface* pdest; | 326 template <typename... Args> |
341 // Pointers to member functions may be up to 16 bytes for virtua
l classes, | 327 void emit(Args... args) const { |
342 // so make sure we have enough space to store it. | 328 typedef void (*em_t)(const _opaque_connection*, Args...); |
343 unsigned char pmethod[16]; | 329 union_caster<emit_t, em_t> caster; |
344 | 330 caster.from = pemit; |
345 public: | 331 (caster.to)(this, args...); |
346 template< typename DestT, typename ... Args > | 332 } |
347 _opaque_connection(DestT* pd, void (DestT::*pm)(Args...)) : pdes
t(pd) | 333 |
348 { | 334 private: |
349 typedef void (DestT::*pm_t)(Args...); | 335 template <typename DestT, typename... Args> |
350 static_assert(sizeof(pm_t) <= sizeof(pmethod), "Size of
slot function pointer too large."); | 336 static void emitter(const _opaque_connection* self, Args... args) { |
351 | 337 typedef void (DestT::*pm_t)(Args...); |
352 std::memcpy(pmethod, &pm, sizeof(pm_t)); | 338 pm_t pm; |
353 | 339 std::memcpy(&pm, self->pmethod, sizeof(pm_t)); |
354 typedef void (*em_t)(const _opaque_connection* self, Arg
s...); | 340 (static_cast<DestT*>(self->pdest)->*(pm))(args...); |
355 union_caster< em_t, emit_t > caster2; | 341 } |
356 caster2.from = &_opaque_connection::emitter< DestT, Args
... >; | 342 }; |
357 pemit = caster2.to; | 343 |
358 } | 344 template <class mt_policy> |
359 | 345 class _signal_base : public _signal_base_interface, public mt_policy { |
360 has_slots_interface* getdest() const { return pdest; } | 346 protected: |
361 | 347 typedef std::list<_opaque_connection> connections_list; |
362 _opaque_connection duplicate(has_slots_interface* newtarget) con
st | 348 |
363 { | 349 _signal_base() |
364 _opaque_connection res = *this; | 350 : _signal_base_interface(&_signal_base::do_slot_disconnect, |
365 res.pdest = newtarget; | 351 &_signal_base::do_slot_duplicate), |
366 return res; | 352 m_current_iterator(m_connected_slots.end()) {} |
367 } | 353 |
368 | 354 ~_signal_base() { disconnect_all(); } |
369 // Just calls the stored "emitter" function pointer stored at co
nstruction | 355 |
370 // time. | 356 private: |
371 template< typename ... Args > | 357 _signal_base& operator=(_signal_base const& that); |
372 void emit(Args... args) const | 358 |
373 { | 359 public: |
374 typedef void (*em_t)(const _opaque_connection*, Args...)
; | 360 _signal_base(const _signal_base& o) |
375 union_caster< emit_t, em_t > caster; | 361 : _signal_base_interface(&_signal_base::do_slot_disconnect, |
376 caster.from = pemit; | 362 &_signal_base::do_slot_duplicate), |
377 (caster.to)(this, args...); | 363 m_current_iterator(m_connected_slots.end()) { |
378 } | 364 lock_block<mt_policy> lock(this); |
379 | 365 for (const auto& connection : o.m_connected_slots) { |
380 private: | 366 connection.getdest()->signal_connect(this); |
381 template< typename DestT, typename ... Args > | 367 m_connected_slots.push_back(connection); |
382 static void emitter(const _opaque_connection* self, Args... args
) | 368 } |
383 { | 369 } |
384 typedef void (DestT::*pm_t)(Args...); | 370 |
385 pm_t pm; | 371 bool is_empty() { |
386 std::memcpy(&pm, self->pmethod, sizeof(pm_t)); | 372 lock_block<mt_policy> lock(this); |
387 (static_cast< DestT* >(self->pdest)->*(pm))(args...); | 373 return m_connected_slots.empty(); |
388 } | 374 } |
389 }; | 375 |
390 | 376 void disconnect_all() { |
391 template<class mt_policy> | 377 lock_block<mt_policy> lock(this); |
392 class _signal_base : public _signal_base_interface, public mt_policy | 378 |
393 { | 379 while (!m_connected_slots.empty()) { |
394 protected: | 380 has_slots_interface* pdest = m_connected_slots.front().getdest(); |
395 typedef std::list< _opaque_connection > connections_list; | 381 m_connected_slots.pop_front(); |
396 | 382 pdest->signal_disconnect(static_cast<_signal_base_interface*>(this)); |
397 _signal_base() : _signal_base_interface(&_signal_base::do_slot_d
isconnect, &_signal_base::do_slot_duplicate), | 383 } |
398 m_current_iterator(m_connected_slots.end()) | 384 // If disconnect_all is called while the signal is firing, advance the |
399 { | 385 // current slot iterator to the end to avoid an invalidated iterator from |
400 } | 386 // being dereferenced. |
401 | 387 m_current_iterator = m_connected_slots.end(); |
402 ~_signal_base() | 388 } |
403 { | |
404 disconnect_all(); | |
405 } | |
406 | |
407 private: | |
408 _signal_base& operator= (_signal_base const& that); | |
409 | |
410 public: | |
411 _signal_base(const _signal_base& o) : _signal_base_interface(&_s
ignal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate), | |
412 m_current_iterator(m_connected_slots.end()) { | |
413 lock_block<mt_policy> lock(this); | |
414 for (const auto& connection : o.m_connected_slots) | |
415 { | |
416 connection.getdest()->signal_connect(this); | |
417 m_connected_slots.push_back(connection); | |
418 } | |
419 } | |
420 | |
421 bool is_empty() | |
422 { | |
423 lock_block<mt_policy> lock(this); | |
424 return m_connected_slots.empty(); | |
425 } | |
426 | |
427 void disconnect_all() | |
428 { | |
429 lock_block<mt_policy> lock(this); | |
430 | |
431 while(!m_connected_slots.empty()) | |
432 { | |
433 has_slots_interface* pdest = m_connected_slots.f
ront().getdest(); | |
434 m_connected_slots.pop_front(); | |
435 pdest->signal_disconnect(static_cast< _signal_ba
se_interface* >(this)); | |
436 } | |
437 // If disconnect_all is called while the signal is firing, advance the | |
438 // current slot iterator to the end to avoid an invalidated iterator from | |
439 // being dereferenced. | |
440 m_current_iterator = m_connected_slots.end(); | |
441 } | |
442 | 389 |
443 #if !defined(NDEBUG) | 390 #if !defined(NDEBUG) |
444 » » bool connected(has_slots_interface* pclass) | 391 bool connected(has_slots_interface* pclass) { |
445 » » { | 392 lock_block<mt_policy> lock(this); |
446 » » » lock_block<mt_policy> lock(this); | 393 connections_list::const_iterator it = m_connected_slots.begin(); |
447 » » » connections_list::const_iterator it = m_connected_slots.
begin(); | 394 connections_list::const_iterator itEnd = m_connected_slots.end(); |
448 » » » connections_list::const_iterator itEnd = m_connected_slo
ts.end(); | 395 while (it != itEnd) { |
449 » » » while(it != itEnd) | 396 if (it->getdest() == pclass) |
450 » » » { | 397 return true; |
451 » » » » if (it->getdest() == pclass) | 398 ++it; |
452 » » » » » return true; | 399 } |
453 » » » » ++it; | 400 return false; |
454 » » » } | 401 } |
455 » » » return false; | |
456 » » } | |
457 #endif | 402 #endif |
458 | 403 |
459 » » void disconnect(has_slots_interface* pclass) | 404 void disconnect(has_slots_interface* pclass) { |
460 » » { | 405 lock_block<mt_policy> lock(this); |
461 » » » lock_block<mt_policy> lock(this); | 406 connections_list::iterator it = m_connected_slots.begin(); |
462 » » » connections_list::iterator it = m_connected_slots.begin(
); | 407 connections_list::iterator itEnd = m_connected_slots.end(); |
463 » » » connections_list::iterator itEnd = m_connected_slots.end
(); | 408 |
464 | 409 while (it != itEnd) { |
465 » » » while(it != itEnd) | 410 if (it->getdest() == pclass) { |
466 » » » { | 411 // If we're currently using this iterator because the signal is firing, |
467 » » » » if(it->getdest() == pclass) | 412 // advance it to avoid it being invalidated. |
468 » » » » { | 413 if (m_current_iterator == it) { |
469 // If we're currently using this iterator because the signal is | 414 m_current_iterator = m_connected_slots.erase(it); |
470 // firing, advance it to avoid it being invalidated. | 415 } else { |
471 if (m_current_iterator == it) { | 416 m_connected_slots.erase(it); |
472 m_current_iterator = m_connected_slots.erase(it); | |
473 } else { | |
474 m_connected_slots.erase(it); | |
475 } | |
476 » » » » » pclass->signal_disconnect(static_cast< _
signal_base_interface* >(this)); | |
477 » » » » » return; | |
478 » » » » } | |
479 | |
480 » » » » ++it; | |
481 » » » } | |
482 » » } | |
483 | |
484 » private: | |
485 » » static void do_slot_disconnect(_signal_base_interface* p, has_sl
ots_interface* pslot) | |
486 » » { | |
487 » » » _signal_base* const self = static_cast< _signal_base* >(
p); | |
488 » » » lock_block<mt_policy> lock(self); | |
489 » » » connections_list::iterator it = self->m_connected_slots.
begin(); | |
490 » » » connections_list::iterator itEnd = self->m_connected_slo
ts.end(); | |
491 | |
492 » » » while(it != itEnd) | |
493 » » » { | |
494 » » » » connections_list::iterator itNext = it; | |
495 » » » » ++itNext; | |
496 | |
497 » » » » if(it->getdest() == pslot) | |
498 » » » » { | |
499 // If we're currently using this iterator because the signal is | |
500 // firing, advance it to avoid it being invalidated. | |
501 if (self->m_current_iterator == it) { | |
502 self->m_current_iterator = self->m_connected_slots.erase(it); | |
503 } else { | |
504 self->m_connected_slots.erase(it); | |
505 } | |
506 } | 417 } |
507 | 418 pclass->signal_disconnect(static_cast<_signal_base_interface*>(this)); |
508 » » » » it = itNext; | 419 return; |
509 » » » } | |
510 » » } | |
511 | |
512 » » static void do_slot_duplicate(_signal_base_interface* p, const h
as_slots_interface* oldtarget, has_slots_interface* newtarget) | |
513 » » { | |
514 » » » _signal_base* const self = static_cast< _signal_base* >(
p); | |
515 » » » lock_block<mt_policy> lock(self); | |
516 » » » connections_list::iterator it = self->m_connected_slots.
begin(); | |
517 » » » connections_list::iterator itEnd = self->m_connected_slo
ts.end(); | |
518 | |
519 » » » while(it != itEnd) | |
520 » » » { | |
521 » » » » if(it->getdest() == oldtarget) | |
522 » » » » { | |
523 » » » » » self->m_connected_slots.push_back(it->du
plicate(newtarget)); | |
524 » » » » } | |
525 | |
526 » » » » ++it; | |
527 » » » } | |
528 » » } | |
529 | |
530 » protected: | |
531 » » connections_list m_connected_slots; | |
532 | |
533 // Used to handle a slot being disconnected while a signal is | |
534 // firing (iterating m_connected_slots). | |
535 connections_list::iterator m_current_iterator; | |
536 }; | |
537 | |
538 » template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | |
539 » class has_slots : public has_slots_interface, public mt_policy | |
540 » { | |
541 » private: | |
542 » » typedef std::set< _signal_base_interface* > sender_set; | |
543 » » typedef sender_set::const_iterator const_iterator; | |
544 | |
545 » public: | |
546 » » has_slots() : has_slots_interface(&has_slots::do_signal_connect,
&has_slots::do_signal_disconnect, &has_slots::do_disconnect_all) | |
547 » » { | |
548 » » } | |
549 | |
550 » » has_slots(has_slots const& o) : has_slots_interface(&has_slots::
do_signal_connect, &has_slots::do_signal_disconnect, &has_slots::do_disconnect_a
ll) | |
551 { | |
552 » » » lock_block<mt_policy> lock(this); | |
553 for (auto* sender : o.m_senders) { | |
554 sender->slot_duplicate(&o, this); | |
555 m_senders.insert(sender); | |
556 } | 420 } |
557 } | 421 ++it; |
558 | 422 } |
559 ~has_slots() | 423 } |
560 { | 424 |
561 this->disconnect_all(); | 425 private: |
562 } | 426 static void do_slot_disconnect(_signal_base_interface* p, |
563 | 427 has_slots_interface* pslot) { |
564 private: | 428 _signal_base* const self = static_cast<_signal_base*>(p); |
565 has_slots& operator= (has_slots const&); | 429 lock_block<mt_policy> lock(self); |
566 | 430 connections_list::iterator it = self->m_connected_slots.begin(); |
567 static void do_signal_connect(has_slots_interface* p, _signal_ba
se_interface* sender) | 431 connections_list::iterator itEnd = self->m_connected_slots.end(); |
568 { | 432 |
569 has_slots* const self = static_cast< has_slots* >(p); | 433 while (it != itEnd) { |
570 lock_block<mt_policy> lock(self); | 434 connections_list::iterator itNext = it; |
571 self->m_senders.insert(sender); | 435 ++itNext; |
572 } | 436 |
573 | 437 if (it->getdest() == pslot) { |
574 static void do_signal_disconnect(has_slots_interface* p, _signal
_base_interface* sender) | 438 // If we're currently using this iterator because the signal is firing, |
575 { | 439 // advance it to avoid it being invalidated. |
576 has_slots* const self = static_cast< has_slots* >(p); | 440 if (self->m_current_iterator == it) { |
577 lock_block<mt_policy> lock(self); | 441 self->m_current_iterator = self->m_connected_slots.erase(it); |
578 self->m_senders.erase(sender); | 442 } else { |
579 } | 443 self->m_connected_slots.erase(it); |
580 | 444 } |
581 static void do_disconnect_all(has_slots_interface* p) | 445 } |
582 { | 446 |
583 has_slots* const self = static_cast< has_slots* >(p); | 447 it = itNext; |
584 lock_block<mt_policy> lock(self); | 448 } |
585 while (!self->m_senders.empty()) | 449 } |
586 { | 450 |
587 std::set< _signal_base_interface* > senders; | 451 static void do_slot_duplicate(_signal_base_interface* p, |
588 senders.swap(self->m_senders); | 452 const has_slots_interface* oldtarget, |
589 const_iterator it = senders.begin(); | 453 has_slots_interface* newtarget) { |
590 const_iterator itEnd = senders.end(); | 454 _signal_base* const self = static_cast<_signal_base*>(p); |
591 | 455 lock_block<mt_policy> lock(self); |
592 while(it != itEnd) | 456 connections_list::iterator it = self->m_connected_slots.begin(); |
593 { | 457 connections_list::iterator itEnd = self->m_connected_slots.end(); |
594 _signal_base_interface* s = *it; | 458 |
595 ++it; | 459 while (it != itEnd) { |
596 s->slot_disconnect(p); | 460 if (it->getdest() == oldtarget) { |
597 } | 461 self->m_connected_slots.push_back(it->duplicate(newtarget)); |
598 } | 462 } |
599 } | 463 |
600 | 464 ++it; |
601 private: | 465 } |
602 sender_set m_senders; | 466 } |
603 }; | 467 |
604 | 468 protected: |
605 template<class mt_policy, typename ... Args> | 469 connections_list m_connected_slots; |
606 class signal_with_thread_policy : public _signal_base<mt_policy> | 470 |
607 { | 471 // Used to handle a slot being disconnected while a signal is |
608 private: | 472 // firing (iterating m_connected_slots). |
609 typedef _signal_base<mt_policy> base; | 473 connections_list::iterator m_current_iterator; |
610 | 474 bool m_erase_current_iterator = false; |
611 protected: | 475 }; |
612 typedef typename base::connections_list connections_list; | 476 |
613 | 477 template <class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
614 public: | 478 class has_slots : public has_slots_interface, public mt_policy { |
615 signal_with_thread_policy() | 479 private: |
616 { | 480 typedef std::set<_signal_base_interface*> sender_set; |
617 } | 481 typedef sender_set::const_iterator const_iterator; |
618 | 482 |
619 template<class desttype> | 483 public: |
620 void connect(desttype* pclass, void (desttype::*pmemfun)(Args...
)) | 484 has_slots() |
621 { | 485 : has_slots_interface(&has_slots::do_signal_connect, |
622 lock_block<mt_policy> lock(this); | 486 &has_slots::do_signal_disconnect, |
623 this->m_connected_slots.push_back(_opaque_connection(pcl
ass, pmemfun)); | 487 &has_slots::do_disconnect_all) {} |
624 pclass->signal_connect(static_cast< _signal_base_interfa
ce* >(this)); | 488 |
625 } | 489 has_slots(has_slots const& o) |
626 | 490 : has_slots_interface(&has_slots::do_signal_connect, |
627 void emit(Args... args) | 491 &has_slots::do_signal_disconnect, |
628 { | 492 &has_slots::do_disconnect_all) { |
629 lock_block<mt_policy> lock(this); | 493 lock_block<mt_policy> lock(this); |
630 this->m_current_iterator = | 494 for (auto* sender : o.m_senders) { |
631 this->m_connected_slots.begin(); | 495 sender->slot_duplicate(&o, this); |
632 while (this->m_current_iterator != | 496 m_senders.insert(sender); |
633 this->m_connected_slots.end()) { | 497 } |
634 _opaque_connection const& conn = | 498 } |
635 *this->m_current_iterator; | 499 |
636 ++(this->m_current_iterator); | 500 ~has_slots() { this->disconnect_all(); } |
637 conn.emit<Args...>(args...); | 501 |
638 } | 502 private: |
639 } | 503 has_slots& operator=(has_slots const&); |
640 | 504 |
641 void operator()(Args... args) | 505 static void do_signal_connect(has_slots_interface* p, |
642 { | 506 _signal_base_interface* sender) { |
643 emit(args...); | 507 has_slots* const self = static_cast<has_slots*>(p); |
644 } | 508 lock_block<mt_policy> lock(self); |
645 }; | 509 self->m_senders.insert(sender); |
646 | 510 } |
647 // Alias with default thread policy. Needed because both default argumen
ts | 511 |
648 // and variadic template arguments must go at the end of the list, so we | 512 static void do_signal_disconnect(has_slots_interface* p, |
649 // can't have both at once. | 513 _signal_base_interface* sender) { |
650 template<typename ... Args> | 514 has_slots* const self = static_cast<has_slots*>(p); |
651 using signal = signal_with_thread_policy<SIGSLOT_DEFAULT_MT_POLICY, Args
...>; | 515 lock_block<mt_policy> lock(self); |
652 | 516 self->m_senders.erase(sender); |
653 // The previous verion of sigslot didn't use variadic templates, so you
would | 517 } |
654 // need to write "sigslot::signal2<Arg1, Arg2>", for example. | 518 |
655 // Now you can just write "sigslot::signal<Arg1, Arg2>", but these alias
es | 519 static void do_disconnect_all(has_slots_interface* p) { |
656 // exist for backwards compatibility. | 520 has_slots* const self = static_cast<has_slots*>(p); |
657 template<typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 521 lock_block<mt_policy> lock(self); |
658 using signal0 = signal_with_thread_policy<mt_policy>; | 522 while (!self->m_senders.empty()) { |
659 | 523 std::set<_signal_base_interface*> senders; |
660 template<typename A1, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 524 senders.swap(self->m_senders); |
661 using signal1 = signal_with_thread_policy<mt_policy, A1>; | 525 const_iterator it = senders.begin(); |
662 | 526 const_iterator itEnd = senders.end(); |
663 template<typename A1, typename A2, typename mt_policy = SIGSLOT_DEFAULT_
MT_POLICY> | 527 |
664 using signal2 = signal_with_thread_policy<mt_policy, A1, A2>; | 528 while (it != itEnd) { |
665 | 529 _signal_base_interface* s = *it; |
666 template<typename A1, typename A2, typename A3, typename mt_policy = SIG
SLOT_DEFAULT_MT_POLICY> | 530 ++it; |
667 using signal3 = signal_with_thread_policy<mt_policy, A1, A2, A3>; | 531 s->slot_disconnect(p); |
668 | 532 } |
669 template<typename A1, typename A2, typename A3, typename A4, typename mt
_policy = SIGSLOT_DEFAULT_MT_POLICY> | 533 } |
670 using signal4 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4>; | 534 } |
671 | 535 |
672 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 536 private: |
673 using signal5 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5>
; | 537 sender_set m_senders; |
674 | 538 }; |
675 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 539 |
676 using signal6 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6>; | 540 template <class mt_policy, typename... Args> |
677 | 541 class signal_with_thread_policy : public _signal_base<mt_policy> { |
678 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 542 private: |
679 using signal7 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7>; | 543 typedef _signal_base<mt_policy> base; |
680 | 544 |
681 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename A8, typename mt_policy = SIGSLOT_DEFAULT_MT
_POLICY> | 545 protected: |
682 using signal8 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7, A8>; | 546 typedef typename base::connections_list connections_list; |
683 | 547 |
684 } // namespace sigslot | 548 public: |
685 | 549 signal_with_thread_policy() {} |
686 #endif // WEBRTC_BASE_SIGSLOT_H__ | 550 |
| 551 template <class desttype> |
| 552 void connect(desttype* pclass, void (desttype::*pmemfun)(Args...)) { |
| 553 lock_block<mt_policy> lock(this); |
| 554 this->m_connected_slots.push_back(_opaque_connection(pclass, pmemfun)); |
| 555 pclass->signal_connect(static_cast<_signal_base_interface*>(this)); |
| 556 } |
| 557 |
| 558 void emit(Args... args) { |
| 559 lock_block<mt_policy> lock(this); |
| 560 this->m_current_iterator = this->m_connected_slots.begin(); |
| 561 while (this->m_current_iterator != this->m_connected_slots.end()) { |
| 562 _opaque_connection const& conn = *this->m_current_iterator; |
| 563 ++(this->m_current_iterator); |
| 564 conn.emit<Args...>(args...); |
| 565 } |
| 566 } |
| 567 |
| 568 void operator()(Args... args) { emit(args...); } |
| 569 }; |
| 570 |
| 571 // Alias with default thread policy. Needed because both default arguments |
| 572 // and variadic template arguments must go at the end of the list, so we |
| 573 // can't have both at once. |
| 574 template <typename... Args> |
| 575 using signal = signal_with_thread_policy<SIGSLOT_DEFAULT_MT_POLICY, Args...>; |
| 576 |
| 577 // The previous verion of sigslot didn't use variadic templates, so you would |
| 578 // need to write "sigslot::signal2<Arg1, Arg2>", for example. |
| 579 // Now you can just write "sigslot::signal<Arg1, Arg2>", but these aliases |
| 580 // exist for backwards compatibility. |
| 581 template <typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 582 using signal0 = signal_with_thread_policy<mt_policy>; |
| 583 |
| 584 template <typename A1, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 585 using signal1 = signal_with_thread_policy<mt_policy, A1>; |
| 586 |
| 587 template <typename A1, |
| 588 typename A2, |
| 589 typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 590 using signal2 = signal_with_thread_policy<mt_policy, A1, A2>; |
| 591 |
| 592 template <typename A1, |
| 593 typename A2, |
| 594 typename A3, |
| 595 typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 596 using signal3 = signal_with_thread_policy<mt_policy, A1, A2, A3>; |
| 597 |
| 598 template <typename A1, |
| 599 typename A2, |
| 600 typename A3, |
| 601 typename A4, |
| 602 typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 603 using signal4 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4>; |
| 604 |
| 605 template <typename A1, |
| 606 typename A2, |
| 607 typename A3, |
| 608 typename A4, |
| 609 typename A5, |
| 610 typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 611 using signal5 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5>; |
| 612 |
| 613 template <typename A1, |
| 614 typename A2, |
| 615 typename A3, |
| 616 typename A4, |
| 617 typename A5, |
| 618 typename A6, |
| 619 typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 620 using signal6 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6>; |
| 621 |
| 622 template <typename A1, |
| 623 typename A2, |
| 624 typename A3, |
| 625 typename A4, |
| 626 typename A5, |
| 627 typename A6, |
| 628 typename A7, |
| 629 typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 630 using signal7 = |
| 631 signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6, A7>; |
| 632 |
| 633 template <typename A1, |
| 634 typename A2, |
| 635 typename A3, |
| 636 typename A4, |
| 637 typename A5, |
| 638 typename A6, |
| 639 typename A7, |
| 640 typename A8, |
| 641 typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
| 642 using signal8 = |
| 643 signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6, A7, A8>; |
| 644 |
| 645 } // namespace sigslot |
| 646 |
| 647 #endif // WEBRTC_BASE_SIGSLOT_H__ |
OLD | NEW |