File indexing completed on 2025-12-16 10:08:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_SIGNALS2_CONNECTION_HPP
0015 #define BOOST_SIGNALS2_CONNECTION_HPP
0016
0017 #include <boost/config.hpp>
0018 #include <boost/core/noncopyable.hpp>
0019 #include <boost/function.hpp>
0020 #include <boost/mpl/bool.hpp>
0021 #include <boost/shared_ptr.hpp>
0022 #include <boost/signals2/detail/auto_buffer.hpp>
0023 #include <boost/signals2/detail/null_output_iterator.hpp>
0024 #include <boost/signals2/detail/unique_lock.hpp>
0025 #include <boost/signals2/slot.hpp>
0026 #include <boost/weak_ptr.hpp>
0027
0028 namespace boost
0029 {
0030 namespace signals2
0031 {
0032 inline void null_deleter(const void*) {}
0033 namespace detail
0034 {
0035
0036
0037
0038
0039 template<typename Mutex>
0040 class garbage_collecting_lock: public noncopyable
0041 {
0042 public:
0043 garbage_collecting_lock(Mutex &m):
0044 lock(m)
0045 {}
0046 void add_trash(const shared_ptr<void> &piece_of_trash)
0047 {
0048 garbage.push_back(piece_of_trash);
0049 }
0050 private:
0051
0052
0053
0054 auto_buffer<shared_ptr<void>, store_n_objects<10> > garbage;
0055 unique_lock<Mutex> lock;
0056 };
0057
0058 class connection_body_base
0059 {
0060 public:
0061 connection_body_base():
0062 _connected(true), m_slot_refcount(1)
0063 {
0064 }
0065 virtual ~connection_body_base() {}
0066 void disconnect()
0067 {
0068 garbage_collecting_lock<connection_body_base> local_lock(*this);
0069 nolock_disconnect(local_lock);
0070 }
0071 template<typename Mutex>
0072 void nolock_disconnect(garbage_collecting_lock<Mutex> &lock_arg) const
0073 {
0074 if(_connected)
0075 {
0076 _connected = false;
0077 dec_slot_refcount(lock_arg);
0078 }
0079 }
0080 virtual bool connected() const = 0;
0081 shared_ptr<void> get_blocker()
0082 {
0083 unique_lock<connection_body_base> local_lock(*this);
0084 shared_ptr<void> blocker = _weak_blocker.lock();
0085 if(blocker == shared_ptr<void>())
0086 {
0087 blocker.reset(this, &null_deleter);
0088 _weak_blocker = blocker;
0089 }
0090 return blocker;
0091 }
0092 bool blocked() const
0093 {
0094 return !_weak_blocker.expired();
0095 }
0096 bool nolock_nograb_blocked() const
0097 {
0098 return nolock_nograb_connected() == false || blocked();
0099 }
0100 bool nolock_nograb_connected() const {return _connected;}
0101
0102 virtual void lock() = 0;
0103 virtual void unlock() = 0;
0104
0105
0106
0107
0108
0109
0110
0111 template<typename Mutex>
0112 void inc_slot_refcount(const garbage_collecting_lock<Mutex> &)
0113 {
0114 BOOST_ASSERT(m_slot_refcount != 0);
0115 ++m_slot_refcount;
0116 }
0117
0118
0119
0120
0121 template<typename Mutex>
0122 void dec_slot_refcount(garbage_collecting_lock<Mutex> &lock_arg) const
0123 {
0124 BOOST_ASSERT(m_slot_refcount != 0);
0125 if(--m_slot_refcount == 0)
0126 {
0127 lock_arg.add_trash(release_slot());
0128 }
0129 }
0130
0131 protected:
0132 virtual shared_ptr<void> release_slot() const = 0;
0133
0134 weak_ptr<void> _weak_blocker;
0135 private:
0136 mutable bool _connected;
0137 mutable unsigned m_slot_refcount;
0138 };
0139
0140 template<typename GroupKey, typename SlotType, typename Mutex>
0141 class connection_body: public connection_body_base
0142 {
0143 public:
0144 typedef Mutex mutex_type;
0145 connection_body(const SlotType &slot_in, const boost::shared_ptr<mutex_type> &signal_mutex):
0146 m_slot(new SlotType(slot_in)), _mutex(signal_mutex)
0147 {
0148 }
0149 virtual ~connection_body() {}
0150 virtual bool connected() const
0151 {
0152 garbage_collecting_lock<mutex_type> local_lock(*_mutex);
0153 nolock_grab_tracked_objects(local_lock, detail::null_output_iterator());
0154 return nolock_nograb_connected();
0155 }
0156 const GroupKey& group_key() const {return _group_key;}
0157 void set_group_key(const GroupKey &key) {_group_key = key;}
0158 template<typename M>
0159 void disconnect_expired_slot(garbage_collecting_lock<M> &lock_arg)
0160 {
0161 if(!m_slot) return;
0162 bool expired = slot().expired();
0163 if(expired == true)
0164 {
0165 nolock_disconnect(lock_arg);
0166 }
0167 }
0168 template<typename M, typename OutputIterator>
0169 void nolock_grab_tracked_objects(garbage_collecting_lock<M> &lock_arg,
0170 OutputIterator inserter) const
0171 {
0172 if(!m_slot) return;
0173 slot_base::tracked_container_type::const_iterator it;
0174 for(it = slot().tracked_objects().begin();
0175 it != slot().tracked_objects().end();
0176 ++it)
0177 {
0178 void_shared_ptr_variant locked_object
0179 (
0180 apply_visitor
0181 (
0182 detail::lock_weak_ptr_visitor(),
0183 *it
0184 )
0185 );
0186 if(apply_visitor(detail::expired_weak_ptr_visitor(), *it))
0187 {
0188 nolock_disconnect(lock_arg);
0189 return;
0190 }
0191 *inserter++ = locked_object;
0192 }
0193 }
0194
0195 virtual void lock()
0196 {
0197 _mutex->lock();
0198 }
0199 virtual void unlock()
0200 {
0201 _mutex->unlock();
0202 }
0203 SlotType &slot()
0204 {
0205 return *m_slot;
0206 }
0207 const SlotType &slot() const
0208 {
0209 return *m_slot;
0210 }
0211 protected:
0212 virtual shared_ptr<void> release_slot() const
0213 {
0214
0215 shared_ptr<void> released_slot = m_slot;
0216 m_slot.reset();
0217 return released_slot;
0218 }
0219 private:
0220 mutable boost::shared_ptr<SlotType> m_slot;
0221 const boost::shared_ptr<mutex_type> _mutex;
0222 GroupKey _group_key;
0223 };
0224 }
0225
0226 class shared_connection_block;
0227
0228 class connection
0229 {
0230 public:
0231 friend class shared_connection_block;
0232
0233 connection() BOOST_NOEXCEPT {}
0234 connection(const connection &other) BOOST_NOEXCEPT: _weak_connection_body(other._weak_connection_body)
0235 {}
0236 connection(const boost::weak_ptr<detail::connection_body_base> &connectionBody) BOOST_NOEXCEPT:
0237 _weak_connection_body(connectionBody)
0238 {}
0239
0240
0241 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0242 connection(connection && other) BOOST_NOEXCEPT: _weak_connection_body(std::move(other._weak_connection_body))
0243 {
0244
0245
0246 other._weak_connection_body.reset();
0247 }
0248 connection & operator=(connection && other) BOOST_NOEXCEPT
0249 {
0250 if(&other == this) return *this;
0251 _weak_connection_body = std::move(other._weak_connection_body);
0252
0253
0254 other._weak_connection_body.reset();
0255 return *this;
0256 }
0257 #endif
0258 connection & operator=(const connection & other) BOOST_NOEXCEPT
0259 {
0260 if(&other == this) return *this;
0261 _weak_connection_body = other._weak_connection_body;
0262 return *this;
0263 }
0264
0265 ~connection() {}
0266 void disconnect() const
0267 {
0268 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
0269 if(connectionBody == 0) return;
0270 connectionBody->disconnect();
0271 }
0272 bool connected() const
0273 {
0274 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
0275 if(connectionBody == 0) return false;
0276 return connectionBody->connected();
0277 }
0278 bool blocked() const
0279 {
0280 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
0281 if(connectionBody == 0) return true;
0282 return connectionBody->blocked();
0283 }
0284 bool operator==(const connection& other) const
0285 {
0286 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
0287 boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
0288 return connectionBody == otherConnectionBody;
0289 }
0290 bool operator!=(const connection& other) const
0291 {
0292 return !(*this == other);
0293 }
0294 bool operator<(const connection& other) const
0295 {
0296 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
0297 boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
0298 return connectionBody < otherConnectionBody;
0299 }
0300 void swap(connection &other) BOOST_NOEXCEPT
0301 {
0302 using std::swap;
0303 swap(_weak_connection_body, other._weak_connection_body);
0304 }
0305 protected:
0306
0307 boost::weak_ptr<detail::connection_body_base> _weak_connection_body;
0308 };
0309 inline void swap(connection &conn1, connection &conn2) BOOST_NOEXCEPT
0310 {
0311 conn1.swap(conn2);
0312 }
0313
0314 class scoped_connection: public connection
0315 {
0316 public:
0317 scoped_connection() BOOST_NOEXCEPT {}
0318 scoped_connection(const connection &other) BOOST_NOEXCEPT:
0319 connection(other)
0320 {}
0321 ~scoped_connection()
0322 {
0323 disconnect();
0324 }
0325 scoped_connection& operator=(const connection &rhs) BOOST_NOEXCEPT
0326 {
0327 disconnect();
0328 connection::operator=(rhs);
0329 return *this;
0330 }
0331
0332
0333 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0334 scoped_connection(scoped_connection && other) BOOST_NOEXCEPT: connection(std::move(other))
0335 {
0336 }
0337 scoped_connection(connection && other) BOOST_NOEXCEPT: connection(std::move(other))
0338 {
0339 }
0340 scoped_connection & operator=(scoped_connection && other) BOOST_NOEXCEPT
0341 {
0342 if(&other == this) return *this;
0343 disconnect();
0344 connection::operator=(std::move(other));
0345 return *this;
0346 }
0347 scoped_connection & operator=(connection && other) BOOST_NOEXCEPT
0348 {
0349 if(&other == this) return *this;
0350 disconnect();
0351 connection::operator=(std::move(other));
0352 return *this;
0353 }
0354 #endif
0355
0356 connection release()
0357 {
0358 connection conn(_weak_connection_body);
0359 _weak_connection_body.reset();
0360 return conn;
0361 }
0362 private:
0363 scoped_connection(const scoped_connection &other);
0364 scoped_connection& operator=(const scoped_connection &rhs);
0365 };
0366
0367
0368 inline void swap(scoped_connection &conn1, scoped_connection &conn2) BOOST_NOEXCEPT
0369 {
0370 conn1.swap(conn2);
0371 }
0372 }
0373 }
0374
0375 #endif