/* sigslot.h: Signal/Slot classes Written by Sarah Thompson (sarah@telergy.com) 2002. License: Public domain. You are free to use this code however you like, with the proviso that the author takes on no responsibility or liability for any use. QUICK DOCUMENTATION (see also the full documentation at http://sigslot.sourceforge.net/) 1. #define switches SIGSLOT_PURE_ISO: Define this to force ISO C++ compliance. This also disables all of the thread safety support on platforms where it is available. SIGSLOT_USE_POSIX_THREADS: Force use of Posix threads when using a C++ compiler other than gcc on a platform that supports Posix threads. (When using gcc, this is the default - use SIGSLOT_PURE_ISO to disable this if necessary) SIGSLOT_DEFAULT_MT_POLICY: Where thread support is enabled, this defaults to multi_threaded_global. Otherwise, the default is single_threaded. #define this yourself to override the default. In pure ISO mode, anything other than single_threaded will cause a compiler error. 2. PLATFORM NOTES Win32: On Win32, the WIN32 symbol must be #defined. Most mainstream compilers do this by default, but you may need to define it yourself if your build environment is less standard. This causes the Win32 thread support to be compiled in and used automatically. Unix/Linux/BSD, etc: If you're using gcc, it is assumed that you have Posix threads available, so they are used automatically. You can override this (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using something other than gcc but still want to use Posix threads, you need to #define SIGSLOT_USE_POSIX_THREADS. ISO C++: If none of the supported platforms are detected, or if SIGSLOT_PURE_ISO is defined, all multithreading support is turned off, along with any code that might cause a pure ISO C++ environment to complain. Before you ask, gcc -ansi -pedantic won't compile this library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of errors that aren't really there. If you feel like investigating this, please contact the author. THREADING MODES single_threaded: Your program is assumed to be single threaded from the point of view of signal/slot usage (i.e. all objects using signals and slots are created and destroyed from a single thread). Behaviour if objects are destroyed concurrently is undefined (i.e. you'll get the occasional segmentation fault/memory exception). multi_threaded_global: Your program is assumed to be multi threaded. Objects using signals and slots can be safely created and destroyed from any thread, even when connections exist. In multi_threaded_global mode, this is achieved by a single global mutex (actually a critical section on Windows because they are faster). This option uses less OS resources, but results in more opportunities for contention, possibly resulting in more context switches than are strictly necessary. multi_threaded_local: Behaviour in this mode is essentially the same as multi_threaded_global, except that each signal, and each object that inherits has_slots, all have their own mutex/critical section. In practice, this means that mutex collisions (and hence context switches) only happen if they are absolutely essential. However, on some platforms, creating a lot of mutexes can slow down the whole OS, so use this option with care. USING THE LIBRARY See the full documentation at http://sigslot.sourceforge.net/ */ #ifndef SIGSLOT_H #define SIGSLOT_H #include #include #include #include #include #include "ext/tgt/runnable.h" #include "ext/tgt/singleton.h" #ifndef SIGSLOT_DEFAULT_MT_POLICY # ifdef _SIGSLOT_SINGLE_THREADED # define SIGSLOT_DEFAULT_MT_POLICY single_threaded # else # define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local # endif #endif namespace sigslot { class _signal_handle_base { public: virtual ~_signal_handle_base() {}; virtual void emitSignal() const = 0; }; // ================================================================================================ class signal_manager : public tgt::Singleton, public tgt::Runnable { friend class tgt::Singleton; 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); /// \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(); 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 static const std::string loggerCat_; }; // ================================================================================================ typedef tbb::spin_rw_mutex tbb_mutex; // The multi threading policies only get compiled in if they are enabled. class multi_threaded_global { public: multi_threaded_global() { ; } multi_threaded_global(const multi_threaded_global&) { ; } virtual ~multi_threaded_global() { ; } tbb_mutex& get_mutex() { static tbb_mutex g_mutex; return g_mutex; } }; class multi_threaded_local { public: multi_threaded_local() { ; } multi_threaded_local(const multi_threaded_local&) { ; } virtual ~multi_threaded_local() { ; } tbb_mutex& get_mutex() { return m_mutex; } private: tbb_mutex m_mutex; }; template class lock_block_write : tbb_mutex::scoped_lock { public: lock_block_write(mt_policy *mtx) : tbb_mutex::scoped_lock(mtx->get_mutex(), true) { } ~lock_block_write() { } }; template class lock_block_read : tbb_mutex::scoped_lock { public: lock_block_read(mt_policy *mtx) : tbb_mutex::scoped_lock(mtx->get_mutex(), false) { } ~lock_block_read() { } }; // ================================================================================================ template class has_slots; template class _connection_base0 { public: virtual ~_connection_base0() {} virtual has_slots* getdest() const = 0; virtual void emitSignal() = 0; virtual _connection_base0* clone() = 0; virtual _connection_base0* duplicate(has_slots* pnewdest) = 0; }; template class _connection_base1 { public: virtual ~_connection_base1() {} virtual has_slots* getdest() const = 0; virtual void emitSignal(arg1_type) = 0; virtual _connection_base1* clone() = 0; virtual _connection_base1* duplicate(has_slots* pnewdest) = 0; }; template class _connection_base2 { public: virtual ~_connection_base2() {} virtual has_slots* getdest() const = 0; virtual void emitSignal(arg1_type, arg2_type) = 0; virtual _connection_base2* clone() = 0; virtual _connection_base2* duplicate(has_slots* pnewdest) = 0; }; template class _connection_base3 { public: virtual ~_connection_base3() {} virtual has_slots* getdest() const = 0; virtual void emitSignal(arg1_type, arg2_type, arg3_type) = 0; virtual _connection_base3* clone() = 0; virtual _connection_base3* duplicate(has_slots* pnewdest) = 0; }; template class _connection_base4 { public: virtual ~_connection_base4() {} virtual has_slots* getdest() const = 0; virtual void emitSignal(arg1_type, arg2_type, arg3_type, arg4_type) = 0; virtual _connection_base4* clone() = 0; virtual _connection_base4* duplicate(has_slots* pnewdest) = 0; }; template class _connection_base5 { public: virtual ~_connection_base5() {} virtual has_slots* getdest() const = 0; virtual void emitSignal(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type) = 0; virtual _connection_base5* clone() = 0; virtual _connection_base5* duplicate(has_slots* pnewdest) = 0; }; // ================================================================================================ template class _signal_base : public mt_policy { public: virtual void slot_disconnect(has_slots* pslot) = 0; virtual void slot_duplicate(has_slots const* poldslot, has_slots* pnewslot) = 0; }; template class has_slots : public mt_policy { private: typedef typename std::set<_signal_base *> sender_set; typedef typename sender_set::const_iterator const_iterator; public: has_slots() {} has_slots(has_slots const& hs) : mt_policy(hs) { lock_block_write lock(this); const_iterator it = hs.m_senders.begin(); const_iterator itEnd = hs.m_senders.end(); while (it != itEnd) { (*it)->slot_duplicate(&hs, this); m_senders.insert(*it); ++it; } } void signal_connect(_signal_base* sender) { lock_block_write lock(this); m_senders.insert(sender); } void signal_disconnect(_signal_base* sender) { lock_block_write lock(this); m_senders.erase(sender); } virtual ~has_slots() { disconnect_all(); } void disconnect_all() { lock_block_write lock(this); const_iterator it = m_senders.begin(); const_iterator itEnd = m_senders.end(); while (it != itEnd) { (*it)->slot_disconnect(this); ++it; } m_senders.erase(m_senders.begin(), m_senders.end()); } private: sender_set m_senders; }; template class _signal_base0 : public _signal_base { public: typedef std::list<_connection_base0 *> connections_list; _signal_base0() {} _signal_base0(_signal_base0 const& s) : _signal_base(s) { lock_block_write lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } ~_signal_base0() { disconnect_all(); } void disconnect_all() { lock_block_write lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } void disconnect(has_slots* pclass) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots* pslot) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if ((*it)->getdest() == pslot) { m_connected_slots.erase(it); // delete *it; } it = itNext; } } void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } bool has_connections() const { return !m_connected_slots.empty(); } protected: connections_list m_connected_slots; }; template class _signal_base1 : public _signal_base { public: typedef std::list<_connection_base1 *> connections_list; _signal_base1() {} _signal_base1(_signal_base1 const& s) : _signal_base(s) { lock_block_write lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base1() { disconnect_all(); } void disconnect_all() { lock_block_write lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } void disconnect(has_slots* pclass) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots* pslot) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if ((*it)->getdest() == pslot) { m_connected_slots.erase(it); // delete *it; } it = itNext; } } bool has_connections() const { return !m_connected_slots.empty(); } protected: connections_list m_connected_slots; }; template class _signal_base2 : public _signal_base { public: typedef std::list<_connection_base2 *> connections_list; _signal_base2() {} _signal_base2(_signal_base2 const& s) : _signal_base(s) { lock_block_write lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base2() { disconnect_all(); } void disconnect_all() { lock_block_write lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } void disconnect(has_slots* pclass) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots* pslot) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if ((*it)->getdest() == pslot) { m_connected_slots.erase(it); // delete *it; } it = itNext; } } bool has_connections() const { return !m_connected_slots.empty(); } protected: connections_list m_connected_slots; }; template class _signal_base3 : public _signal_base { public: typedef std::list<_connection_base3 *> connections_list; _signal_base3() {} _signal_base3(_signal_base3 const& s) : _signal_base(s) { lock_block_write lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(has_slots const* oldtarget, has_slots* newtarget) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base3() { disconnect_all(); } void disconnect_all() { lock_block_write lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } void disconnect(has_slots* pclass) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots* pslot) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if ((*it)->getdest() == pslot) { m_connected_slots.erase(it); // delete *it; } it = itNext; } } bool has_connections() const { return !m_connected_slots.empty(); } protected: connections_list m_connected_slots; }; template class _signal_base4 : public _signal_base { public: typedef std::list<_connection_base4 *> connections_list; _signal_base4() {} _signal_base4(const _signal_base4& s) : _signal_base(s) { lock_block_write lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base4() { disconnect_all(); } void disconnect_all() { lock_block_write lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } void disconnect(has_slots* pclass) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots* pslot) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if ((*it)->getdest() == pslot) { m_connected_slots.erase(it); // delete *it; } it = itNext; } } bool has_connections() const { return !m_connected_slots.empty(); } protected: connections_list m_connected_slots; }; template class _signal_base5 : public _signal_base { public: typedef std::list<_connection_base5 *> connections_list; _signal_base5() {} _signal_base5(const _signal_base5& s) : _signal_base(s) { lock_block_write lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base5() { disconnect_all(); } void disconnect_all() { lock_block_write lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while (it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } void disconnect(has_slots* pclass) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { if ((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots* pslot) { lock_block_write lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while (it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if ((*it)->getdest() == pslot) { m_connected_slots.erase(it); // delete *it; } it = itNext; } } bool has_connections() const { return !m_connected_slots.empty(); } protected: connections_list m_connected_slots; }; // ================================================================================================ template class _connection0 : public _connection_base0 { public: _connection0() { m_pobject = 0; m_pmemfun = 0; } _connection0(dest_type* pobject, void (dest_type::*pmemfun)()) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual _connection_base0* clone() { return new _connection0(*this); } virtual _connection_base0* duplicate(has_slots* pnewdest) { return new _connection0((dest_type *)pnewdest, m_pmemfun); } virtual void emitSignal() { (m_pobject->*m_pmemfun)(); } virtual has_slots* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(); }; template class _connection1 : public _connection_base1 { public: _connection1() { m_pobject = 0; m_pmemfun = 0; } _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual _connection_base1* clone() { return new _connection1(*this); } virtual _connection_base1* duplicate(has_slots* pnewdest) { return new _connection1((dest_type *)pnewdest, m_pmemfun); } virtual void emitSignal(arg1_type a1) { (m_pobject->*m_pmemfun)(a1); } virtual has_slots* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type); }; template class _connection2 : public _connection_base2 { public: _connection2() { m_pobject = 0; m_pmemfun = 0; } _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual _connection_base2* clone() { return new _connection2(*this); } virtual _connection_base2* duplicate(has_slots* pnewdest) { return new _connection2((dest_type *)pnewdest, m_pmemfun); } virtual void emitSignal(arg1_type a1, arg2_type a2) { (m_pobject->*m_pmemfun)(a1, a2); } virtual has_slots* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type); }; template class _connection3 : public _connection_base3 { public: _connection3() { m_pobject = 0; m_pmemfun = 0; } _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual _connection_base3* clone() { return new _connection3(*this); } virtual _connection_base3* duplicate(has_slots* pnewdest) { return new _connection3((dest_type *)pnewdest, m_pmemfun); } virtual void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3) { (m_pobject->*m_pmemfun)(a1, a2, a3); } virtual has_slots* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type); }; template class _connection4 : public _connection_base4 { public: _connection4() { m_pobject = 0; m_pmemfun = 0; } _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual _connection_base4* clone() { return new _connection4(*this); } virtual _connection_base4* duplicate(has_slots* pnewdest) { return new _connection4((dest_type *)pnewdest, m_pmemfun); } virtual void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) { (m_pobject->*m_pmemfun)(a1, a2, a3, a4); } virtual has_slots* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type); }; template class _connection5 : public _connection_base5 { public: _connection5() { m_pobject = 0; m_pmemfun = 0; } _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual _connection_base5* clone() { return new _connection5(*this); } virtual _connection_base5* duplicate(has_slots* pnewdest) { return new _connection5((dest_type *)pnewdest, m_pmemfun); } virtual void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) { (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5); } virtual has_slots* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type); }; // ================================================================================================ template class signal0 : public _signal_base0 { public: typedef _signal_base0 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; class signal_handle0 : public _signal_handle_base { public: signal_handle0(signal0* sender) : _sender(sender) {}; ~signal_handle0() {}; // override void emitSignal() const { lock_block_read lock(_sender); typename connections_list::const_iterator itNext, it = _sender->m_connected_slots.begin(); typename connections_list::const_iterator itEnd = _sender->m_connected_slots.end(); while (it != itEnd) { itNext = it; ++itNext; (*it)->emitSignal(); it = itNext; } }; signal0* _sender; }; signal0() {} signal0(const signal0& s) : _signal_base0(s) {} template void connect(desttype* pclass, void (desttype::*pmemfun)()) { lock_block_write lock(this); _connection0* conn = new _connection0(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emitSignal() { signal_handle0* sh = new signal_handle0(this); signal_manager::getRef().triggerSignal(sh); } void operator()() { signal_handle0* sh = new signal_handle0(this); signal_manager::getRef().queueSignal(sh); } }; template class signal1 : public _signal_base1 { public: typedef _signal_base1 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; class signal_handle1 : public _signal_handle_base { public: signal_handle1(signal1* sender, arg1_type a1) : _sender(sender) , _a1(a1) {}; ~signal_handle1() {}; // override void emitSignal() const { lock_block_read lock(_sender); typename connections_list::const_iterator itNext, it = _sender->m_connected_slots.begin(); typename connections_list::const_iterator itEnd = _sender->m_connected_slots.end(); while (it != itEnd) { itNext = it; ++itNext; (*it)->emitSignal(_a1); it = itNext; } }; signal1* _sender; arg1_type _a1; }; signal1() {} signal1(const signal1& s) : _signal_base1(s) {} template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type)) { lock_block_write lock(this); _connection1* conn = new _connection1(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emitSignal(arg1_type a1) { signal_handle1* sh = new signal_handle1(this, a1); signal_manager::getRef().triggerSignal(sh); } void operator()(arg1_type a1) { signal_handle1* sh = new signal_handle1(this, a1); signal_manager::getRef().queueSignal(sh); } }; template class signal2 : public _signal_base2 { public: typedef _signal_base2 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; class signal_handle2 : public _signal_handle_base { public: signal_handle2(signal2* sender, arg1_type a1, arg2_type a2) : _sender(sender) , _a1(a1) , _a2(a2) {}; ~signal_handle2() {}; // override void emitSignal() const { lock_block_read lock(_sender); typename connections_list::const_iterator itNext, it = _sender->m_connected_slots.begin(); typename connections_list::const_iterator itEnd = _sender->m_connected_slots.end(); while (it != itEnd) { itNext = it; ++itNext; (*it)->emitSignal(_a1, _a2); it = itNext; } }; signal2* _sender; arg1_type _a1; arg2_type _a2; }; signal2() {} signal2(const signal2& s) : _signal_base2(s) {} template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type)) { lock_block_write lock(this); _connection2* conn = new _connection2(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emitSignal(arg1_type a1, arg2_type a2) { signal_handle2* sh = new signal_handle2(this, a1, a2); signal_manager::getRef().triggerSignal(sh); } void operator()(arg1_type a1, arg2_type a2) { signal_handle2* sh = new signal_handle2(this, a1, a2); signal_manager::getRef().queueSignal(sh); } }; template class signal3 : public _signal_base3 { public: typedef _signal_base3 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; class signal_handle3 : public _signal_handle_base { public: signal_handle3(signal3* sender, arg1_type a1, arg2_type a2, arg3_type a3) : _sender(sender) , _a1(a1) , _a2(a2) , _a3(a3) {}; ~signal_handle3() {}; // override void emitSignal() const { lock_block_read lock(_sender); typename connections_list::const_iterator itNext, it = _sender->m_connected_slots.begin(); typename connections_list::const_iterator itEnd = _sender->m_connected_slots.end(); while (it != itEnd) { itNext = it; ++itNext; (*it)->emitSignal(_a1, _a2, _a3); it = itNext; } }; signal3* _sender; arg1_type _a1; arg2_type _a2; arg3_type _a3; }; signal3() {} signal3(const signal3& s) : _signal_base3(s) {} template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type)) { lock_block_write lock(this); _connection3* conn = new _connection3(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3) { signal_handle3* sh = new signal_handle3(this, a1, a2, a3); signal_manager::getRef().triggerSignal(sh); } void operator()(arg1_type a1, arg2_type a2, arg3_type a3) { signal_handle3* sh = new signal_handle3(this, a1, a2, a3); signal_manager::getRef().queueSignal(sh); } }; template class signal4 : public _signal_base4 { public: typedef _signal_base4 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; class signal_handle4 : public _signal_handle_base { public: signal_handle4(signal4* sender, arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) : _sender(sender) , _a1(a1) , _a2(a2) , _a3(a3) , _a4(a4) {}; ~signal_handle4() {}; // override void emitSignal() const { lock_block_read lock(_sender); typename connections_list::const_iterator itNext, it = _sender->m_connected_slots.begin(); typename connections_list::const_iterator itEnd = _sender->m_connected_slots.end(); while (it != itEnd) { itNext = it; ++itNext; (*it)->emitSignal(_a1, _a2, _a3, _a4); it = itNext; } }; signal4* _sender; arg1_type _a1; arg2_type _a2; arg3_type _a3; arg4_type _a4; }; signal4() {} signal4(const signal4& s) : _signal_base4(s) {} template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type)) { lock_block_write lock(this); _connection4* conn = new _connection4(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) { signal_handle4* sh = new signal_handle4(this, a1, a2, a3, a4); signal_manager::getRef().triggerSignal(sh); } void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) { signal_handle4* sh = new signal_handle4(this, a1, a2, a3, a4); signal_manager::getRef().queueSignal(sh); } }; template class signal5 : public _signal_base5 { public: typedef _signal_base5 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; class signal_handle5 : public _signal_handle_base { public: signal_handle5(signal5* sender, arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) : _sender(sender) , _a1(a1) , _a2(a2) , _a3(a3) , _a4(a4) , _a5(a5) {}; ~signal_handle5() {}; // override void emitSignal() const { lock_block_read lock(_sender); typename connections_list::const_iterator itNext, it = _sender->m_connected_slots.begin(); typename connections_list::const_iterator itEnd = _sender->m_connected_slots.end(); while (it != itEnd) { itNext = it; ++itNext; (*it)->emitSignal(_a1, _a2, _a3, _a4, _a5); it = itNext; } }; signal5* _sender; arg1_type _a1; arg2_type _a2; arg3_type _a3; arg4_type _a4; arg5_type _a5; }; signal5() {} signal5(const signal5& s) : _signal_base5(s) {} template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type)) { lock_block_write lock(this); _connection5* conn = new _connection5(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) { signal_handle5* sh = new signal_handle5(this, a1, a2, a3, a4, a5); signal_manager::getRef().triggerSignal(sh); } void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) { signal_handle5* sh = new signal_handle5(this, a1, a2, a3, a4, a5); signal_manager::getRef().queueSignal(sh); } }; } // namespace sigslot #endif // SIGSLOT_H