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 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
#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
256
257
258
259
260
261
        virtual void processSignal() const = 0;

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

        std::string _callingFunction;   ///< Function that emitted this signal
        std::string _callingFile;       ///< File which emitted this signal
        int _callingLine;               ///< Line where this signal was emitted
#endif
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.
271
272
     * This is either done synchrnously by using triggerSignalImpl() or asynchronously by using 
     * queueSignalImpl(). Furthermore it allows to check, whether the current thread is the 
273
274
275
276
277
278
     * 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 {
279
280
281
        friend class tgt::Singleton<signal_manager>;

    public:
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
        /// 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);

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

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

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

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

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

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

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

342
343
        std::thread::id _this_thread_id;

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

347
348
// ================================================================================================

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

#ifdef CAMPVIS_DEBUG
    protected:
        // This is debug information only, automatically removed from release builds
        // using local variables is not really thread-safe, but for debug-only code, this is a risk we can take.
        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) \
            _the_signal_handle->_callingFunction = this->_callingFunction; \
            _the_signal_handle->_callingFile = this->_callingFile; \
            _the_signal_handle->_callingLine = this->_callingLine;
#else
        // In release mode, this macro expands to a NOP.
        #define writeDebugInfoToSignalHandle(_the_signal_handle) 
#endif
schultezub's avatar
schultezub committed
444
    };
445

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

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

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

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

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

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
984
        
schultezub's avatar
schultezub committed
985
986
987
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
988
    
989
990
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type>
    class _signal_base5 : public _signal_base
schultezub's avatar
schultezub committed
991
992
    {
    public:
993
        typedef concurrent_pointer_list<_connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type> >  connections_list;
schultezub's avatar
schultezub committed
994
995
996
        
        _signal_base5() {}
        
997
998
        _signal_base5(const _signal_base5<arg1_type, arg2_type,