blob: c0fe5050fe2b2394c7762053cbad541b6bd2e754 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001// sigslot.h: Signal/Slot classes
2//
3// Written by Sarah Thompson (sarah@telergy.com) 2002.
4//
5// License: Public domain. You are free to use this code however you like, with the proviso that
6// the author takes on no responsibility or liability for any use.
7//
8// QUICK DOCUMENTATION
9//
10// (see also the full documentation at http://sigslot.sourceforge.net/)
11//
12// #define switches
13// SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables
14// all of the thread safety support on platforms where it is
15// available.
16//
17// SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than
18// gcc on a platform that supports Posix threads. (When using gcc,
19// this is the default - use SIGSLOT_PURE_ISO to disable this if
20// necessary)
21//
22// SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global.
23// Otherwise, the default is single_threaded. #define this yourself to
24// override the default. In pure ISO mode, anything other than
25// single_threaded will cause a compiler error.
26//
27// PLATFORM NOTES
28//
29// Win32 - On Win32, the WEBRTC_WIN symbol must be #defined. Most mainstream
30// compilers do this by default, but you may need to define it
31// yourself if your build environment is less standard. This causes
32// the Win32 thread support to be compiled in and used automatically.
33//
34// Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads
35// available, so they are used automatically. You can override this
36// (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using
37// something other than gcc but still want to use Posix threads, you
38// need to #define SIGSLOT_USE_POSIX_THREADS.
39//
40// ISO C++ - If none of the supported platforms are detected, or if
41// SIGSLOT_PURE_ISO is defined, all multithreading support is turned off,
42// along with any code that might cause a pure ISO C++ environment to
43// complain. Before you ask, gcc -ansi -pedantic won't compile this
44// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of
45// errors that aren't really there. If you feel like investigating this,
46// please contact the author.
47//
48//
49// THREADING MODES
50//
51// single_threaded - Your program is assumed to be single threaded from the point of view
52// of signal/slot usage (i.e. all objects using signals and slots are
53// created and destroyed from a single thread). Behaviour if objects are
54// destroyed concurrently is undefined (i.e. you'll get the occasional
55// segmentation fault/memory exception).
56//
57// multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and
58// slots can be safely created and destroyed from any thread, even when
59// connections exist. In multi_threaded_global mode, this is achieved by a
60// single global mutex (actually a critical section on Windows because they
61// are faster). This option uses less OS resources, but results in more
62// opportunities for contention, possibly resulting in more context switches
63// than are strictly necessary.
64//
65// multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global,
66// except that each signal, and each object that inherits has_slots, all
67// have their own mutex/critical section. In practice, this means that
68// mutex collisions (and hence context switches) only happen if they are
69// absolutely essential. However, on some platforms, creating a lot of
70// mutexes can slow down the whole OS, so use this option with care.
71//
72// USING THE LIBRARY
73//
74// See the full documentation at http://sigslot.sourceforge.net/
75//
76//
77// Libjingle specific:
78// 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
80// has_slots<single_threaded> and signal0<multi_threaded_local> or
81// 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
83// 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
85// or signal is not happening concurrently or data race may occur.
86
87#ifndef WEBRTC_BASE_SIGSLOT_H__
88#define WEBRTC_BASE_SIGSLOT_H__
89
deadbeef8d517c42017-02-19 14:12:24 -080090#include <cstring>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091#include <list>
92#include <set>
93#include <stdlib.h>
94
95// On our copy of sigslot.h, we set single threading as default.
96#define SIGSLOT_DEFAULT_MT_POLICY single_threaded
97
98#if defined(SIGSLOT_PURE_ISO) || (!defined(WEBRTC_WIN) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS))
99# define _SIGSLOT_SINGLE_THREADED
100#elif defined(WEBRTC_WIN)
101# define _SIGSLOT_HAS_WIN32_THREADS
102# if !defined(WIN32_LEAN_AND_MEAN)
103# define WIN32_LEAN_AND_MEAN
104# endif
105# include "webrtc/base/win32.h"
106#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS)
107# define _SIGSLOT_HAS_POSIX_THREADS
108# include <pthread.h>
109#else
110# define _SIGSLOT_SINGLE_THREADED
111#endif
112
113#ifndef SIGSLOT_DEFAULT_MT_POLICY
114# ifdef _SIGSLOT_SINGLE_THREADED
115# define SIGSLOT_DEFAULT_MT_POLICY single_threaded
116# else
117# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local
118# endif
119#endif
120
121// TODO: change this namespace to rtc?
122namespace sigslot {
123
124 class single_threaded
125 {
126 public:
deadbeef8d517c42017-02-19 14:12:24 -0800127 void lock() {}
128 void unlock() {}
129 };
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000130
131#ifdef _SIGSLOT_HAS_WIN32_THREADS
132 // The multi threading policies only get compiled in if they are enabled.
133 class multi_threaded_global
134 {
135 public:
136 multi_threaded_global()
137 {
138 static bool isinitialised = false;
139
140 if(!isinitialised)
141 {
142 InitializeCriticalSection(get_critsec());
143 isinitialised = true;
144 }
145 }
146
deadbeef8d517c42017-02-19 14:12:24 -0800147 void lock()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148 {
149 EnterCriticalSection(get_critsec());
150 }
151
deadbeef8d517c42017-02-19 14:12:24 -0800152 void unlock()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153 {
154 LeaveCriticalSection(get_critsec());
155 }
156
157 private:
158 CRITICAL_SECTION* get_critsec()
159 {
160 static CRITICAL_SECTION g_critsec;
161 return &g_critsec;
162 }
163 };
164
165 class multi_threaded_local
166 {
167 public:
168 multi_threaded_local()
169 {
170 InitializeCriticalSection(&m_critsec);
171 }
172
173 multi_threaded_local(const multi_threaded_local&)
174 {
175 InitializeCriticalSection(&m_critsec);
176 }
177
deadbeef8d517c42017-02-19 14:12:24 -0800178 ~multi_threaded_local()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000179 {
180 DeleteCriticalSection(&m_critsec);
181 }
182
deadbeef8d517c42017-02-19 14:12:24 -0800183 void lock()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000184 {
185 EnterCriticalSection(&m_critsec);
186 }
187
deadbeef8d517c42017-02-19 14:12:24 -0800188 void unlock()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000189 {
190 LeaveCriticalSection(&m_critsec);
191 }
192
193 private:
194 CRITICAL_SECTION m_critsec;
195 };
196#endif // _SIGSLOT_HAS_WIN32_THREADS
197
198#ifdef _SIGSLOT_HAS_POSIX_THREADS
199 // The multi threading policies only get compiled in if they are enabled.
200 class multi_threaded_global
201 {
202 public:
deadbeef8d517c42017-02-19 14:12:24 -0800203 void lock()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000204 {
deadbeef8d517c42017-02-19 14:12:24 -0800205 pthread_mutex_lock(get_mutex());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000206 }
deadbeef8d517c42017-02-19 14:12:24 -0800207 void unlock()
208 {
209 pthread_mutex_unlock(get_mutex());
210 }
211
212 private:
213 static pthread_mutex_t* get_mutex();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000214 };
215
216 class multi_threaded_local
217 {
218 public:
deadbeef37f5ecf2017-02-27 14:06:41 -0800219 multi_threaded_local() { pthread_mutex_init(&m_mutex, nullptr); }
220 multi_threaded_local(const multi_threaded_local&) {
221 pthread_mutex_init(&m_mutex, nullptr);
deadbeef8d517c42017-02-19 14:12:24 -0800222 }
223 ~multi_threaded_local()
224 {
225 pthread_mutex_destroy(&m_mutex);
226 }
227 void lock()
228 {
229 pthread_mutex_lock(&m_mutex);
230 }
231 void unlock()
232 {
233 pthread_mutex_unlock(&m_mutex);
234 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000235
deadbeef8d517c42017-02-19 14:12:24 -0800236 private:
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000237 pthread_mutex_t m_mutex;
238 };
239#endif // _SIGSLOT_HAS_POSIX_THREADS
240
241 template<class mt_policy>
242 class lock_block
243 {
244 public:
245 mt_policy *m_mutex;
246
247 lock_block(mt_policy *mtx)
248 : m_mutex(mtx)
249 {
250 m_mutex->lock();
251 }
252
253 ~lock_block()
254 {
255 m_mutex->unlock();
256 }
257 };
258
deadbeef8d517c42017-02-19 14:12:24 -0800259 class _signal_base_interface;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000260
deadbeef8d517c42017-02-19 14:12:24 -0800261 class has_slots_interface
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000262 {
deadbeef8d517c42017-02-19 14:12:24 -0800263 private:
264 typedef void (*signal_connect_t)(has_slots_interface* self, _signal_base_interface* sender);
265 typedef void (*signal_disconnect_t)(has_slots_interface* self, _signal_base_interface* sender);
266 typedef void (*disconnect_all_t)(has_slots_interface* self);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000267
deadbeef8d517c42017-02-19 14:12:24 -0800268 const signal_connect_t m_signal_connect;
269 const signal_disconnect_t m_signal_disconnect;
270 const disconnect_all_t m_disconnect_all;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000271
deadbeef8d517c42017-02-19 14:12:24 -0800272 protected:
273 has_slots_interface(signal_connect_t conn, signal_disconnect_t disc, disconnect_all_t disc_all) :
274 m_signal_connect(conn), m_signal_disconnect(disc), m_disconnect_all(disc_all)
275 {
276 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000277
deadbeef8d517c42017-02-19 14:12:24 -0800278 // Doesn't really need to be virtual, but is for backwards compatibility
279 // (it was virtual in a previous version of sigslot).
280 virtual ~has_slots_interface() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000281
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000282 public:
deadbeef8d517c42017-02-19 14:12:24 -0800283 void signal_connect(_signal_base_interface* sender)
284 {
285 m_signal_connect(this, sender);
286 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000287
deadbeef8d517c42017-02-19 14:12:24 -0800288 void signal_disconnect(_signal_base_interface* sender)
289 {
290 m_signal_disconnect(this, sender);
291 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000292
deadbeef8d517c42017-02-19 14:12:24 -0800293 void disconnect_all()
294 {
295 m_disconnect_all(this);
296 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000297 };
298
299 class _signal_base_interface
300 {
deadbeef8d517c42017-02-19 14:12:24 -0800301 private:
302 typedef void (*slot_disconnect_t)(_signal_base_interface* self, has_slots_interface* pslot);
303 typedef void (*slot_duplicate_t)(_signal_base_interface* self, const has_slots_interface* poldslot, has_slots_interface* pnewslot);
304
305 const slot_disconnect_t m_slot_disconnect;
306 const slot_duplicate_t m_slot_duplicate;
307
308 protected:
309 _signal_base_interface(slot_disconnect_t disc, slot_duplicate_t dupl) :
310 m_slot_disconnect(disc), m_slot_duplicate(dupl)
311 {
312 }
313
314 ~_signal_base_interface() {}
315
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000316 public:
deadbeef8d517c42017-02-19 14:12:24 -0800317 void slot_disconnect(has_slots_interface* pslot)
318 {
319 m_slot_disconnect(this, pslot);
320 }
321
322 void slot_duplicate(const has_slots_interface* poldslot, has_slots_interface* pnewslot)
323 {
324 m_slot_duplicate(this, poldslot, pnewslot);
325 }
326 };
327
328 class _opaque_connection
329 {
330 private:
331 typedef void (*emit_t)(const _opaque_connection*);
332 template< typename FromT, typename ToT >
333 union union_caster
334 {
335 FromT from;
336 ToT to;
337 };
338
339 emit_t pemit;
340 has_slots_interface* pdest;
341 // Pointers to member functions may be up to 16 bytes for virtual classes,
342 // so make sure we have enough space to store it.
343 unsigned char pmethod[16];
344
345 public:
346 template< typename DestT, typename ... Args >
347 _opaque_connection(DestT* pd, void (DestT::*pm)(Args...)) : pdest(pd)
348 {
349 typedef void (DestT::*pm_t)(Args...);
350 static_assert(sizeof(pm_t) <= sizeof(pmethod), "Size of slot function pointer too large.");
351
352 std::memcpy(pmethod, &pm, sizeof(pm_t));
353
354 typedef void (*em_t)(const _opaque_connection* self, Args...);
355 union_caster< em_t, emit_t > caster2;
356 caster2.from = &_opaque_connection::emitter< DestT, Args... >;
357 pemit = caster2.to;
358 }
359
360 has_slots_interface* getdest() const { return pdest; }
361
362 _opaque_connection duplicate(has_slots_interface* newtarget) const
363 {
364 _opaque_connection res = *this;
365 res.pdest = newtarget;
366 return res;
367 }
368
369 // Just calls the stored "emitter" function pointer stored at construction
370 // time.
371 template< typename ... Args >
372 void emit(Args... args) const
373 {
374 typedef void (*em_t)(const _opaque_connection*, Args...);
375 union_caster< emit_t, em_t > caster;
376 caster.from = pemit;
377 (caster.to)(this, args...);
378 }
379
380 private:
381 template< typename DestT, typename ... Args >
382 static void emitter(const _opaque_connection* self, Args... args)
383 {
384 typedef void (DestT::*pm_t)(Args...);
385 pm_t pm;
386 std::memcpy(&pm, self->pmethod, sizeof(pm_t));
387 (static_cast< DestT* >(self->pdest)->*(pm))(args...);
388 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000389 };
390
391 template<class mt_policy>
392 class _signal_base : public _signal_base_interface, public mt_policy
393 {
deadbeef8d517c42017-02-19 14:12:24 -0800394 protected:
395 typedef std::list< _opaque_connection > connections_list;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000396
deadbeef4483af32017-05-12 08:44:38 -0700397 _signal_base() : _signal_base_interface(&_signal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate),
398 m_current_iterator(m_connected_slots.end())
deadbeef8d517c42017-02-19 14:12:24 -0800399 {
400 }
401
402 ~_signal_base()
403 {
404 disconnect_all();
405 }
406
407 private:
408 _signal_base& operator= (_signal_base const& that);
409
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000410 public:
deadbeef4483af32017-05-12 08:44:38 -0700411 _signal_base(const _signal_base& o) : _signal_base_interface(&_signal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate),
412 m_current_iterator(m_connected_slots.end()) {
deadbeef8d517c42017-02-19 14:12:24 -0800413 lock_block<mt_policy> lock(this);
deadbeef8b1d8622017-04-29 00:27:04 -0700414 for (const auto& connection : o.m_connected_slots)
deadbeef8d517c42017-02-19 14:12:24 -0800415 {
deadbeef8b1d8622017-04-29 00:27:04 -0700416 connection.getdest()->signal_connect(this);
417 m_connected_slots.push_back(connection);
deadbeef8d517c42017-02-19 14:12:24 -0800418 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000419 }
420
deadbeef8d517c42017-02-19 14:12:24 -0800421 bool is_empty()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000422 {
deadbeef8d517c42017-02-19 14:12:24 -0800423 lock_block<mt_policy> lock(this);
424 return m_connected_slots.empty();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000425 }
426
deadbeef8d517c42017-02-19 14:12:24 -0800427 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.front().getdest();
434 m_connected_slots.pop_front();
435 pdest->signal_disconnect(static_cast< _signal_base_interface* >(this));
436 }
deadbeef4483af32017-05-12 08:44:38 -0700437 // 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();
deadbeef8d517c42017-02-19 14:12:24 -0800441 }
442
443#if !defined(NDEBUG)
444 bool connected(has_slots_interface* pclass)
445 {
446 lock_block<mt_policy> lock(this);
447 connections_list::const_iterator it = m_connected_slots.begin();
448 connections_list::const_iterator itEnd = m_connected_slots.end();
449 while(it != itEnd)
450 {
451 if (it->getdest() == pclass)
452 return true;
453 ++it;
454 }
455 return false;
456 }
457#endif
458
459 void disconnect(has_slots_interface* pclass)
460 {
461 lock_block<mt_policy> lock(this);
462 connections_list::iterator it = m_connected_slots.begin();
463 connections_list::iterator itEnd = m_connected_slots.end();
464
465 while(it != itEnd)
466 {
467 if(it->getdest() == pclass)
468 {
deadbeef4483af32017-05-12 08:44:38 -0700469 // If we're currently using this iterator because the signal is
470 // firing, advance it to avoid it being invalidated.
471 if (m_current_iterator == it) {
472 m_current_iterator = m_connected_slots.erase(it);
473 } else {
474 m_connected_slots.erase(it);
475 }
deadbeef8d517c42017-02-19 14:12:24 -0800476 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_slots_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_slots.end();
491
492 while(it != itEnd)
493 {
494 connections_list::iterator itNext = it;
495 ++itNext;
496
497 if(it->getdest() == pslot)
498 {
deadbeef4483af32017-05-12 08:44:38 -0700499 // 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 }
deadbeef8d517c42017-02-19 14:12:24 -0800507
508 it = itNext;
509 }
510 }
511
512 static void do_slot_duplicate(_signal_base_interface* p, const has_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_slots.end();
518
519 while(it != itEnd)
520 {
521 if(it->getdest() == oldtarget)
522 {
523 self->m_connected_slots.push_back(it->duplicate(newtarget));
524 }
525
526 ++it;
527 }
528 }
529
530 protected:
531 connections_list m_connected_slots;
deadbeef4483af32017-05-12 08:44:38 -0700532
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 };
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000537
538 template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
539 class has_slots : public has_slots_interface, public mt_policy
540 {
541 private:
deadbeef8d517c42017-02-19 14:12:24 -0800542 typedef std::set< _signal_base_interface* > sender_set;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000543 typedef sender_set::const_iterator const_iterator;
544
545 public:
deadbeef8d517c42017-02-19 14:12:24 -0800546 has_slots() : has_slots_interface(&has_slots::do_signal_connect, &has_slots::do_signal_disconnect, &has_slots::do_disconnect_all)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000547 {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000548 }
549
deadbeef8b1d8622017-04-29 00:27:04 -0700550 has_slots(has_slots const& o) : has_slots_interface(&has_slots::do_signal_connect, &has_slots::do_signal_disconnect, &has_slots::do_disconnect_all)
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 }
557 }
558
deadbeef8d517c42017-02-19 14:12:24 -0800559 ~has_slots()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000560 {
deadbeef8d517c42017-02-19 14:12:24 -0800561 this->disconnect_all();
562 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000563
deadbeef8d517c42017-02-19 14:12:24 -0800564 private:
deadbeef8d517c42017-02-19 14:12:24 -0800565 has_slots& operator= (has_slots const&);
566
567 static void do_signal_connect(has_slots_interface* p, _signal_base_interface* sender)
568 {
569 has_slots* const self = static_cast< has_slots* >(p);
570 lock_block<mt_policy> lock(self);
571 self->m_senders.insert(sender);
572 }
573
574 static void do_signal_disconnect(has_slots_interface* p, _signal_base_interface* sender)
575 {
576 has_slots* const self = static_cast< has_slots* >(p);
577 lock_block<mt_policy> lock(self);
578 self->m_senders.erase(sender);
579 }
580
581 static void do_disconnect_all(has_slots_interface* p)
582 {
583 has_slots* const self = static_cast< has_slots* >(p);
584 lock_block<mt_policy> lock(self);
585 while (!self->m_senders.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000586 {
deadbeef8d517c42017-02-19 14:12:24 -0800587 std::set< _signal_base_interface* > senders;
588 senders.swap(self->m_senders);
589 const_iterator it = senders.begin();
590 const_iterator itEnd = senders.end();
591
592 while(it != itEnd)
593 {
594 _signal_base_interface* s = *it;
595 ++it;
596 s->slot_disconnect(p);
597 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000598 }
599 }
600
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000601 private:
602 sender_set m_senders;
603 };
604
deadbeef8d517c42017-02-19 14:12:24 -0800605 template<class mt_policy, typename ... Args>
606 class signal_with_thread_policy : public _signal_base<mt_policy>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000607 {
deadbeef8d517c42017-02-19 14:12:24 -0800608 private:
609 typedef _signal_base<mt_policy> base;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000610
611 protected:
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000612 typedef typename base::connections_list connections_list;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000613
deadbeef8d517c42017-02-19 14:12:24 -0800614 public:
615 signal_with_thread_policy()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000616 {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000617 }
618
619 template<class desttype>
deadbeef8d517c42017-02-19 14:12:24 -0800620 void connect(desttype* pclass, void (desttype::*pmemfun)(Args...))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000621 {
622 lock_block<mt_policy> lock(this);
deadbeef8d517c42017-02-19 14:12:24 -0800623 this->m_connected_slots.push_back(_opaque_connection(pclass, pmemfun));
624 pclass->signal_connect(static_cast< _signal_base_interface* >(this));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000625 }
626
deadbeef8d517c42017-02-19 14:12:24 -0800627 void emit(Args... args)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000628 {
629 lock_block<mt_policy> lock(this);
deadbeef4483af32017-05-12 08:44:38 -0700630 this->m_current_iterator =
631 this->m_connected_slots.begin();
632 while (this->m_current_iterator !=
633 this->m_connected_slots.end()) {
634 _opaque_connection const& conn =
635 *this->m_current_iterator;
636 ++(this->m_current_iterator);
637 conn.emit<Args...>(args...);
638 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000639 }
640
deadbeef8d517c42017-02-19 14:12:24 -0800641 void operator()(Args... args)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000642 {
deadbeef8d517c42017-02-19 14:12:24 -0800643 emit(args...);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000644 }
645 };
646
deadbeef8d517c42017-02-19 14:12:24 -0800647 // Alias with default thread policy. Needed because both default arguments
648 // and variadic template arguments must go at the end of the list, so we
649 // can't have both at once.
650 template<typename ... Args>
651 using signal = signal_with_thread_policy<SIGSLOT_DEFAULT_MT_POLICY, Args...>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000652
deadbeef8d517c42017-02-19 14:12:24 -0800653 // The previous verion of sigslot didn't use variadic templates, so you would
654 // need to write "sigslot::signal2<Arg1, Arg2>", for example.
655 // Now you can just write "sigslot::signal<Arg1, Arg2>", but these aliases
656 // exist for backwards compatibility.
657 template<typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
658 using signal0 = signal_with_thread_policy<mt_policy>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000659
deadbeef8d517c42017-02-19 14:12:24 -0800660 template<typename A1, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
661 using signal1 = signal_with_thread_policy<mt_policy, A1>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000662
deadbeef8d517c42017-02-19 14:12:24 -0800663 template<typename A1, typename A2, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
664 using signal2 = signal_with_thread_policy<mt_policy, A1, A2>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000665
deadbeef8d517c42017-02-19 14:12:24 -0800666 template<typename A1, typename A2, typename A3, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
667 using signal3 = signal_with_thread_policy<mt_policy, A1, A2, A3>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000668
deadbeef8d517c42017-02-19 14:12:24 -0800669 template<typename A1, typename A2, typename A3, typename A4, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
670 using signal4 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000671
deadbeef8d517c42017-02-19 14:12:24 -0800672 template<typename A1, typename A2, typename A3, typename A4, typename A5, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
673 using signal5 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000674
deadbeef8d517c42017-02-19 14:12:24 -0800675 template<typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
676 using signal6 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000677
deadbeef8d517c42017-02-19 14:12:24 -0800678 template<typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
679 using signal7 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6, A7>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000680
deadbeef8d517c42017-02-19 14:12:24 -0800681 template<typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
682 using signal8 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6, A7, A8>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000683
deadbeef8d517c42017-02-19 14:12:24 -0800684} // namespace sigslot
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000685
686#endif // WEBRTC_BASE_SIGSLOT_H__