sigslot.h 70.6 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
#define TBB_PREVIEW_MEMORY_POOL 1
62
#include <tbb/concurrent_queue.h>
63
#include <tbb/concurrent_vector.h>
64
#include <tbb/memory_pool.h>
65
#include <tbb/spin_mutex.h>
schultezub's avatar
schultezub committed
66

67
68
69
#include "ext/tgt/runnable.h"
#include "ext/tgt/singleton.h"

schultezub's avatar
schultezub committed
70
namespace sigslot {
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
98
99
    
    /**
     * 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;
100
                } while (_position < _end && *_position == nullptr);
101
102
103
104
105
106
107
108
109
110
111
112
                return *this;
            }

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

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

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

123
            T*& operator*() const {
124
125
126
                return *_position;
            }

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

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

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

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

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

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

186
        bool empty() const;
187
188
189
190
191
192

    protected:
        StorageType _storage;
    };

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

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

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

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

248
// ================================================================================================
schultezub's avatar
schultezub committed
249

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

258
259
260
        static void* operator new(std::size_t size) throw(std::bad_alloc);
        static void operator delete(void* rawMemory, std::size_t size) throw();

261
262
263
264
265
266
267
#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
268
269
    };

270
271
// ================================================================================================

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

    public:
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
        /// 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);

307
308
        /**
         * Directly dispatches the signal \a signal to all currently registered listeners.
309
         * \note    For using threaded signal dispatching use queueSignalImpl()
310
311
         * \param   signal   signal to dispatch
         */
312
        void triggerSignalImpl(_signal_handle_base* signal);
313
314
315

        /**
         * Enqueue \a signal into the list of signals to be dispatched.
316
317
         * \note    Dispatch will be performed in signal_mananger thread. For direct dispatch in
         *          caller thread use triggerSignalImpl().
318
319
320
         * \param   signal   signal to dispatch
         * \return  True, if \a signal was successfully enqueued to signal queue.
         */
321
        bool queueSignalImpl(_signal_handle_base* signal);
322

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

329
330
331
332
333
334
335
336
337
338
339
        /// \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();

340
        /// Typedef for the signal queue
341
342
        typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;

343
        SignalHandlingMode _handlingMode;               ///< Mode for handling signals
344
        SignalQueue _signalQueue;                       ///< Queue for signals to be dispatched
345

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

349
350
        std::thread::id _this_thread_id;

351
352
353
        typedef std::allocator<_signal_handle_base> pool_allocator_t;
        tbb::memory_pool<pool_allocator_t> _signalPool; ///< Memory pool for the signals

354
355
356
        static const std::string loggerCat_;
    };

357
358
// ================================================================================================

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

#ifdef CAMPVIS_DEBUG
    protected:
        // This is debug information only, automatically removed from release builds
440
441
442
443
444
445
446
447
448
        // 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
        
449
450
451
452
453
454
        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) \
455
456
            { \
            tbb::spin_mutex::scoped_lock lock(this->_debugMutex); \
457
458
            _the_signal_handle->_callingFunction = this->_callingFunction; \
            _the_signal_handle->_callingFile = this->_callingFile; \
459
460
            _the_signal_handle->_callingLine = this->_callingLine; \
            }
461
462
463
464
#else
        // In release mode, this macro expands to a NOP.
        #define writeDebugInfoToSignalHandle(_the_signal_handle) 
#endif
schultezub's avatar
schultezub committed
465
    };
466

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

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

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

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

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

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
1005
        
schultezub's avatar
schultezub committed
1006
1007
1008
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
1009
    
1010
1011
    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
1012
1013
    {
    public:
1014
        typedef concurrent_pointer_list<_connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type> >  connections_list;
schultezub's avatar
schultezub committed
1015
1016
1017
        
        _signal_base5() {}
        
1018
1019
        _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>& s)
        : _signal_base(s)
schultezub's avatar
schultezub committed
1020
        {
1021
1022
            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
1023
1024
            
            while (it != itEnd