Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:08:48

0001 /*
0002   boost::signals2::connection provides a handle to a signal/slot connection.
0003 
0004   Author: Frank Mori Hess <fmhess@users.sourceforge.net>
0005   Begin: 2007-01-23
0006 */
0007 // Copyright Frank Mori Hess 2007-2008.
0008 // Distributed under the Boost Software License, Version
0009 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0010 // http://www.boost.org/LICENSE_1_0.txt)
0011 
0012 // See http://www.boost.org/libs/signals2 for library home page.
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       // This lock maintains a list of shared_ptr<void>
0036       // which will be destroyed only after the lock
0037       // has released its mutex.  Used to garbage
0038       // collect disconnected slots
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         // garbage must be declared before lock
0052         // to insure it is destroyed after lock is
0053         // destroyed.
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         // expose part of Lockable concept of mutex
0102         virtual void lock() = 0;
0103         virtual void unlock() = 0;
0104 
0105         // Slot refcount should be incremented while
0106         // a signal invocation is using the slot, in order
0107         // to prevent slot from being destroyed mid-invocation.
0108         // garbage_collecting_lock parameter enforces 
0109         // the existance of a lock before this
0110         // method is called
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         // if slot refcount decrements to zero due to this call, 
0118         // it puts a
0119         // shared_ptr to the slot in the garbage collecting lock,
0120         // which will destroy the slot only after it unlocks.
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         // expose Lockable concept of mutex
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       // move support
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         // make sure other is reset, in case it is a scoped_connection (so it
0245         // won't disconnect on destruction after being moved away from).
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         // make sure other is reset, in case it is a scoped_connection (so it
0253         // won't disconnect on destruction after being moved away from).
0254         other._weak_connection_body.reset();
0255         return *this;
0256       }
0257 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
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       // move support
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 // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
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     // Sun 5.9 compiler doesn't find the swap for base connection class when
0367     // arguments are scoped_connection, so we provide this explicitly.
0368     inline void swap(scoped_connection &conn1, scoped_connection &conn2) BOOST_NOEXCEPT
0369     {
0370       conn1.swap(conn2);
0371     }
0372   }
0373 }
0374 
0375 #endif  // BOOST_SIGNALS2_CONNECTION_HPP