sigslot.h 60.6 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
    
    /**
     * 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;
            }

182
            T*& operator*() const {
183
184
185
                return *_position;
            }

186
            T* operator->() const {
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
                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);

245
        bool empty() const;
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

    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;
        }
    }

276
277
278
279
280
281
282
283
284
285
286
287
288
289
    template<typename T>
    bool sigslot::concurrent_pointer_list<T>::empty() const {
        iterator it = begin();
        iterator itEnd = end();

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

        return true;
    }

290
// ================================================================================================
schultezub's avatar
schultezub committed
291

292
    /// Base class for signal handles that provides an interface to emit the signal.
293
294
    class _signal_handle_base {
    public:
295
        /// Virtual destructor
296
        virtual ~_signal_handle_base() {};
297
        /// Emits the signal of this signal handle.
298
299
300
        virtual void emitSignal() const = 0;
    };

301
302
// ================================================================================================

303
304
305
306
307
308
309
310
311
312
313
314
315
    /**
     * 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 {
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
        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);

335
336
337
338
339
340
        /**
         * Checks whether calling thread is signal_manager thread.
         * \return  std::this_thread::get_id() == _this_thread_id
         */
        bool isCurrentThreadSignalManagerThread() const;

341
342
343
344
345
346
347
348
349
350
351
        /// \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();

352
        /// Typedef for the signal queue
353
354
355
356
357
358
359
        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

360
361
        std::thread::id _this_thread_id;

362
363
364
        static const std::string loggerCat_;
    };

365
366
// ================================================================================================

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

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

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

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

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

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