1 /* 2 boost::signals2::connection provides a handle to a signal/slot connection. 3 4 Author: Frank Mori Hess <fmhess@users.sourceforge.net> 5 Begin: 2007-01-23 6 */ 7 // Copyright Frank Mori Hess 2007-2008. 8 // Distributed under the Boost Software License, Version 9 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at 10 // http://www.boost.org/LICENSE_1_0.txt) 11 12 // See http://www.boost.org/libs/signals2 for library home page. 13 14 #ifndef BOOST_SIGNALS2_CONNECTION_HPP 15 #define BOOST_SIGNALS2_CONNECTION_HPP 16 17 #include <boost/function.hpp> 18 #include <boost/mpl/bool.hpp> 19 #include <boost/noncopyable.hpp> 20 #include <boost/shared_ptr.hpp> 21 #include <boost/signals2/detail/null_output_iterator.hpp> 22 #include <boost/signals2/detail/unique_lock.hpp> 23 #include <boost/signals2/slot.hpp> 24 #include <boost/weak_ptr.hpp> 25 26 namespace boost 27 { 28 namespace signals2 29 { null_deleter(const void *)30 extern inline void null_deleter(const void*) {} 31 namespace detail 32 { 33 class connection_body_base 34 { 35 public: connection_body_base()36 connection_body_base(): 37 _connected(true) 38 { 39 } ~connection_body_base()40 virtual ~connection_body_base() {} disconnect()41 void disconnect() 42 { 43 unique_lock<connection_body_base> local_lock(*this); 44 nolock_disconnect(); 45 } nolock_disconnect()46 void nolock_disconnect() 47 { 48 _connected = false; 49 } 50 virtual bool connected() const = 0; get_blocker()51 shared_ptr<void> get_blocker() 52 { 53 unique_lock<connection_body_base> local_lock(*this); 54 shared_ptr<void> blocker = _weak_blocker.lock(); 55 if(blocker == shared_ptr<void>()) 56 { 57 blocker.reset(this, &null_deleter); 58 _weak_blocker = blocker; 59 } 60 return blocker; 61 } blocked() const62 bool blocked() const 63 { 64 return !_weak_blocker.expired(); 65 } nolock_nograb_blocked() const66 bool nolock_nograb_blocked() const 67 { 68 return nolock_nograb_connected() == false || blocked(); 69 } nolock_nograb_connected() const70 bool nolock_nograb_connected() const {return _connected;} 71 // expose part of Lockable concept of mutex 72 virtual void lock() = 0; 73 virtual void unlock() = 0; 74 75 protected: 76 77 mutable bool _connected; 78 weak_ptr<void> _weak_blocker; 79 }; 80 81 template<typename GroupKey, typename SlotType, typename Mutex> 82 class connection_body: public connection_body_base 83 { 84 public: 85 typedef Mutex mutex_type; connection_body(const SlotType & slot_in)86 connection_body(const SlotType &slot_in): 87 slot(slot_in) 88 { 89 } ~connection_body()90 virtual ~connection_body() {} connected() const91 virtual bool connected() const 92 { 93 unique_lock<mutex_type> local_lock(_mutex); 94 nolock_grab_tracked_objects(detail::null_output_iterator()); 95 return nolock_nograb_connected(); 96 } group_key() const97 const GroupKey& group_key() const {return _group_key;} set_group_key(const GroupKey & key)98 void set_group_key(const GroupKey &key) {_group_key = key;} nolock_slot_expired() const99 bool nolock_slot_expired() const 100 { 101 bool expired = slot.expired(); 102 if(expired == true) 103 { 104 _connected = false; 105 } 106 return expired; 107 } 108 template<typename OutputIterator> nolock_grab_tracked_objects(OutputIterator inserter) const109 void nolock_grab_tracked_objects(OutputIterator inserter) const 110 { 111 slot_base::tracked_container_type::const_iterator it; 112 for(it = slot.tracked_objects().begin(); 113 it != slot.tracked_objects().end(); 114 ++it) 115 { 116 void_shared_ptr_variant locked_object 117 ( 118 apply_visitor 119 ( 120 detail::lock_weak_ptr_visitor(), 121 *it 122 ) 123 ); 124 if(apply_visitor(detail::expired_weak_ptr_visitor(), *it)) 125 { 126 _connected = false; 127 return; 128 } 129 *inserter++ = locked_object; 130 } 131 } 132 // expose Lockable concept of mutex lock()133 virtual void lock() 134 { 135 _mutex.lock(); 136 } unlock()137 virtual void unlock() 138 { 139 _mutex.unlock(); 140 } 141 SlotType slot; 142 private: 143 mutable mutex_type _mutex; 144 GroupKey _group_key; 145 }; 146 } 147 148 class shared_connection_block; 149 150 class connection 151 { 152 public: 153 friend class shared_connection_block; 154 connection()155 connection() {} connection(const connection & other)156 connection(const connection &other): _weak_connection_body(other._weak_connection_body) 157 {} connection(const boost::weak_ptr<detail::connection_body_base> & connectionBody)158 connection(const boost::weak_ptr<detail::connection_body_base> &connectionBody): 159 _weak_connection_body(connectionBody) 160 {} ~connection()161 ~connection() {} disconnect() const162 void disconnect() const 163 { 164 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock()); 165 if(connectionBody == 0) return; 166 connectionBody->disconnect(); 167 } connected() const168 bool connected() const 169 { 170 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock()); 171 if(connectionBody == 0) return false; 172 return connectionBody->connected(); 173 } blocked() const174 bool blocked() const 175 { 176 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock()); 177 if(connectionBody == 0) return true; 178 return connectionBody->blocked(); 179 } operator ==(const connection & other) const180 bool operator==(const connection& other) const 181 { 182 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock()); 183 boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock()); 184 return connectionBody == otherConnectionBody; 185 } operator !=(const connection & other) const186 bool operator!=(const connection& other) const 187 { 188 return !(*this == other); 189 } operator <(const connection & other) const190 bool operator<(const connection& other) const 191 { 192 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock()); 193 boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock()); 194 return connectionBody < otherConnectionBody; 195 } swap(connection & other)196 void swap(connection &other) 197 { 198 using std::swap; 199 swap(_weak_connection_body, other._weak_connection_body); 200 } 201 protected: 202 203 boost::weak_ptr<detail::connection_body_base> _weak_connection_body; 204 }; swap(connection & conn1,connection & conn2)205 inline void swap(connection &conn1, connection &conn2) 206 { 207 conn1.swap(conn2); 208 } 209 210 class scoped_connection: public connection 211 { 212 public: scoped_connection()213 scoped_connection() {} scoped_connection(const connection & other)214 scoped_connection(const connection &other): 215 connection(other) 216 {} ~scoped_connection()217 ~scoped_connection() 218 { 219 disconnect(); 220 } operator =(const connection & rhs)221 scoped_connection& operator=(const connection &rhs) 222 { 223 disconnect(); 224 connection::operator=(rhs); 225 return *this; 226 } release()227 connection release() 228 { 229 connection conn(_weak_connection_body); 230 _weak_connection_body.reset(); 231 return conn; 232 } 233 private: 234 scoped_connection(const scoped_connection &other); 235 scoped_connection& operator=(const scoped_connection &rhs); 236 }; 237 // Sun 5.9 compiler doesn't find the swap for base connection class when 238 // arguments are scoped_connection, so we provide this explicitly. swap(scoped_connection & conn1,scoped_connection & conn2)239 inline void swap(scoped_connection &conn1, scoped_connection &conn2) 240 { 241 conn1.swap(conn2); 242 } 243 } 244 } 245 246 #endif // BOOST_SIGNALS2_CONNECTION_HPP 247