Chris@16: /* Chris@16: boost::signals2::connection provides a handle to a signal/slot connection. Chris@16: Chris@16: Author: Frank Mori Hess Chris@16: Begin: 2007-01-23 Chris@16: */ Chris@16: // Copyright Frank Mori Hess 2007-2008. Chris@16: // Distributed under the Boost Software License, Version Chris@16: // 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // See http://www.boost.org/libs/signals2 for library home page. Chris@16: Chris@16: #ifndef BOOST_SIGNALS2_CONNECTION_HPP Chris@16: #define BOOST_SIGNALS2_CONNECTION_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: namespace signals2 Chris@16: { Chris@16: extern inline void null_deleter(const void*) {} Chris@16: namespace detail Chris@16: { Chris@16: class connection_body_base Chris@16: { Chris@16: public: Chris@16: connection_body_base(): Chris@16: _connected(true) Chris@16: { Chris@16: } Chris@16: virtual ~connection_body_base() {} Chris@16: void disconnect() Chris@16: { Chris@16: unique_lock local_lock(*this); Chris@16: nolock_disconnect(); Chris@16: } Chris@16: void nolock_disconnect() Chris@16: { Chris@16: _connected = false; Chris@16: } Chris@16: virtual bool connected() const = 0; Chris@16: shared_ptr get_blocker() Chris@16: { Chris@16: unique_lock local_lock(*this); Chris@16: shared_ptr blocker = _weak_blocker.lock(); Chris@16: if(blocker == shared_ptr()) Chris@16: { Chris@16: blocker.reset(this, &null_deleter); Chris@16: _weak_blocker = blocker; Chris@16: } Chris@16: return blocker; Chris@16: } Chris@16: bool blocked() const Chris@16: { Chris@16: return !_weak_blocker.expired(); Chris@16: } Chris@16: bool nolock_nograb_blocked() const Chris@16: { Chris@16: return nolock_nograb_connected() == false || blocked(); Chris@16: } Chris@16: bool nolock_nograb_connected() const {return _connected;} Chris@16: // expose part of Lockable concept of mutex Chris@16: virtual void lock() = 0; Chris@16: virtual void unlock() = 0; Chris@16: Chris@16: protected: Chris@16: Chris@16: mutable bool _connected; Chris@16: weak_ptr _weak_blocker; Chris@16: }; Chris@16: Chris@16: template Chris@16: class connection_body: public connection_body_base Chris@16: { Chris@16: public: Chris@16: typedef Mutex mutex_type; Chris@16: connection_body(const SlotType &slot_in): Chris@16: slot(slot_in) Chris@16: { Chris@16: } Chris@16: virtual ~connection_body() {} Chris@16: virtual bool connected() const Chris@16: { Chris@16: unique_lock local_lock(_mutex); Chris@16: nolock_grab_tracked_objects(detail::null_output_iterator()); Chris@16: return nolock_nograb_connected(); Chris@16: } Chris@16: const GroupKey& group_key() const {return _group_key;} Chris@16: void set_group_key(const GroupKey &key) {_group_key = key;} Chris@16: bool nolock_slot_expired() const Chris@16: { Chris@16: bool expired = slot.expired(); Chris@16: if(expired == true) Chris@16: { Chris@16: _connected = false; Chris@16: } Chris@16: return expired; Chris@16: } Chris@16: template Chris@16: void nolock_grab_tracked_objects(OutputIterator inserter) const Chris@16: { Chris@16: slot_base::tracked_container_type::const_iterator it; Chris@16: for(it = slot.tracked_objects().begin(); Chris@16: it != slot.tracked_objects().end(); Chris@16: ++it) Chris@16: { Chris@16: void_shared_ptr_variant locked_object Chris@16: ( Chris@16: apply_visitor Chris@16: ( Chris@16: detail::lock_weak_ptr_visitor(), Chris@16: *it Chris@16: ) Chris@16: ); Chris@16: if(apply_visitor(detail::expired_weak_ptr_visitor(), *it)) Chris@16: { Chris@16: _connected = false; Chris@16: return; Chris@16: } Chris@16: *inserter++ = locked_object; Chris@16: } Chris@16: } Chris@16: // expose Lockable concept of mutex Chris@16: virtual void lock() Chris@16: { Chris@16: _mutex.lock(); Chris@16: } Chris@16: virtual void unlock() Chris@16: { Chris@16: _mutex.unlock(); Chris@16: } Chris@16: SlotType slot; Chris@16: private: Chris@16: mutable mutex_type _mutex; Chris@16: GroupKey _group_key; Chris@16: }; Chris@16: } Chris@16: Chris@16: class shared_connection_block; Chris@16: Chris@16: class connection Chris@16: { Chris@16: public: Chris@16: friend class shared_connection_block; Chris@16: Chris@16: connection() {} Chris@16: connection(const connection &other): _weak_connection_body(other._weak_connection_body) Chris@16: {} Chris@16: connection(const boost::weak_ptr &connectionBody): Chris@16: _weak_connection_body(connectionBody) Chris@16: {} Chris@101: Chris@101: // move support Chris@101: #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) Chris@101: connection(connection && other): _weak_connection_body(std::move(other._weak_connection_body)) Chris@101: { Chris@101: // make sure other is reset, in case it is a scoped_connection (so it Chris@101: // won't disconnect on destruction after being moved away from). Chris@101: other._weak_connection_body.reset(); Chris@101: } Chris@101: connection & operator=(connection && other) Chris@101: { Chris@101: if(&other == this) return *this; Chris@101: _weak_connection_body = std::move(other._weak_connection_body); Chris@101: // make sure other is reset, in case it is a scoped_connection (so it Chris@101: // won't disconnect on destruction after being moved away from). Chris@101: other._weak_connection_body.reset(); Chris@101: return *this; Chris@101: } Chris@101: #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) Chris@101: connection & operator=(const connection & other) Chris@101: { Chris@101: if(&other == this) return *this; Chris@101: _weak_connection_body = other._weak_connection_body; Chris@101: return *this; Chris@101: } Chris@101: Chris@16: ~connection() {} Chris@16: void disconnect() const Chris@16: { Chris@16: boost::shared_ptr connectionBody(_weak_connection_body.lock()); Chris@16: if(connectionBody == 0) return; Chris@16: connectionBody->disconnect(); Chris@16: } Chris@16: bool connected() const Chris@16: { Chris@16: boost::shared_ptr connectionBody(_weak_connection_body.lock()); Chris@16: if(connectionBody == 0) return false; Chris@16: return connectionBody->connected(); Chris@16: } Chris@16: bool blocked() const Chris@16: { Chris@16: boost::shared_ptr connectionBody(_weak_connection_body.lock()); Chris@16: if(connectionBody == 0) return true; Chris@16: return connectionBody->blocked(); Chris@16: } Chris@16: bool operator==(const connection& other) const Chris@16: { Chris@16: boost::shared_ptr connectionBody(_weak_connection_body.lock()); Chris@16: boost::shared_ptr otherConnectionBody(other._weak_connection_body.lock()); Chris@16: return connectionBody == otherConnectionBody; Chris@16: } Chris@16: bool operator!=(const connection& other) const Chris@16: { Chris@16: return !(*this == other); Chris@16: } Chris@16: bool operator<(const connection& other) const Chris@16: { Chris@16: boost::shared_ptr connectionBody(_weak_connection_body.lock()); Chris@16: boost::shared_ptr otherConnectionBody(other._weak_connection_body.lock()); Chris@16: return connectionBody < otherConnectionBody; Chris@16: } Chris@16: void swap(connection &other) Chris@16: { Chris@16: using std::swap; Chris@16: swap(_weak_connection_body, other._weak_connection_body); Chris@16: } Chris@16: protected: Chris@16: Chris@16: boost::weak_ptr _weak_connection_body; Chris@16: }; Chris@16: inline void swap(connection &conn1, connection &conn2) Chris@16: { Chris@16: conn1.swap(conn2); Chris@16: } Chris@16: Chris@16: class scoped_connection: public connection Chris@16: { Chris@16: public: Chris@16: scoped_connection() {} Chris@16: scoped_connection(const connection &other): Chris@16: connection(other) Chris@16: {} Chris@16: ~scoped_connection() Chris@16: { Chris@16: disconnect(); Chris@16: } Chris@16: scoped_connection& operator=(const connection &rhs) Chris@16: { Chris@16: disconnect(); Chris@16: connection::operator=(rhs); Chris@16: return *this; Chris@16: } Chris@101: Chris@101: // move support Chris@101: #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) Chris@101: scoped_connection(scoped_connection && other): connection(std::move(other)) Chris@101: { Chris@101: } Chris@101: scoped_connection(connection && other): connection(std::move(other)) Chris@101: { Chris@101: } Chris@101: scoped_connection & operator=(scoped_connection && other) Chris@101: { Chris@101: if(&other == this) return *this; Chris@101: disconnect(); Chris@101: connection::operator=(std::move(other)); Chris@101: return *this; Chris@101: } Chris@101: scoped_connection & operator=(connection && other) Chris@101: { Chris@101: if(&other == this) return *this; Chris@101: disconnect(); Chris@101: connection::operator=(std::move(other)); Chris@101: return *this; Chris@101: } Chris@101: #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) Chris@101: Chris@16: connection release() Chris@16: { Chris@16: connection conn(_weak_connection_body); Chris@16: _weak_connection_body.reset(); Chris@16: return conn; Chris@16: } Chris@16: private: Chris@16: scoped_connection(const scoped_connection &other); Chris@16: scoped_connection& operator=(const scoped_connection &rhs); Chris@16: }; Chris@16: // Sun 5.9 compiler doesn't find the swap for base connection class when Chris@16: // arguments are scoped_connection, so we provide this explicitly. Chris@16: inline void swap(scoped_connection &conn1, scoped_connection &conn2) Chris@16: { Chris@16: conn1.swap(conn2); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: #endif // BOOST_SIGNALS2_CONNECTION_HPP