/* * $Id: callback.h.in,v 1.1 2007/07/19 08:24:50 pippijn Exp $ */ #ifndef CALLBACK_H #define CALLBACK_H #include #include namespace callback { class event_base; class has_listeners { private: typedef std::set sender_set; typedef sender_set::const_iterator const_iterator; typedef sender_set::iterator iterator; sender_set m_senders; sender_set &invokers (); const sender_set &invokers () const; public: has_listeners (); has_listeners (const has_listeners &rhs); virtual ~has_listeners (); has_listeners &operator = (const has_listeners &rhs); void add_invoker (event_base *sender); void remove_invoker (event_base *sender); protected: void copy_invokers (const has_listeners &rhs); void disconnect_all (); }; typedef has_listeners listening_base; class event_base { public: virtual ~event_base () { } event_base () { } inline bool detach (listening_base *plistener) { return this->listener_detach (plistener); } virtual bool listener_duplicate (const listening_base *poldlistener, listening_base *pnewlistener) = 0; protected: virtual bool listener_detach (listening_base *plistener) = 0; template void free_connections (list_T &list) { typename list_T::const_iterator it; typename list_T::const_iterator it_end = list.end (); for (it = list.begin (); it != it_end; ++it) { (*it)->getdest ()->remove_invoker (this); delete *it; } list.clear (); } template bool detach (listening_base *plistener, list_T &list) { typename list_T::iterator it; typename list_T::iterator it_end = list.end (); for (it = list.begin (); it != it_end; ++it) { if ((*it)->getdest () == plistener) { delete *it; list.erase (it); plistener->remove_invoker (this); return true; } } return false; } template bool duplicate_connection (const listeningT *oldtarget, listeningT *newtarget, SetT &list) { typename SetT::iterator it = list.begin (); typename SetT::iterator it_end = list.end (); bool ret = false; for (; it != it_end; ++it) { if ((*it)->getdest () == oldtarget) { list.push_back ((*it)->duplicate (newtarget)); ret = true; } } return ret; } template void copy_connections (const SetT &src, SetT &tgt) { if (&src == &tgt) return ; typename SetT::const_iterator it = src.begin (); typename SetT::const_iterator it_end = src.end (); typedef typename SetT::value_type ConT; ConT clone = 0; for (; it != it_end; ++it) { clone = (*it)->clone (); if (!clone) continue; clone->getdest ()->add_invoker (this); tgt.push_back (clone); } } }; class connection_base0 { public: virtual ~connection_base0 () { } typedef connection_base0 this_type; virtual listening_base *getdest () const = 0; virtual void invoke () const = 0; virtual this_type *clone () const = 0; virtual this_type *duplicate (listening_base *pnewdest) const = 0; }; template class connection_base1 { public: virtual ~connection_base1 () { } typedef connection_base1 this_type; virtual listening_base *getdest () const = 0; virtual void invoke (arg1_type) const = 0; virtual this_type *clone () const = 0; virtual this_type *duplicate (listening_base *pnewdest) const = 0; }; template class connection0 : public connection_base0 { public: typedef connection_base0 base_type; typedef connection0 this_type; typedef void (dest_type::*listener_fun) (); connection0 (): m_pobject (0), m_pmemfun (0){} virtual ~connection0 () { } connection0 (dest_type *pobject, listener_fun pmemfun): m_pobject (pobject), m_pmemfun (pmemfun){} virtual base_type *clone () const { return new this_type (*this); } virtual base_type *duplicate (listening_base *pnewdest) const { return new this_type (dynamic_cast (pnewdest), m_pmemfun); } virtual void invoke () const { (m_pobject->*m_pmemfun) (); } virtual listening_base *getdest () const { return m_pobject; } private: dest_type *m_pobject; listener_fun m_pmemfun; }; template class connection1 : public connection_base1 { public: typedef connection_base1 base_type; typedef connection1 this_type; typedef void (dest_type::*listener_fun) (arg1_type); connection1 (): m_pobject (0), m_pmemfun (0){} connection1 (dest_type *pobject, listener_fun pmemfun): m_pobject (pobject), m_pmemfun (pmemfun){} virtual ~connection1 () { } virtual base_type *clone () const { return new this_type (*this); } virtual base_type *duplicate (listening_base *pnewdest) const { return new this_type (dynamic_cast (pnewdest), m_pmemfun); } virtual void invoke (arg1_type a1) const { (m_pobject->*m_pmemfun) (a1); } virtual listening_base *getdest () const { return m_pobject; } private: dest_type *m_pobject; listener_fun m_pmemfun; }; class event0 : public event_base { public: typedef std::list connection_list; event0 () { } event0 (const event0 &s): event_base (s) { this->copy_connections (s.connections (), this->connections ()); } event0 &operator = (const event0 &s) { this->copy_connections (s.connections (), this->connections ()); return *this; } virtual ~event0 () { this->disconnect_all (); } void disconnect_all () { this->free_connections (this->connections ()); } template void attach (desttype *pclass, void (desttype::*pmemfun) ()) { connection_base0 *conn = new connection0 (pclass, pmemfun); this->connections ().push_back (conn); pclass->add_invoker (this); } bool listener_duplicate (const listening_base *oldtarget, listening_base *newtarget) { return this->duplicate_connection (oldtarget, newtarget, this->connections ()); } void invoke () const { connection_list::const_iterator it; connection_list::const_iterator end = this->connections ().end (); for (it = this->connections ().begin (); it != end; ++it) (*it)->invoke (); } void operator () () const { this->invoke (); } protected: connection_list &connections () { return this->m_connected_listeners; } const connection_list &connections () const { return this->m_connected_listeners; } bool listener_detach (listening_base *plistener) { return this->detach (plistener, this->connections ()); } private: connection_list m_connected_listeners; }; template class event1 : public event_base { public: typedef std::list *> connection_list; event1 () { } event1 (const event1 &s): event_base (s) { } template void attach (dest_type *pclass, void (dest_type::*pmemfun) (arg1_type)) { connection_base1 *conn = new connection1 (pclass, pmemfun); this->connections ().push_back (conn); pclass->add_invoker (this); } void invoke (arg1_type a1) const { typename connection_list::const_iterator it; typename connection_list::const_iterator it_end = this->connections ().end (); for (it = this->connections ().begin (); it != it_end; ++it) { (*it)->invoke (a1); } } void operator () (arg1_type a1) const { this->invoke (a1); } event1 &operator = (const event1 &s) { this->copy_connections (s.connections (), this->connections ()); return *this; } bool listener_duplicate (const listening_base *oldtarget, listening_base *newtarget) { return this->duplicate_connection (oldtarget, newtarget, this->connections ()); } ~event1 () { this->disconnect_all (); } void disconnect_all () { this->free_connections (connections ()); } protected: connection_list &connections () { return this->m_connected_listeners; } const connection_list &connections () const { return this->m_connected_listeners; } bool listener_detach (listening_base *plistener) { return this->detach (plistener, this->connections ()); } private: connection_list m_connected_listeners; }; @CALLBACKS@ } // namespace callback class has_callbacks { protected: struct callbacks { callback::event1 created; callback::event1 destroyed; }; static callbacks callback; has_callbacks (); ~has_callbacks (); }; #endif // CALLBACK_H