sigslot.h 59.7 KB
Newer Older
schultezub's avatar
schultezub committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
 
 sigslot.h: Signal/Slot classes
 
 Written by Sarah Thompson (sarah@telergy.com) 2002.
 
 License: Public domain. You are free to use this code however you like,
          with the proviso that the author takes on no responsibility or
          liability for any use.
 
 QUICK DOCUMENTATION
 
 (see also the full documentation at http://sigslot.sourceforge.net/)
 
 1. #define switches

    SIGSLOT_PURE_ISO:
    Define this to force ISO C++ compliance. This also disables
    all of the thread safety support on platforms where it is 
    available.
 
    SIGSLOT_USE_POSIX_THREADS:
    Force use of Posix threads when using a C++ compiler other than
    gcc on a platform that supports Posix threads. (When using gcc,
    this is the default - use SIGSLOT_PURE_ISO to disable this if 
    necessary)
 
    SIGSLOT_DEFAULT_MT_POLICY:
    Where thread support is enabled, this defaults to multi_threaded_global.
    Otherwise, the default is single_threaded. #define this yourself to
    override the default. In pure ISO mode, anything other than
    single_threaded will cause a compiler error.

 2. PLATFORM NOTES
 
    Win32:
    On Win32, the WIN32 symbol must be #defined. Most mainstream
    compilers do this by default, but you may need to define it
    yourself if your build environment is less standard. This causes
    the Win32 thread support to be compiled in and used automatically.
 
    Unix/Linux/BSD, etc:
    If you're using gcc, it is assumed that you have Posix threads
    available, so they are used automatically. You can override this
    (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using
    something other than gcc but still want to use Posix threads, you
    need to #define SIGSLOT_USE_POSIX_THREADS.
 
    ISO C++:
    If none of the supported platforms are detected, or if
    SIGSLOT_PURE_ISO is defined, all multithreading support is turned off,
    along with any code that might cause a pure ISO C++ environment to
    complain. Before you ask, gcc -ansi -pedantic won't compile this 
    library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of
    errors that aren't really there. If you feel like investigating this,
    please contact the author.
      
 THREADING MODES
 
    single_threaded:
    Your program is assumed to be single threaded from the point of view
    of signal/slot usage (i.e. all objects using signals and slots are
    created and destroyed from a single thread). Behaviour if objects are
    destroyed concurrently is undefined (i.e. you'll get the occasional
    segmentation fault/memory exception).
 
    multi_threaded_global:
    Your program is assumed to be multi threaded. Objects using signals and
    slots can be safely created and destroyed from any thread, even when
    connections exist. In multi_threaded_global mode, this is achieved by a
    single global mutex (actually a critical section on Windows because they
    are faster). This option uses less OS resources, but results in more
    opportunities for contention, possibly resulting in more context switches
    than are strictly necessary.
 
    multi_threaded_local:
    Behaviour in this mode is essentially the same as multi_threaded_global,
    except that each signal, and each object that inherits has_slots, all 
    have their own mutex/critical section. In practice, this means that
    mutex collisions (and hence context switches) only happen if they are
    absolutely essential. However, on some platforms, creating a lot of 
    mutexes can slow down the whole OS, so use this option with care.
 
 USING THE LIBRARY
 
 See the full documentation at http://sigslot.sourceforge.net/
 
*/
schultezub's avatar
schultezub committed
89

schultezub's avatar
schultezub committed
90
91
#ifndef SIGSLOT_H
#define SIGSLOT_H
schultezub's avatar
schultezub committed
92

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

#ifdef CAMPVIS_DYNAMIC_LIBS
    #ifdef SIGSLOT_BUILD_DLL
        // building library -> export symbols
        #ifdef WIN32
            #define SIGSLOT_API __declspec(dllexport)
        #else
            #define SIGSLOT_API
        #endif
    #else
        // including library -> import symbols
        #ifdef WIN32
            #define SIGSLOT_API __declspec(dllimport)
        #else
            #define SIGSLOT_API
        #endif
    #endif
#else
    // building/including static library -> do nothing
    #define SIGSLOT_API
#endif


schultezub's avatar
schultezub committed
116
117
#include <set>
#include <list>
118

119
#include "tgt/assert.h"
120
121
#include <tbb/compat/condition_variable>
#include <tbb/concurrent_queue.h>
122
#include <tbb/concurrent_vector.h>
schultezub's avatar
schultezub committed
123

124
125
126
#include "ext/tgt/runnable.h"
#include "ext/tgt/singleton.h"

schultezub's avatar
schultezub committed
127
namespace sigslot {
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    
    /**
     * List-like container allowing thread-safe bidirectional iteration, insertion and removal of elements. 
     * ATTENTION: Since removed items are internally stored as nullptr, the element type is constrained 
     * to be a pointer type (or at least have pointer semantics) and never be 0. Use with caution!
     */
    template<typename T>
    class concurrent_pointer_list {
    public:
        /// Typedef for internal storage of elements
        typedef tbb::concurrent_vector<T*> StorageType;

        /// Iterator for concurrent_pointer_list
        class concurrent_pointer_list_iterator : public std::iterator<std::bidirectional_iterator_tag, T*> {
        public:
            concurrent_pointer_list_iterator() {};

            concurrent_pointer_list_iterator(StorageType& storage, typename StorageType::iterator position)
                : _begin(storage.begin())
                , _position(position)
                , _end(storage.end())
            {
                if (_position != _end && *_position == nullptr)
                    operator++();
            }

            concurrent_pointer_list_iterator& operator++() {
                tgtAssert(_position != _end, "Trying to advance an iterator past the end!");
                do {
                    ++_position;
                } while (_position != _end && *_position == nullptr);
                return *this;
            }

            concurrent_pointer_list_iterator operator++(int) {
                concurrent_pointer_list_iterator toReturn = *this;
                operator++();
                return toReturn;
            }

            concurrent_pointer_list_iterator& operator--() {
                tgtAssert(_position != _begin, "Trying to advance an iterator befor the begin!");
                do {
                    --_position;
                } while (_position != _begin && *_position == nullptr);
                return *this;
            }

            concurrent_pointer_list_iterator operator--(int) {
                concurrent_pointer_list_iterator toReturn = *this;
                operator--();
                return toReturn;
            }

            reference operator*() const {
                return *_position;
            }

            pointer operator->() const {
                return &*_position;
            }

            bool operator==(const concurrent_pointer_list_iterator& rhs) const {
                return (_begin == rhs._begin && _position == rhs._position && _end == rhs._end);
            }

            bool operator!=(const concurrent_pointer_list_iterator& rhs) const {
                return (_begin != rhs._begin || _position != rhs._position || _end != rhs._end);
            }

        protected:
            typename StorageType::iterator _begin;
            typename StorageType::iterator _position;
            typename StorageType::iterator _end;
        };

        // TODO: As I am currently too lazy to correctly implement const_iterator: I hacked this collection to have a standard iterator as const_iterator.
        typedef concurrent_pointer_list_iterator iterator; ///< iterator typedef
        typedef concurrent_pointer_list_iterator const_iterator; ///< const_iterator typedef 

        /**
         * Creates a new concurrent_pointer_list object of default size
         */
        concurrent_pointer_list() {};

        /**
         * Creates a new concurrent_pointer_list object of default size
         * \param   initalSize  Initial size fo the internal storage
         */
        concurrent_pointer_list(typename StorageType::size_type initalSize) 
            : _storage(initalSize)
        {};


        /// Return an iterator to the beginning of the collection
        iterator begin() { return iterator(_storage, _storage.begin()); };
        /// Return an iterator to the beginning of the collection
        const_iterator begin() const { 
            StorageType& s = const_cast<StorageType&>(_storage);  // const_cast neccessary, because we did not implement const_iterator
            return const_iterator(s, s.begin()); 
        };

        /// Return an iterator to the end of the collection
        iterator end() { return iterator(_storage, _storage.end()); };
        /// Return an iterator to the end of the collection
        const_iterator end() const  { 
            StorageType& s = const_cast<StorageType&>(_storage);  // const_cast neccessary, because we did not implement const_iterator
            return const_iterator(s, s.end()); 
        };

        void push_back(T* element) { _storage.push_back(element); };
        void insert(T* element) { _storage.push_back(element); };

        size_t erase(T* element);
        void erase(const const_iterator& it) { *it = nullptr; };
        void erase(const const_iterator& begin, const const_iterator& end);


    protected:
        StorageType _storage;
    };

// ================================================================================================
    
    template<typename T>
    size_t concurrent_pointer_list<T>::erase(T* element) {
        size_t count = 0;
        iterator it = begin();
        iterator itEnd = end();

        for (/* nothing here */; it != itEnd; ++it) {
            if (*it == element) {
                *it = nullptr;
                ++count;
            }
        }

        return count;
    }

    template<typename T>
    void concurrent_pointer_list<T>::erase(const typename concurrent_pointer_list<T>::const_iterator& begin, const typename concurrent_pointer_list<T>::const_iterator& end) {
        for (const_iterator it = begin; it != end; ++it) {
            *it = nullptr;
        }
    }

// ================================================================================================
schultezub's avatar
schultezub committed
276

277
    /// Base class for signal handles that provides an interface to emit the signal.
278
279
    class _signal_handle_base {
    public:
280
        /// Virtual destructor
281
        virtual ~_signal_handle_base() {};
282
        /// Emits the signal of this signal handle.
283
284
285
        virtual void emitSignal() const = 0;
    };

286
287
// ================================================================================================

288
289
290
291
292
293
294
295
296
297
298
299
300
    /**
     * Singleton class that takes care of queuing and asynchronously dispatching signals.
     * 
     * The signal_manager implements the Runnable interface, i.e. runs in it's own thread once it
     * was launched. The signal_manager takes care of dispatching signals to their connections.
     * This is either done synchrnously by using triggerSignal() or asynchronously by using 
     * queueSignal(). Furthermore it allows to check, whether the current thread is the 
     * signal_manager thread. This allows the default signal emitting method operator() to 
     * automatically decide on the dispatch type based on the emitting thread.
     * 
     * signal_manager can be considered as thread-safe.
     */
    class SIGSLOT_API signal_manager : public tgt::Singleton<signal_manager>, public tgt::Runnable {
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
        friend class tgt::Singleton<signal_manager>;

    public:
        /**
         * Directly dispatches the signal \a signal to all currently registered listeners.
         * \note    For using threaded signal dispatching use queueSignal()
         * \param   signal   signal to dispatch
         */
        void triggerSignal(_signal_handle_base* signal) const;

        /**
         * Enqueue \a signal into the list of signals to be dispatched.
         * \note    Dispatch will be perfomed in signal_mananger thread. For direct dispatch in
         *          caller thread use triggerSignal().
         * \param   signal   signal to dispatch
         * \return  True, if \a signal was successfully enqueued to signal queue.
         */
        bool queueSignal(_signal_handle_base* signal);

320
321
322
323
324
325
        /**
         * Checks whether calling thread is signal_manager thread.
         * \return  std::this_thread::get_id() == _this_thread_id
         */
        bool isCurrentThreadSignalManagerThread() const;

326
327
328
329
330
331
332
333
334
335
336
        /// \see Runnable:run
        virtual void run();
        /// \see Runnable:stop
        virtual void stop();

    private:
        /// Private constructor only for singleton
        signal_manager();
        /// Private destructor only for singleton
        ~signal_manager();

337
        /// Typedef for the signal queue
338
339
340
341
342
343
344
        typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;

        SignalQueue _signalQueue;   ///< Queue for signals to be dispatched

        std::condition_variable _evaluationCondition; ///< conditional wait to be used when there are currently no jobs to process
        tbb::mutex _ecMutex; ///< Mutex for protecting _evaluationCondition

345
346
        std::thread::id _this_thread_id;

347
348
349
        static const std::string loggerCat_;
    };

350
351
// ================================================================================================

352
    
schultezub's avatar
schultezub committed
353
    class has_slots;
schultezub's avatar
schultezub committed
354
    
355
    
schultezub's avatar
schultezub committed
356
357
358
    class _connection_base0
    {
    public:
schultezub's avatar
schultezub committed
359
        virtual ~_connection_base0() {}
360
        virtual has_slots* getdest() const = 0;
schultezub's avatar
schultezub committed
361
362
        virtual void emitSignal() = 0;
        virtual _connection_base0* clone() = 0;
363
        virtual _connection_base0* duplicate(has_slots* pnewdest) = 0;
schultezub's avatar
schultezub committed
364
    };
schultezub's avatar
schultezub committed
365
    
366
    template<class arg1_type>
schultezub's avatar
schultezub committed
367
368
369
    class _connection_base1
    {
    public:
schultezub's avatar
schultezub committed
370
        virtual ~_connection_base1() {}
371
        virtual has_slots* getdest() const = 0;
schultezub's avatar
schultezub committed
372
        virtual void emitSignal(arg1_type) = 0;
373
374
        virtual _connection_base1<arg1_type>* clone() = 0;
        virtual _connection_base1<arg1_type>* duplicate(has_slots* pnewdest) = 0;
schultezub's avatar
schultezub committed
375
    };
schultezub's avatar
schultezub committed
376
    
377
    template<class arg1_type, class arg2_type>
schultezub's avatar
schultezub committed
378
379
380
    class _connection_base2
    {
    public:
schultezub's avatar
schultezub committed
381
        virtual ~_connection_base2() {}
382
        virtual has_slots* getdest() const = 0;
schultezub's avatar
schultezub committed
383
        virtual void emitSignal(arg1_type, arg2_type) = 0;
384
385
        virtual _connection_base2<arg1_type, arg2_type>* clone() = 0;
        virtual _connection_base2<arg1_type, arg2_type>* duplicate(has_slots* pnewdest) = 0;
schultezub's avatar
schultezub committed
386
    };
schultezub's avatar
schultezub committed
387
    
388
    template<class arg1_type, class arg2_type, class arg3_type>
schultezub's avatar
schultezub committed
389
390
391
    class _connection_base3
    {
    public:
schultezub's avatar
schultezub committed
392
        virtual ~_connection_base3() {}
393
        virtual has_slots* getdest() const = 0;
schultezub's avatar
schultezub committed
394
        virtual void emitSignal(arg1_type, arg2_type, arg3_type) = 0;
395
396
        virtual _connection_base3<arg1_type, arg2_type, arg3_type>* clone() = 0;
        virtual _connection_base3<arg1_type, arg2_type, arg3_type>* duplicate(has_slots* pnewdest) = 0;
schultezub's avatar
schultezub committed
397
    };
schultezub's avatar
schultezub committed
398
    
399
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type>
schultezub's avatar
schultezub committed
400
401
402
    class _connection_base4
    {
    public:
schultezub's avatar
schultezub committed
403
        virtual ~_connection_base4() {}
404
        virtual has_slots* getdest() const = 0;
schultezub's avatar
schultezub committed
405
        virtual void emitSignal(arg1_type, arg2_type, arg3_type, arg4_type) = 0;
406
407
        virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type>* clone() = 0;
        virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type>* duplicate(has_slots* pnewdest) = 0;
schultezub's avatar
schultezub committed
408
    };
schultezub's avatar
schultezub committed
409
    
410
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type>
schultezub's avatar
schultezub committed
411
412
413
    class _connection_base5
    {
    public:
schultezub's avatar
schultezub committed
414
        virtual ~_connection_base5() {}
415
        virtual has_slots* getdest() const = 0;
416
        virtual void emitSignal(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type) = 0;
417
418
        virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>* clone() = 0;
        virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>* duplicate(has_slots* pnewdest) = 0;
schultezub's avatar
schultezub committed
419
    };
schultezub's avatar
schultezub committed
420
    
421
// ================================================================================================
schultezub's avatar
schultezub committed
422
    
423
424
    
    class _signal_base
schultezub's avatar
schultezub committed
425
426
    {
    public:
427
428
        virtual void slot_disconnect(has_slots* pslot) = 0;
        virtual void slot_duplicate(has_slots const* poldslot, has_slots* pnewslot) = 0;
schultezub's avatar
schultezub committed
429
    };
schultezub's avatar
schultezub committed
430
    
431
    class has_slots
schultezub's avatar
schultezub committed
432
433
    {
    private:
434
435
        typedef concurrent_pointer_list<_signal_base> sender_set;
        typedef sender_set::const_iterator const_iterator;
schultezub's avatar
schultezub committed
436
        
schultezub's avatar
schultezub committed
437
    public:
schultezub's avatar
schultezub committed
438
439
        has_slots() {}
        
440
        has_slots(has_slots const& hs)
schultezub's avatar
schultezub committed
441
442
443
        {
            const_iterator it = hs.m_senders.begin();
            const_iterator itEnd = hs.m_senders.end();
schultezub's avatar
schultezub committed
444
445
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
446
447
448
449
450
                (*it)->slot_duplicate(&hs, this);
                m_senders.insert(*it);
                ++it;
            }
        } 
schultezub's avatar
schultezub committed
451
        
452
        void signal_connect(_signal_base* sender)
schultezub's avatar
schultezub committed
453
454
455
        {
            m_senders.insert(sender);
        }
schultezub's avatar
schultezub committed
456
        
457
        void signal_disconnect(_signal_base* sender)
schultezub's avatar
schultezub committed
458
459
460
        {
            m_senders.erase(sender);
        }
schultezub's avatar
schultezub committed
461
        
schultezub's avatar
schultezub committed
462
463
464
465
        virtual ~has_slots()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
466
        
schultezub's avatar
schultezub committed
467
468
469
470
        void disconnect_all()
        {
            const_iterator it = m_senders.begin();
            const_iterator itEnd = m_senders.end();
schultezub's avatar
schultezub committed
471
472
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
473
474
475
                (*it)->slot_disconnect(this);
                ++it;
            }
schultezub's avatar
schultezub committed
476
            
schultezub's avatar
schultezub committed
477
478
            m_senders.erase(m_senders.begin(), m_senders.end());
        }
schultezub's avatar
schultezub committed
479
        
schultezub's avatar
schultezub committed
480
481
482
    private:
        sender_set m_senders;
    };
schultezub's avatar
schultezub committed
483
    
484
485
    
    class _signal_base0 : public _signal_base
schultezub's avatar
schultezub committed
486
487
    {
    public:
488
        typedef concurrent_pointer_list<_connection_base0 >  connections_list;
schultezub's avatar
schultezub committed
489
490
491
        
        _signal_base0() {}
        
492
        _signal_base0(_signal_base0 const& s) : _signal_base(s)
schultezub's avatar
schultezub committed
493
        {
494
495
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();
schultezub's avatar
schultezub committed
496
497
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
498
499
500
501
502
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
503
        
schultezub's avatar
schultezub committed
504
505
506
507
        ~_signal_base0()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
508
        
schultezub's avatar
schultezub committed
509
510
        void disconnect_all()
        {
511
512
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
513
514
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
515
516
517
518
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
519
            
schultezub's avatar
schultezub committed
520
521
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
522
        
523
        void disconnect(has_slots* pclass)
schultezub's avatar
schultezub committed
524
        {
525
526
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
527
528
529
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
530
531
532
533
534
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
535
                
schultezub's avatar
schultezub committed
536
537
538
                ++it;
            }
        }
schultezub's avatar
schultezub committed
539
        
540
        void slot_disconnect(has_slots* pslot)
schultezub's avatar
schultezub committed
541
        {
542
543
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
544
545
            
            while (it != itEnd) {
546
                connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
547
                ++itNext;
schultezub's avatar
schultezub committed
548
549
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
550
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
551
                    //          delete *it;
schultezub's avatar
schultezub committed
552
                }
schultezub's avatar
schultezub committed
553
                
schultezub's avatar
schultezub committed
554
555
556
                it = itNext;
            }
        }
schultezub's avatar
schultezub committed
557
        
558
        void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
559
        {
560
561
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
562
563
564
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
565
566
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
567
                
schultezub's avatar
schultezub committed
568
569
570
                ++it;
            }
        }
571
572
573
574
575

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
576
        
schultezub's avatar
schultezub committed
577
578
579
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
580
    
581
582
    template<class arg1_type>
    class _signal_base1 : public _signal_base
schultezub's avatar
schultezub committed
583
584
    {
    public:
585
        typedef concurrent_pointer_list<_connection_base1<arg1_type> >  connections_list;
schultezub's avatar
schultezub committed
586
587
588
        
        _signal_base1() {}
        
589
        _signal_base1(_signal_base1<arg1_type> const& s) : _signal_base(s)
schultezub's avatar
schultezub committed
590
        {
591
592
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();
schultezub's avatar
schultezub committed
593
594
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
595
596
597
598
599
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
600
        
601
        void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
602
        {
603
604
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
605
606
607
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
608
609
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
610
                
schultezub's avatar
schultezub committed
611
612
613
                ++it;
            }
        }
schultezub's avatar
schultezub committed
614
        
schultezub's avatar
schultezub committed
615
616
617
618
        ~_signal_base1()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
619
        
schultezub's avatar
schultezub committed
620
621
        void disconnect_all()
        {
622
623
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
624
625
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
626
627
628
629
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
630
            
schultezub's avatar
schultezub committed
631
632
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
633
        
634
        void disconnect(has_slots* pclass)
schultezub's avatar
schultezub committed
635
        {
636
637
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
638
639
640
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
641
642
643
644
645
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
646
                
schultezub's avatar
schultezub committed
647
648
649
                ++it;
            }
        }
schultezub's avatar
schultezub committed
650
        
651
        void slot_disconnect(has_slots* pslot)
schultezub's avatar
schultezub committed
652
        {
653
654
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
655
656
            
            while (it != itEnd) {
657
                connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
658
                ++itNext;
schultezub's avatar
schultezub committed
659
660
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
661
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
662
                    //          delete *it;
schultezub's avatar
schultezub committed
663
                }
schultezub's avatar
schultezub committed
664
                
schultezub's avatar
schultezub committed
665
666
667
                it = itNext;
            }
        }
668
669
670
671
672

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
673
674
        
        
schultezub's avatar
schultezub committed
675
676
677
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
678
    
679
680
    template<class arg1_type, class arg2_type>
    class _signal_base2 : public _signal_base
schultezub's avatar
schultezub committed
681
682
    {
    public:
683
        typedef concurrent_pointer_list<_connection_base2<arg1_type, arg2_type> >  connections_list;
schultezub's avatar
schultezub committed
684
685
686
        
        _signal_base2() {}
        
687
        _signal_base2(_signal_base2<arg1_type, arg2_type> const& s) : _signal_base(s)
schultezub's avatar
schultezub committed
688
        {
689
690
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();
schultezub's avatar
schultezub committed
691
692
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
693
694
695
696
697
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
698
        
699
        void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
700
        {
701
702
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
703
704
705
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
706
707
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
708
                
schultezub's avatar
schultezub committed
709
710
711
                ++it;
            }
        }
schultezub's avatar
schultezub committed
712
        
schultezub's avatar
schultezub committed
713
714
715
716
        ~_signal_base2()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
717
        
schultezub's avatar
schultezub committed
718
719
        void disconnect_all()
        {
720
721
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
722
723
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
724
725
726
727
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
728
            
schultezub's avatar
schultezub committed
729
730
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
731
        
732
        void disconnect(has_slots* pclass)
schultezub's avatar
schultezub committed
733
        {
734
735
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
736
737
738
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
739
740
741
742
743
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
744
                
schultezub's avatar
schultezub committed
745
746
747
                ++it;
            }
        }
schultezub's avatar
schultezub committed
748
        
749
        void slot_disconnect(has_slots* pslot)
schultezub's avatar
schultezub committed
750
        {
751
752
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
753
754
            
            while (it != itEnd) {
755
                connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
756
                ++itNext;
schultezub's avatar
schultezub committed
757
758
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
759
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
760
                    //          delete *it;
schultezub's avatar
schultezub committed
761
                }
schultezub's avatar
schultezub committed
762
                
schultezub's avatar
schultezub committed
763
764
765
                it = itNext;
            }
        }
766
767
768
769
770

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
771
        
schultezub's avatar
schultezub committed
772
773
774
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
775
    
776
777
    template<class arg1_type, class arg2_type, class arg3_type>
    class _signal_base3 : public _signal_base
schultezub's avatar
schultezub committed
778
779
    {
    public:
780
781
        typedef concurrent_pointer_list<_connection_base3<arg1_type, arg2_type, arg3_type> >  connections_list;
         
schultezub's avatar
schultezub committed
782
783
        _signal_base3() {}
        
784
785
        _signal_base3(_signal_base3<arg1_type, arg2_type, arg3_type> const& s)
        : _signal_base(s)
schultezub's avatar
schultezub committed
786
        {
787
788
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();
schultezub's avatar
schultezub committed
789
790
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
791
792
793
794
795
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
796
        
797
        void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
798
        {
799
800
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
801
802
803
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
804
805
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
806
                
schultezub's avatar
schultezub committed
807
808
809
                ++it;
            }
        }
schultezub's avatar
schultezub committed
810
        
schultezub's avatar
schultezub committed
811
812
813
814
        ~_signal_base3()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
815
        
schultezub's avatar
schultezub committed
816
817
        void disconnect_all()
        {
818
819
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
820
821
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
822
823
824
825
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
826
            
schultezub's avatar
schultezub committed
827
828
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
829
        
830
        void disconnect(has_slots* pclass)
schultezub's avatar
schultezub committed
831
        {
832
833
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
834
835
836
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
837
838
839
840
841
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
842
                
schultezub's avatar
schultezub committed
843
844
845
                ++it;
            }
        }
schultezub's avatar
schultezub committed
846
        
847
        void slot_disconnect(has_slots* pslot)
schultezub's avatar
schultezub committed
848
        {
849
850
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
851
852
            
            while (it != itEnd) {
853
                connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
854
                ++itNext;
schultezub's avatar
schultezub committed
855
856
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
857
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
858
                    //          delete *it;
schultezub's avatar
schultezub committed
859
                }
schultezub's avatar
schultezub committed
860
                
schultezub's avatar
schultezub committed
861
862
863
                it = itNext;
            }
        }
864
865
866
867
868

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
869
        
schultezub's avatar
schultezub committed
870
871
872
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
873
    
874
875
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type>
    class _signal_base4 : public _signal_base
schultezub's avatar
schultezub committed
876
877
    {
    public:
878
        typedef concurrent_pointer_list<_connection_base4<arg1_type, arg2_type, arg3_type, arg4_type> >  connections_list;
schultezub's avatar
schultezub committed
879
880
881
        
        _signal_base4() {}
        
882
883
        _signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type>& s)
        : _signal_base(s)
schultezub's avatar
schultezub committed
884
        {
885
886
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();
schultezub's avatar
schultezub committed
887
888
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
889
890
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
schultezub's avatar
schultezub committed
891
                
schultezub's avatar
schultezub committed
892
893
894
                ++it;
            }
        }
schultezub's avatar
schultezub committed
895
        
896
        void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
897
        {
898
899
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
900
901
902
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
903
904
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
905
                
schultezub's avatar
schultezub committed
906
907
908
                ++it;
            }
        }
schultezub's avatar
schultezub committed
909
        
schultezub's avatar
schultezub committed
910
911
912
913
        ~_signal_base4()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
914
        
schultezub's avatar
schultezub committed
915
916
        void disconnect_all()
        {
917
918
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
919
920
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
921
922
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
schultezub's avatar
schultezub committed
923
                
schultezub's avatar
schultezub committed
924
925
                ++it;
            }
schultezub's avatar
schultezub committed
926
            
schultezub's avatar
schultezub committed
927
928
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
929
        
930
        void disconnect(has_slots* pclass)
schultezub's avatar
schultezub committed
931
        {
932
933
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
934
935
936
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
937
938
939
940
941
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
942
                
schultezub's avatar
schultezub committed
943
944
945
                ++it;
            }
        }
schultezub's avatar
schultezub committed
946
        
947
        void slot_disconnect(has_slots* pslot)
schultezub's avatar
schultezub committed
948
        {
949
950
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
951
952
            
            while (it != itEnd) {
953
                connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
954
                ++itNext;
schultezub's avatar
schultezub committed
955
956
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
957
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
958
                    //          delete *it;
schultezub's avatar
schultezub committed
959
                }
schultezub's avatar
schultezub committed
960
                
schultezub's avatar
schultezub committed
961
962
963
                it = itNext;
            }
        }
964
965
966
967
968

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
969
        
schultezub's avatar
schultezub committed
970
971
972
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
973
    
974
975
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type>
    class _signal_base5 : public _signal_base
schultezub's avatar
schultezub committed
976
977
    {
    public:
978
        typedef concurrent_pointer_list<_connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type> >  connections_list;
schultezub's avatar
schultezub committed
979
980
981
        
        _signal_base5() {}
        
982
983
        _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>& s)
        : _signal_base(s)
schultezub's avatar
schultezub committed
984
        {
985
986
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();
schultezub's avatar
schultezub committed
987
988
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
989
990
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
schultezub's avatar
schultezub committed
991
                
schultezub's avatar
schultezub committed
992
993
994
                ++it;
            }
        }
schultezub's avatar
schultezub committed
995
        
996
        void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
997
        {
998
999
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
1000
1001
1002
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
1003
1004
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
1005
                
schultezub's avatar
schultezub committed
1006
1007
1008
                ++it;
            }
        }
schultezub's avatar
schultezub committed
1009
        
schultezub's avatar
schultezub committed
1010
1011
1012
1013
        ~_signal_base5()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
1014
        
schultezub's avatar
schultezub committed
1015
1016
        void disconnect_all()
        {
1017
1018
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
1019
1020
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
1021
1022
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
schultezub's avatar
schultezub committed
1023
                
schultezub's avatar
schultezub committed
1024
1025
                ++it;
            }
schultezub's avatar
schultezub committed
1026
            
schultezub's avatar
schultezub committed
1027
1028
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
1029
        
1030
        void disconnect(has_slots* pclass)
schultezub's avatar
schultezub committed
1031
        {
1032
1033
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
1034
1035
1036
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
1037
1038
1039
1040
1041
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
1042
                
schultezub's avatar
schultezub committed
1043
1044
1045
                ++it;
            }
        }
schultezub's avatar
schultezub committed
1046
        
1047
        void slot_disconnect(has_slots* pslot)
schultezub's avatar
schultezub committed
1048
        {