#ifndef lite__Signal__hpp_ #define lite__Signal__hpp_ #include "Connection.hpp" #include "boost/any.hpp" #include "boost/function.hpp" #include namespace lite { namespace signals { namespace detail { typedef unsigned long Signal_Info_Id; template struct Signal_Info { typedef boost::function Function_Type; Signal_Info_Id id_; Function_Type function_; Signal_Info( Signal_Info_Id id, Function_Type const & function) : id_(id) , function_(function) { } }; template class Signal_Base { public: typedef Signal_Base self_type; private: struct Connection_Token { Signal_Base * signal_; Signal_Info_Id id_; Connection_Token( Signal_Base * signal, Signal_Info_Id id) : signal_(signal) , id_(id) { } }; public: typedef boost::function< Signature > Function_Type; typedef Typed_Connection Connection; friend class Connection; typedef Connection connection_type; private: typedef Signal_Info< Signature > Info; public: Signal_Base() : id_pool_(0) , list_() { } Connection connect( Function_Type const & f) { Info info(id_pool_++, f); list_.push_back(info); return Connection(Connection_Token(this, info.id_)); } void disconnect( signals::Connection const & conn) { disconnect_(boost::any_cast(&conn.token())); } void replace( signals::Connection const & conn, Function_Type const & func) { replace_(boost::any_cast(&conn.token()), func); } void disconnect_all() { list_.clear(); } void disconnect_all_slots() { disconnect_all(); } private: Signal_Info_Id id_pool_; protected: // A vector is quite a bit faster, but the disconnect/connect code // becomes a bit more complex, especially when allowing them // inside a signal handler... // In my testing, I see measurable performance difference // when we have more than 1000 slots. Since our typical use cases // do not get near than number, I'll leave it like this for now. typedef std::list< Info > list; mutable list list_; private: void replace_( Connection_Token const * token, Function_Type const & function) { if (token && token->signal_ == this) { typename list::iterator i = list_.begin(); typename list::iterator const end = list_.end(); for (; i != end; ++i) { if (i->id_ == token->id_) { i->function_ = function; break; } } } } void disconnect_( Connection_Token const * token) { replace_(token, Function_Type()); } static void disconnect_any_token( boost::any const & any_token) { Connection_Token const * token( boost::any_cast(&any_token)); if (token && token->signal_) { token->signal_->disconnect_(token); } } static void replace_any_token( boost::any const & any_token, boost::any const & any_func) { Connection_Token const * token( boost::any_cast(&any_token)); if (token && token->signal_) { Function_Type function(boost::any_cast(any_func)); token->signal_->replace_(token, function); } } }; } // end detail namespace template struct Signal; template struct Signal : public detail::Signal_Base< R (void)> { R operator()(void) const { typename list::iterator i = list_.begin(); while (i != list_.end()) { if (i->function_) { (i++)->function_(); } else { i = list_.erase(i); } } } }; template struct Signal : public detail::Signal_Base< R (T1)> { R operator()(T1 t1) const { typename list::iterator i = list_.begin(); while (i != list_.end()) { if (i->function_) { (i++)->function_(t1); } else { i = list_.erase(i); } } } }; template struct Signal : public detail::Signal_Base< R (T1, T2)> { R operator()(T1 t1, T2 t2) const { typename list::iterator i = list_.begin(); while (i != list_.end()) { if (i->function_) { (i++)->function_(t1, t2); } else { i = list_.erase(i); } } } }; template struct Signal : public detail::Signal_Base< R (T1, T2, T3)> { R operator()(T1 t1, T2 t2, T3 t3) const { typename list::iterator i = list_.begin(); while (i != list_.end()) { if (i->function_) { (i++)->function_(t1, t2, t3); } else { i = list_.erase(i); } } } }; template struct Signal : public detail::Signal_Base< R (T1, T2, T3, T4)> { R operator()(T1 t1, T2 t2, T3 t3, T4 t4) const { typename list::iterator i = list_.begin(); while (i != list_.end()) { if (i->function_) { (i++)->function_(t1, t2, t3, t4); } else { i = list_.erase(i); } } } }; template struct Signal : public detail::Signal_Base< R (T1, T2, T3, T4, T5)> { R operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) const { typename list::iterator i = list_.begin(); while (i != list_.end()) { if (i->function_) { (i++)->function_(t1, t2, t3, t4, t5); } else { i = list_.erase(i); } } } }; template struct Signal : public detail::Signal_Base< R (T1, T2, T3, T4, T5, T6)> { R operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) const { typename list::iterator i = list_.begin(); while (i != list_.end()) { if (i->function_) { (i++)->function_(t1, t2, t3, t4, t5, t6); } else { i = list_.erase(i); } } } }; template struct Signal : public detail::Signal_Base< R (T1, T2, T3, T4, T5, T6, T7)> { R operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) const { typename list::iterator i = list_.begin(); while (i != list_.end()) { if (i->function_) { (i++)->function_(t1, t2, t3, t4, t5, t6, t7); } else { i = list_.erase(i); } } } }; } // end signals namespace } // end lite namespace #endif // lite__Signal__hpp_