sigslot.h 70.2 KB
Newer Older
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
// ================================================================================================
// 
// sigslot.h/sigslot.cpp - Signal/Slot classes:
// 
// Original siglsot implementation written by Sarah Thompson (sarah@telergy.com) 2002 and 
// published under public domain. <http://sigslot.sourceforge.net/>
// 
// This version of the sigslot library is heavily modified, C++ compliant, inherently thread-safe,
// and offers a manager class that allows to queue and asynchronously dispatch signals.
// 
// Copyright (C) 2012-2014, all rights reserved,
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
//      Technische Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, Germany
// 
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
// 
// ================================================================================================
schultezub's avatar
schultezub committed
28

schultezub's avatar
schultezub committed
29
30
#ifndef SIGSLOT_H
#define SIGSLOT_H
schultezub's avatar
schultezub committed
31

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

#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
55
56
#include <set>
#include <list>
57

58
#include "tgt/assert.h"
59
#include <ext/threading.h>
60

61
#include <tbb/concurrent_queue.h>
62
#include <tbb/concurrent_vector.h>
63
#include <tbb/spin_mutex.h>
schultezub's avatar
schultezub committed
64

65
66
67
#include "ext/tgt/runnable.h"
#include "ext/tgt/singleton.h"

schultezub's avatar
schultezub committed
68
namespace sigslot {
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    
    /**
     * 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++() {
                do {
                    ++_position;
98
                } while (_position < _end && *_position == nullptr);
99
100
101
102
103
104
105
106
107
108
109
110
                return *this;
            }

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

            concurrent_pointer_list_iterator& operator--() {
                do {
                    --_position;
111
                } while (_position > _begin && *_position == nullptr);
112
113
114
115
116
117
118
119
120
                return *this;
            }

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

121
            T*& operator*() const {
122
123
124
                return *_position;
            }

125
            T* operator->() const {
126
127
128
129
                return &*_position;
            }

            bool operator==(const concurrent_pointer_list_iterator& rhs) const {
130
                return (_position == rhs._position);
131
132
133
            }

            bool operator!=(const concurrent_pointer_list_iterator& rhs) const {
134
                return (_position != rhs._position);
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
            }

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

177
178
        void push_back(T* element) { insert(element); };
        void insert(T* element);
179
180
181
182
183

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

184
        bool empty() const;
185
186
187
188
189
190

    protected:
        StorageType _storage;
    };

// ================================================================================================
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208

    template<typename T>
    void concurrent_pointer_list<T>::insert(T* element) {
        iterator it = begin();
        iterator itEnd = end();

        // to ensure non-degrading performance, we first fill the gaps.
        for (/* nothing here */; it != itEnd; ++it) {
            if (*it == nullptr) {
                *it = element;
                return;
            }
        }

        // we did not find an empty element -> we add a new one at the end
        _storage.push_back(element);
    }

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
    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;
        }
    }

232
233
234
235
236
237
238
239
240
241
242
243
244
245
    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;
    }

246
// ================================================================================================
schultezub's avatar
schultezub committed
247

248
    /// Base class for signal handles that provides an interface to emit the signal.
249
250
    class _signal_handle_base {
    public:
251
        /// Virtual destructor
252
        virtual ~_signal_handle_base() {};
253
        /// Emits the signal of this signal handle.
254
255
256
257
258
259
260
261
262
        virtual void processSignal() const = 0;

#ifdef CAMPVIS_DEBUG
        // This is debug information only, automatically removed from release builds

        std::string _callingFunction;   ///< Function that emitted this signal
        std::string _callingFile;       ///< File which emitted this signal
        int _callingLine;               ///< Line where this signal was emitted
#endif
263
264
    };

265
266
// ================================================================================================

267
268
269
270
271
    /**
     * 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.
272
273
     * This is either done synchrnously by using triggerSignalImpl() or asynchronously by using 
     * queueSignalImpl(). Furthermore it allows to check, whether the current thread is the 
274
275
276
277
278
279
     * 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 {
280
281
282
        friend class tgt::Singleton<signal_manager>;

    public:
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
        /// Enumeration of signal handling modes for the signal_manager
        enum SignalHandlingMode {
            DEFAULT,        ///< Default mode is that all signals are queued unless they are emitted from the signal_manager thread.
            FORCE_DIRECT,   ///< Force all signals being directly handled by the emitting thread.
            FORCE_QUEUE     ///< Force all signals being queued and handled by the signal_manager thread.
        };

        /**
         * Returns the signal handling mode of this signal_manager.
         */
        SignalHandlingMode getSignalHandlingMode() const;

        /**
         * Sets the signal handling mode of this signal_manager to \mode.
         * \param   mode    New signal handling mode to set.
         */
        void setSignalHandlingMode(SignalHandlingMode mode);

301
302
        /**
         * Directly dispatches the signal \a signal to all currently registered listeners.
303
         * \note    For using threaded signal dispatching use queueSignalImpl()
304
305
         * \param   signal   signal to dispatch
         */
306
        void triggerSignalImpl(_signal_handle_base* signal);
307
308
309

        /**
         * Enqueue \a signal into the list of signals to be dispatched.
310
311
         * \note    Dispatch will be performed in signal_mananger thread. For direct dispatch in
         *          caller thread use triggerSignalImpl().
312
313
314
         * \param   signal   signal to dispatch
         * \return  True, if \a signal was successfully enqueued to signal queue.
         */
315
        bool queueSignalImpl(_signal_handle_base* signal);
316

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

323
324
325
326
327
328
329
330
331
332
333
        /// \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();

334
        /// Typedef for the signal queue
335
336
        typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;

337
        SignalHandlingMode _handlingMode;               ///< Mode for handling signals
338
        SignalQueue _signalQueue;                       ///< Queue for signals to be dispatched
339

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

343
344
        std::thread::id _this_thread_id;

345
346
347
        static const std::string loggerCat_;
    };

348
349
// ================================================================================================

350
    
351
    class SIGSLOT_API has_slots;
schultezub's avatar
schultezub committed
352
    
353
    
354
    class SIGSLOT_API _connection_base0
schultezub's avatar
schultezub committed
355
356
    {
    public:
schultezub's avatar
schultezub committed
357
        virtual ~_connection_base0() {}
358
        virtual has_slots* getdest() const = 0;
359
        virtual void processSignal() = 0;
schultezub's avatar
schultezub committed
360
        virtual _connection_base0* clone() = 0;
361
        virtual _connection_base0* duplicate(has_slots* pnewdest) = 0;
schultezub's avatar
schultezub committed
362
    };
schultezub's avatar
schultezub committed
363
    
364
    template<class arg1_type>
schultezub's avatar
schultezub committed
365
366
367
    class _connection_base1
    {
    public:
schultezub's avatar
schultezub committed
368
        virtual ~_connection_base1() {}
369
        virtual has_slots* getdest() const = 0;
370
        virtual void processSignal(arg1_type) = 0;
371
372
        virtual _connection_base1<arg1_type>* clone() = 0;
        virtual _connection_base1<arg1_type>* duplicate(has_slots* pnewdest) = 0;
schultezub's avatar
schultezub committed
373
    };
schultezub's avatar
schultezub committed
374
    
375
    template<class arg1_type, class arg2_type>
schultezub's avatar
schultezub committed
376
377
378
    class _connection_base2
    {
    public:
schultezub's avatar
schultezub committed
379
        virtual ~_connection_base2() {}
380
        virtual has_slots* getdest() const = 0;
381
        virtual void processSignal(arg1_type, arg2_type) = 0;
382
383
        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
384
    };
schultezub's avatar
schultezub committed
385
    
386
    template<class arg1_type, class arg2_type, class arg3_type>
schultezub's avatar
schultezub committed
387
388
389
    class _connection_base3
    {
    public:
schultezub's avatar
schultezub committed
390
        virtual ~_connection_base3() {}
391
        virtual has_slots* getdest() const = 0;
392
        virtual void processSignal(arg1_type, arg2_type, arg3_type) = 0;
393
394
        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
395
    };
schultezub's avatar
schultezub committed
396
    
397
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type>
schultezub's avatar
schultezub committed
398
399
400
    class _connection_base4
    {
    public:
schultezub's avatar
schultezub committed
401
        virtual ~_connection_base4() {}
402
        virtual has_slots* getdest() const = 0;
403
        virtual void processSignal(arg1_type, arg2_type, arg3_type, arg4_type) = 0;
404
405
        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
406
    };
schultezub's avatar
schultezub committed
407
    
408
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type>
schultezub's avatar
schultezub committed
409
410
411
    class _connection_base5
    {
    public:
schultezub's avatar
schultezub committed
412
        virtual ~_connection_base5() {}
413
        virtual has_slots* getdest() const = 0;
414
        virtual void processSignal(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type) = 0;
415
416
        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
417
    };
schultezub's avatar
schultezub committed
418
    
419
// ================================================================================================
schultezub's avatar
schultezub committed
420
    
421
    
422
    class SIGSLOT_API _signal_base
schultezub's avatar
schultezub committed
423
424
    {
    public:
425
426
        virtual void slot_disconnect(has_slots* pslot) = 0;
        virtual void slot_duplicate(has_slots const* poldslot, has_slots* pnewslot) = 0;
427
428
429
430

#ifdef CAMPVIS_DEBUG
    protected:
        // This is debug information only, automatically removed from release builds
431
432
433
434
435
436
437
438
439
        // As we're using local variables, we have to protect them with the mutex. This is neither
        // beautiful nor efficient, but as it's for debug-only code, we should be able to live with it.
        // In a side note: This mutex is sufficient to avoid segfaults or other crashes. However, it
        //                 does not guarantee the correct order of execution. Hence, there exist cases
        //                 where the debug information stored in the signal handle is not correct. 
        //                 This is a risk we can take, as the chance that the *very same* signal 
        //                 gets emitted concurrently form different threads is very low.
        tbb::spin_mutex _debugMutex;    ///< Mutex to protect these three variables
        
440
441
442
443
444
445
        std::string _callingFunction;   ///< Function that emitted the last signal
        std::string _callingFile;       ///< File which emitted the last signal
        int _callingLine;               ///< Line where the last signal was emitted

        // In debug mode, this macro writes the caller information to the signal handle
        #define writeDebugInfoToSignalHandle(_the_signal_handle) \
446
447
            { \
            tbb::spin_mutex::scoped_lock lock(this->_debugMutex); \
448
449
            _the_signal_handle->_callingFunction = this->_callingFunction; \
            _the_signal_handle->_callingFile = this->_callingFile; \
450
451
            _the_signal_handle->_callingLine = this->_callingLine; \
            }
452
453
454
455
#else
        // In release mode, this macro expands to a NOP.
        #define writeDebugInfoToSignalHandle(_the_signal_handle) 
#endif
schultezub's avatar
schultezub committed
456
    };
457

458
    class SIGSLOT_API has_slots
schultezub's avatar
schultezub committed
459
460
    {
    private:
461
462
        typedef concurrent_pointer_list<_signal_base> sender_set;
        typedef sender_set::const_iterator const_iterator;
schultezub's avatar
schultezub committed
463
        
schultezub's avatar
schultezub committed
464
    public:
schultezub's avatar
schultezub committed
465
466
        has_slots() {}
        
467
        has_slots(has_slots const& hs)
schultezub's avatar
schultezub committed
468
469
470
        {
            const_iterator it = hs.m_senders.begin();
            const_iterator itEnd = hs.m_senders.end();
schultezub's avatar
schultezub committed
471
472
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
473
474
475
476
477
                (*it)->slot_duplicate(&hs, this);
                m_senders.insert(*it);
                ++it;
            }
        } 
schultezub's avatar
schultezub committed
478
        
479
        void signal_connect(_signal_base* sender)
schultezub's avatar
schultezub committed
480
481
482
        {
            m_senders.insert(sender);
        }
schultezub's avatar
schultezub committed
483
        
484
        void signal_disconnect(_signal_base* sender)
schultezub's avatar
schultezub committed
485
486
487
        {
            m_senders.erase(sender);
        }
schultezub's avatar
schultezub committed
488
        
schultezub's avatar
schultezub committed
489
490
491
492
        virtual ~has_slots()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
493
        
schultezub's avatar
schultezub committed
494
495
496
497
        void disconnect_all()
        {
            const_iterator it = m_senders.begin();
            const_iterator itEnd = m_senders.end();
schultezub's avatar
schultezub committed
498
499
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
500
501
502
                (*it)->slot_disconnect(this);
                ++it;
            }
schultezub's avatar
schultezub committed
503
            
schultezub's avatar
schultezub committed
504
505
            m_senders.erase(m_senders.begin(), m_senders.end());
        }
schultezub's avatar
schultezub committed
506
        
schultezub's avatar
schultezub committed
507
508
509
    private:
        sender_set m_senders;
    };
schultezub's avatar
schultezub committed
510
    
511
512
    
    class _signal_base0 : public _signal_base
schultezub's avatar
schultezub committed
513
514
    {
    public:
515
        typedef concurrent_pointer_list<_connection_base0 >  connections_list;
schultezub's avatar
schultezub committed
516
517
518
        
        _signal_base0() {}
        
519
        _signal_base0(_signal_base0 const& s) : _signal_base(s)
schultezub's avatar
schultezub committed
520
        {
521
522
            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
523
524
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
525
526
527
528
529
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
530
        
schultezub's avatar
schultezub committed
531
532
533
534
        ~_signal_base0()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
535
        
schultezub's avatar
schultezub committed
536
537
        void disconnect_all()
        {
538
539
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
540
541
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
542
543
544
545
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
546
            
schultezub's avatar
schultezub committed
547
548
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
549
        
550
        void disconnect(has_slots* pclass)
schultezub's avatar
schultezub committed
551
        {
552
553
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
554
555
556
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
557
558
559
560
561
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
562
                
schultezub's avatar
schultezub committed
563
564
565
                ++it;
            }
        }
schultezub's avatar
schultezub committed
566
        
567
        void slot_disconnect(has_slots* pslot)
schultezub's avatar
schultezub committed
568
        {
569
570
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
571
572
            
            while (it != itEnd) {
573
                connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
574
                ++itNext;
schultezub's avatar
schultezub committed
575
576
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
577
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
578
                    //          delete *it;
schultezub's avatar
schultezub committed
579
                }
schultezub's avatar
schultezub committed
580
                
schultezub's avatar
schultezub committed
581
582
583
                it = itNext;
            }
        }
schultezub's avatar
schultezub committed
584
        
585
        void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
586
        {
587
588
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
589
590
591
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
592
593
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
594
                
schultezub's avatar
schultezub committed
595
596
597
                ++it;
            }
        }
598
599
600
601
602

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

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

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

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

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
996
        
schultezub's avatar
schultezub committed
997
998
999
    protected:
        connections_list m_connected_slots