2.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

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

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

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

#ifdef CAMPVIS_DYNAMIC_LIBS
    #ifdef SIGSLOT_BUILD_DLL
        // building library -> export symbols
        #ifdef WIN32
            #define SIGSLOT_API __declspec(dllexport)
        #else
            #define SIGSLOT_API
        #endif
    #else
        // including library -> import symbols
        #ifdef WIN32
            #define SIGSLOT_API __declspec(dllimport)
        #else
            #define SIGSLOT_API
        #endif
    #endif
#else
    // building/including static library -> do nothing
    #define SIGSLOT_API
#endif


schultezub's avatar
schultezub committed
55
56
#include <set>
#include <list>
57

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

61
#define TBB_PREVIEW_MEMORY_POOL 1
62
#include <tbb/concurrent_queue.h>
63
#include <tbb/concurrent_vector.h>
64
#include <tbb/memory_pool.h>
65
#include <tbb/spin_mutex.h>
schultezub's avatar
schultezub committed
66

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

schultezub's avatar
schultezub committed
70
namespace sigslot {
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    
    /**
     * List-like container allowing thread-safe bidirectional iteration, insertion and removal of elements. 
     * ATTENTION: Since removed items are internally stored as nullptr, the element type is constrained 
     * to be a pointer type (or at least have pointer semantics) and never be 0. Use with caution!
     */
    template<typename T>
    class concurrent_pointer_list {
    public:
        /// Typedef for internal storage of elements
        typedef tbb::concurrent_vector<T*> StorageType;

        /// Iterator for concurrent_pointer_list
        class concurrent_pointer_list_iterator : public std::iterator<std::bidirectional_iterator_tag, T*> {
        public:
            concurrent_pointer_list_iterator() {};

            concurrent_pointer_list_iterator(StorageType& storage, typename StorageType::iterator position)
                : _begin(storage.begin())
                , _position(position)
                , _end(storage.end())
            {
                if (_position != _end && *_position == nullptr)
                    operator++();
            }

            concurrent_pointer_list_iterator& operator++() {
                do {
                    ++_position;
100
                } while (_position < _end && *_position == nullptr);
101
102
103
104
105
106
107
108
109
110
111
112
                return *this;
            }

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

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

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

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

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

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

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

        protected:
            typename StorageType::iterator _begin;
            typename StorageType::iterator _position;
            typename StorageType::iterator _end;
        };

        // TODO: As I am currently too lazy to correctly implement const_iterator: I hacked this collection to have a standard iterator as const_iterator.
        typedef concurrent_pointer_list_iterator iterator; ///< iterator typedef
        typedef concurrent_pointer_list_iterator const_iterator; ///< const_iterator typedef 

        /**
         * Creates a new concurrent_pointer_list object of default size
         */
        concurrent_pointer_list() {};

        /**
         * Creates a new concurrent_pointer_list object of default size
         * \param   initalSize  Initial size fo the internal storage
         */
        concurrent_pointer_list(typename StorageType::size_type initalSize) 
            : _storage(initalSize)
        {};


        /// Return an iterator to the beginning of the collection
        iterator begin() { return iterator(_storage, _storage.begin()); };
        /// Return an iterator to the beginning of the collection
        const_iterator begin() const { 
            StorageType& s = const_cast<StorageType&>(_storage);  // const_cast neccessary, because we did not implement const_iterator
            return const_iterator(s, s.begin()); 
        };

        /// Return an iterator to the end of the collection
        iterator end() { return iterator(_storage, _storage.end()); };
        /// Return an iterator to the end of the collection
        const_iterator end() const  { 
            StorageType& s = const_cast<StorageType&>(_storage);  // const_cast neccessary, because we did not implement const_iterator
            return const_iterator(s, s.end()); 
        };

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

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

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

    protected:
        StorageType _storage;
    };

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

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

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

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

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
    template<typename T>
    size_t concurrent_pointer_list<T>::erase(T* element) {
        size_t count = 0;
        iterator it = begin();
        iterator itEnd = end();

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

        return count;
    }

    template<typename T>
    void concurrent_pointer_list<T>::erase(const typename concurrent_pointer_list<T>::const_iterator& begin, const typename concurrent_pointer_list<T>::const_iterator& end) {
        for (const_iterator it = begin; it != end; ++it) {
            *it = nullptr;
        }
    }

234
235
236
237
238
239
240
241
242
243
244
245
246
247
    template<typename T>
    bool sigslot::concurrent_pointer_list<T>::empty() const {
        iterator it = begin();
        iterator itEnd = end();

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

        return true;
    }

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

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

258
259
260
261
        /**
         * Overloading the new operator to create signal handles in signal_manager's memory pool.
         * \param   size    Number of bytes to allocate.
         */
262
        static void* operator new(std::size_t size) throw(std::bad_alloc);
263
264
265
266
267
268

        /**
         * Overloading the delete operator to correctly remove signal handles from signal_manager's memory pool.
         * \param   rawMemory   Pointer to object to delete
         * \param   size        Number of bytes
         */
269
270
        static void operator delete(void* rawMemory, std::size_t size) throw();

271
272
273
274
275
276
277
#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
278
279
    };

280
281
// ================================================================================================

282
283
284
285
286
    /**
     * 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.
287
288
     * This is either done synchrnously by using triggerSignalImpl() or asynchronously by using 
     * queueSignalImpl(). Furthermore it allows to check, whether the current thread is the 
289
290
291
292
293
294
     * 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 {
295
296
        friend class tgt::Singleton<signal_manager>;    ///< CRTP
        friend class _signal_handle_base;               ///< so the custom new/delete operator can access the memory pool
297
298

    public:
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
        /// 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);

317
318
        /**
         * Directly dispatches the signal \a signal to all currently registered listeners.
319
         * \note    For using threaded signal dispatching use queueSignalImpl()
320
321
         * \param   signal   signal to dispatch
         */
322
        void triggerSignalImpl(_signal_handle_base* signal);
323
324
325

        /**
         * Enqueue \a signal into the list of signals to be dispatched.
326
327
         * \note    Dispatch will be performed in signal_mananger thread. For direct dispatch in
         *          caller thread use triggerSignalImpl().
328
329
330
         * \param   signal   signal to dispatch
         * \return  True, if \a signal was successfully enqueued to signal queue.
         */
331
        bool queueSignalImpl(_signal_handle_base* signal);
332

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

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

350
        /// Typedef for the signal queue
351
352
        typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;

353
        SignalHandlingMode _handlingMode;               ///< Mode for handling signals
354
        SignalQueue _signalQueue;                       ///< Queue for signals to be dispatched
355

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

359
360
        std::thread::id _this_thread_id;

361
362
363
        typedef std::allocator<_signal_handle_base> pool_allocator_t;
        tbb::memory_pool<pool_allocator_t> _signalPool; ///< Memory pool for the signals

364
365
366
        static const std::string loggerCat_;
    };

367
368
// ================================================================================================

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

#ifdef CAMPVIS_DEBUG
    protected:
        // This is debug information only, automatically removed from release builds
450
451
452
453
454
455
456
457
458
        // As we're using local variables, we have to protect them with the mutex. This is neither
        // beautiful nor efficient, but as it's for debug-only code, we should be able to live with it.
        // In a side note: This mutex is sufficient to avoid segfaults or other crashes. However, it
        //                 does not guarantee the correct order of execution. Hence, there exist cases
        //                 where the debug information stored in the signal handle is not correct. 
        //                 This is a risk we can take, as the chance that the *very same* signal 
        //                 gets emitted concurrently form different threads is very low.
        tbb::spin_mutex _debugMutex;    ///< Mutex to protect these three variables
        
459
460
461
462
463
464
        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) \
465
466
            { \
            tbb::spin_mutex::scoped_lock lock(this->_debugMutex); \
467
468
            _the_signal_handle->_callingFunction = this->_callingFunction; \
            _the_signal_handle->_callingFile = this->_callingFile; \
469
470
            _the_signal_handle->_callingLine = this->_callingLine; \
            }
471
472
473
474
#else
        // In release mode, this macro expands to a NOP.
        #define writeDebugInfoToSignalHandle(_the_signal_handle) 
#endif
schultezub's avatar
schultezub committed
475
    };
476

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

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

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

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

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

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
1015
        
schultezub's avatar
schultezub committed
1016
1017
1018
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
1019
    
1020
1021
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type>
    class _signal_base5 : public _signal_base