blob: 45e0da216bf5c4acc09dd47f4e11c54edfbd2165 [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
perkjde159092017-05-02 06:14:59 -0700397 _signal_base() : _signal_base_interface(&_signal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate)
deadbeef8d517c42017-02-19 14:12:24 -0800398 {
399 }
400
401 ~_signal_base()
402 {
403 disconnect_all();
404 }
405
406 private:
407 _signal_base& operator= (_signal_base const& that);
408
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000409 public:
perkjde159092017-05-02 06:14:59 -0700410 _signal_base(const _signal_base& o) : _signal_base_interface(&_signal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate) {
deadbeef8d517c42017-02-19 14:12:24 -0800411 lock_block<mt_policy> lock(this);
deadbeef8b1d8622017-04-29 00:27:04 -0700412 for (const auto& connection : o.m_connected_slots)
deadbeef8d517c42017-02-19 14:12:24 -0800413 {
deadbeef8b1d8622017-04-29 00:27:04 -0700414 connection.getdest()->signal_connect(this);
415 m_connected_slots.push_back(connection);
deadbeef8d517c42017-02-19 14:12:24 -0800416 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000417 }
418
deadbeef8d517c42017-02-19 14:12:24 -0800419 bool is_empty()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000420 {
deadbeef8d517c42017-02-19 14:12:24 -0800421 lock_block<mt_policy> lock(this);
422 return m_connected_slots.empty();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000423 }
424
deadbeef8d517c42017-02-19 14:12:24 -0800425 void disconnect_all()
426 {
427 lock_block<mt_policy> lock(this);
428
429 while(!m_connected_slots.empty())
430 {
431 has_slots_interface* pdest = m_connected_slots.front().getdest();
432 m_connected_slots.pop_front();
433 pdest->signal_disconnect(static_cast< _signal_base_interface* >(this));
434 }
435 }
436
437#if !defined(NDEBUG)
438 bool connected(has_slots_interface* pclass)
439 {
440 lock_block<mt_policy> lock(this);
441 connections_list::const_iterator it = m_connected_slots.begin();
442 connections_list::const_iterator itEnd = m_connected_slots.end();
443 while(it != itEnd)
444 {
445 if (it->getdest() == pclass)
446 return true;
447 ++it;
448 }
449 return false;
450 }
451#endif
452
453 void disconnect(has_slots_interface* pclass)
454 {
455 lock_block<mt_policy> lock(this);
456 connections_list::iterator it = m_connected_slots.begin();
457 connections_list::iterator itEnd = m_connected_slots.end();
458
459 while(it != itEnd)
460 {
461 if(it->getdest() == pclass)
462 {
perkjde159092017-05-02 06:14:59 -0700463 m_connected_slots.erase(it);
deadbeef8d517c42017-02-19 14:12:24 -0800464 pclass->signal_disconnect(static_cast< _signal_base_interface* >(this));
465 return;
466 }
467
468 ++it;
469 }
470 }
471
472 private:
473 static void do_slot_disconnect(_signal_base_interface* p, has_slots_interface* pslot)
474 {
475 _signal_base* const self = static_cast< _signal_base* >(p);
476 lock_block<mt_policy> lock(self);
477 connections_list::iterator it = self->m_connected_slots.begin();
478 connections_list::iterator itEnd = self->m_connected_slots.end();
479
480 while(it != itEnd)
481 {
482 connections_list::iterator itNext = it;
483 ++itNext;
484
485 if(it->getdest() == pslot)
486 {
perkjde159092017-05-02 06:14:59 -0700487 self->m_connected_slots.erase(it);
488 }
deadbeef8d517c42017-02-19 14:12:24 -0800489
490 it = itNext;
491 }
492 }
493
494 static void do_slot_duplicate(_signal_base_interface* p, const has_slots_interface* oldtarget, has_slots_interface* newtarget)
495 {
496 _signal_base* const self = static_cast< _signal_base* >(p);
497 lock_block<mt_policy> lock(self);
498 connections_list::iterator it = self->m_connected_slots.begin();
499 connections_list::iterator itEnd = self->m_connected_slots.end();
500
501 while(it != itEnd)
502 {
503 if(it->getdest() == oldtarget)
504 {
505 self->m_connected_slots.push_back(it->duplicate(newtarget));
506 }
507
508 ++it;
509 }
510 }
511
512 protected:
513 connections_list m_connected_slots;
perkjde159092017-05-02 06:14:59 -0700514 };
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000515
516 template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
517 class has_slots : public has_slots_interface, public mt_policy
518 {
519 private:
deadbeef8d517c42017-02-19 14:12:24 -0800520 typedef std::set< _signal_base_interface* > sender_set;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000521 typedef sender_set::const_iterator const_iterator;
522
523 public:
deadbeef8d517c42017-02-19 14:12:24 -0800524 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 +0000525 {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000526 }
527
deadbeef8b1d8622017-04-29 00:27:04 -0700528 has_slots(has_slots const& o) : has_slots_interface(&has_slots::do_signal_connect, &has_slots::do_signal_disconnect, &has_slots::do_disconnect_all)
529 {
530 lock_block<mt_policy> lock(this);
531 for (auto* sender : o.m_senders) {
532 sender->slot_duplicate(&o, this);
533 m_senders.insert(sender);
534 }
535 }
536
deadbeef8d517c42017-02-19 14:12:24 -0800537 ~has_slots()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000538 {
deadbeef8d517c42017-02-19 14:12:24 -0800539 this->disconnect_all();
540 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000541
deadbeef8d517c42017-02-19 14:12:24 -0800542 private:
deadbeef8d517c42017-02-19 14:12:24 -0800543 has_slots& operator= (has_slots const&);
544
545 static void do_signal_connect(has_slots_interface* p, _signal_base_interface* sender)
546 {
547 has_slots* const self = static_cast< has_slots* >(p);
548 lock_block<mt_policy> lock(self);
549 self->m_senders.insert(sender);
550 }
551
552 static void do_signal_disconnect(has_slots_interface* p, _signal_base_interface* sender)
553 {
554 has_slots* const self = static_cast< has_slots* >(p);
555 lock_block<mt_policy> lock(self);
556 self->m_senders.erase(sender);
557 }
558
559 static void do_disconnect_all(has_slots_interface* p)
560 {
561 has_slots* const self = static_cast< has_slots* >(p);
562 lock_block<mt_policy> lock(self);
563 while (!self->m_senders.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000564 {
deadbeef8d517c42017-02-19 14:12:24 -0800565 std::set< _signal_base_interface* > senders;
566 senders.swap(self->m_senders);
567 const_iterator it = senders.begin();
568 const_iterator itEnd = senders.end();
569
570 while(it != itEnd)
571 {
572 _signal_base_interface* s = *it;
573 ++it;
574 s->slot_disconnect(p);
575 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000576 }
577 }
578
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000579 private:
580 sender_set m_senders;
581 };
582
deadbeef8d517c42017-02-19 14:12:24 -0800583 template<class mt_policy, typename ... Args>
584 class signal_with_thread_policy : public _signal_base<mt_policy>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000585 {
deadbeef8d517c42017-02-19 14:12:24 -0800586 private:
587 typedef _signal_base<mt_policy> base;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000588
589 protected:
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000590 typedef typename base::connections_list connections_list;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000591
deadbeef8d517c42017-02-19 14:12:24 -0800592 public:
593 signal_with_thread_policy()
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000594 {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000595 }
596
597 template<class desttype>
deadbeef8d517c42017-02-19 14:12:24 -0800598 void connect(desttype* pclass, void (desttype::*pmemfun)(Args...))
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000599 {
600 lock_block<mt_policy> lock(this);
deadbeef8d517c42017-02-19 14:12:24 -0800601 this->m_connected_slots.push_back(_opaque_connection(pclass, pmemfun));
602 pclass->signal_connect(static_cast< _signal_base_interface* >(this));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000603 }
604
deadbeef8d517c42017-02-19 14:12:24 -0800605 void emit(Args... args)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000606 {
607 lock_block<mt_policy> lock(this);
perkjde159092017-05-02 06:14:59 -0700608 typename connections_list::const_iterator it = this->m_connected_slots.begin();
609 typename connections_list::const_iterator itEnd = this->m_connected_slots.end();
610
611 while(it != itEnd)
612 {
613 _opaque_connection const& conn = *it;
614 ++it;
615
616 conn.emit<Args...>(args...);
617 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000618 }
619
deadbeef8d517c42017-02-19 14:12:24 -0800620 void operator()(Args... args)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000621 {
deadbeef8d517c42017-02-19 14:12:24 -0800622 emit(args...);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000623 }
624 };
625
deadbeef8d517c42017-02-19 14:12:24 -0800626 // Alias with default thread policy. Needed because both default arguments
627 // and variadic template arguments must go at the end of the list, so we
628 // can't have both at once.
629 template<typename ... Args>
630 using signal = signal_with_thread_policy<SIGSLOT_DEFAULT_MT_POLICY, Args...>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000631
deadbeef8d517c42017-02-19 14:12:24 -0800632 // The previous verion of sigslot didn't use variadic templates, so you would
633 // need to write "sigslot::signal2<Arg1, Arg2>", for example.
634 // Now you can just write "sigslot::signal<Arg1, Arg2>", but these aliases
635 // exist for backwards compatibility.
636 template<typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
637 using signal0 = signal_with_thread_policy<mt_policy>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000638
deadbeef8d517c42017-02-19 14:12:24 -0800639 template<typename A1, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
640 using signal1 = signal_with_thread_policy<mt_policy, A1>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000641
deadbeef8d517c42017-02-19 14:12:24 -0800642 template<typename A1, typename A2, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
643 using signal2 = signal_with_thread_policy<mt_policy, A1, A2>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000644
deadbeef8d517c42017-02-19 14:12:24 -0800645 template<typename A1, typename A2, typename A3, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
646 using signal3 = signal_with_thread_policy<mt_policy, A1, A2, A3>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000647
deadbeef8d517c42017-02-19 14:12:24 -0800648 template<typename A1, typename A2, typename A3, typename A4, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
649 using signal4 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000650
deadbeef8d517c42017-02-19 14:12:24 -0800651 template<typename A1, typename A2, typename A3, typename A4, typename A5, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
652 using signal5 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000653
deadbeef8d517c42017-02-19 14:12:24 -0800654 template<typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
655 using signal6 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000656
deadbeef8d517c42017-02-19 14:12:24 -0800657 template<typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
658 using signal7 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6, A7>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000659
deadbeef8d517c42017-02-19 14:12:24 -0800660 template<typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
661 using signal8 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6, A7, A8>;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000662
deadbeef8d517c42017-02-19 14:12:24 -0800663} // namespace sigslot
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000664
665#endif // WEBRTC_BASE_SIGSLOT_H__