sigslot.h 58.8 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
60
#include <tbb/compat/condition_variable>
#include <tbb/concurrent_queue.h>
61
#include <tbb/concurrent_vector.h>
schultezub's avatar
schultezub committed
62

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

schultezub's avatar
schultezub committed
66
namespace sigslot {
67
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    
    /**
     * 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++() {
                tgtAssert(_position != _end, "Trying to advance an iterator past the end!");
                do {
                    ++_position;
                } while (_position != _end && *_position == nullptr);
                return *this;
            }

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

            concurrent_pointer_list_iterator& operator--() {
                tgtAssert(_position != _begin, "Trying to advance an iterator befor the begin!");
                do {
                    --_position;
                } while (_position != _begin && *_position == nullptr);
                return *this;
            }

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

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

125
            T* operator->() const {
126
127
128
129
130
131
132
133
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
176
                return &*_position;
            }

            bool operator==(const concurrent_pointer_list_iterator& rhs) const {
                return (_begin == rhs._begin && _position == rhs._position && _end == rhs._end);
            }

            bool operator!=(const concurrent_pointer_list_iterator& rhs) const {
                return (_begin != rhs._begin || _position != rhs._position || _end != rhs._end);
            }

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

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

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

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


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

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

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

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

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

    protected:
        StorageType _storage;
    };

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

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

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

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

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

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

        return count;
    }

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

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

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

        return true;
    }

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

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

257
258
// ================================================================================================

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

    public:
        /**
         * Directly dispatches the signal \a signal to all currently registered listeners.
         * \note    For using threaded signal dispatching use queueSignal()
         * \param   signal   signal to dispatch
         */
        void triggerSignal(_signal_handle_base* signal) const;

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

291
292
293
294
295
296
        /**
         * Checks whether calling thread is signal_manager thread.
         * \return  std::this_thread::get_id() == _this_thread_id
         */
        bool isCurrentThreadSignalManagerThread() const;

297
298
299
300
301
302
303
304
305
306
307
        /// \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();

308
        /// Typedef for the signal queue
309
310
311
312
313
314
315
        typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;

        SignalQueue _signalQueue;   ///< Queue for signals to be dispatched

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

316
317
        std::thread::id _this_thread_id;

318
319
320
        static const std::string loggerCat_;
    };

321
322
// ================================================================================================

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

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

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

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

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

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
940
        
schultezub's avatar
schultezub committed
941
942
943
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
944
    
945
946
    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
947
948
    {
    public:
949
        typedef concurrent_pointer_list<_connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type> >  connections_list;
schultezub's avatar
schultezub committed
950
951
952
        
        _signal_base5() {}
        
953
954
        _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>& s)
        : _signal_base(s)
schultezub's avatar
schultezub committed
955
        {
956
957
            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
958
959
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
960
961
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
schultezub's avatar
schultezub committed
962
                
schultezub's avatar
schultezub committed
963
964
965
                ++it;
            }
        }
schultezub's avatar
schultezub committed
966
        
967
        void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget)
schultezub's avatar
schultezub committed
968
        {
969
970
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed
971
972
973
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
974
975
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
976
                
schultezub's avatar
schultezub committed
977
978
979
                ++it;
            }
        }
schultezub's avatar
schultezub committed
980
        
schultezub's avatar
schultezub committed
981
982
983
984
        ~_signal_base5()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
985
        
schultezub's avatar
schultezub committed
986
987
        void disconnect_all()
        {
988
989
            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
990
991
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
992
993
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
schultezub's avatar
schultezub committed
994
                
schultezub's avatar
schultezub committed
995
996
                ++it;
            }
schultezub's avatar
schultezub committed
997
            
schultezub's avatar
schultezub committed
998
999
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
1000
        
1001
        void disconnect(has_slots* pclass)
schultezub's avatar
schultezub committed
1002
        {
1003
1004
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
schultezub's avatar
schultezub committed