Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

sigslot.h 59.7 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>
schultezub's avatar
schultezub committed
63

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

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

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

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

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

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

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

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

            bool operator!=(const concurrent_pointer_list_iterator& rhs) const {
133
                return (_position != rhs._position);
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
            }

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

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

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

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

    protected:
        StorageType _storage;
    };

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

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

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

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

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

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

256
257
// ================================================================================================

258
259
260
261
262
263
264
265
266
267
268
269
270
    /**
     * Singleton class that takes care of queuing and asynchronously dispatching signals.
     * 
     * The signal_manager implements the Runnable interface, i.e. runs in it's own thread once it
     * was launched. The signal_manager takes care of dispatching signals to their connections.
     * This is either done synchrnously by using triggerSignal() or asynchronously by using 
     * queueSignal(). Furthermore it allows to check, whether the current thread is the 
     * signal_manager thread. This allows the default signal emitting method operator() to 
     * automatically decide on the dispatch type based on the emitting thread.
     * 
     * signal_manager can be considered as thread-safe.
     */
    class SIGSLOT_API signal_manager : public tgt::Singleton<signal_manager>, public tgt::Runnable {
271
272
273
        friend class tgt::Singleton<signal_manager>;

    public:
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
        /// 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);

292
293
294
295
296
        /**
         * Directly dispatches the signal \a signal to all currently registered listeners.
         * \note    For using threaded signal dispatching use queueSignal()
         * \param   signal   signal to dispatch
         */
297
        void triggerSignal(_signal_handle_base* signal);
298
299
300
301
302
303
304
305
306
307

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

308
309
310
311
312
313
        /**
         * Checks whether calling thread is signal_manager thread.
         * \return  std::this_thread::get_id() == _this_thread_id
         */
        bool isCurrentThreadSignalManagerThread() const;

314
315
316
317
318
319
320
321
322
323
324
        /// \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();

325
        /// Typedef for the signal queue
326
327
        typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;

328
        SignalHandlingMode _handlingMode;               ///< Mode for handling signals
329
        SignalQueue _signalQueue;                       ///< Queue for signals to be dispatched
330

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

334
335
        std::thread::id _this_thread_id;

336
337
338
        static const std::string loggerCat_;
    };

339
340
// ================================================================================================

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

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

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

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

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

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
958
        
schultezub's avatar
schultezub committed
959
960
961
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
962
    
963
964
    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
965
966
    {
    public:
967
        typedef concurrent_pointer_list<_connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type> >  connections_list;
schultezub's avatar
schultezub committed
968
969
970
        
        _signal_base5() {}
        
971
972
        _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>& s)
        : _signal_base(s)
schultezub's avatar
schultezub committed
973
        {
974
975
            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
976
977
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
978
979
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
schultezub's avatar
schultezub committed
980
                
schultezub's avatar
schultezub committed
981
982
983
                ++it;
            }
        }
schultezub's avatar
schultezub committed
984
        
985
        void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
986
        {
987
988
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
989
990
991
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {