LCOV - code coverage report
Current view: top level - opt/homebrew/include/boost/signals2 - connection.hpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 89 111 80.2 %
Date: 2026-06-25 07:23:51 Functions: 82 261 31.4 %

          Line data    Source code
       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/config.hpp>
      18             : #include <boost/core/noncopyable.hpp>
      19             : #include <boost/function.hpp>
      20             : #include <boost/mpl/bool.hpp>
      21             : #include <boost/shared_ptr.hpp>
      22             : #include <boost/signals2/detail/auto_buffer.hpp>
      23             : #include <boost/signals2/detail/null_output_iterator.hpp>
      24             : #include <boost/signals2/detail/unique_lock.hpp>
      25             : #include <boost/signals2/slot.hpp>
      26             : #include <boost/weak_ptr.hpp>
      27             : 
      28             : namespace boost
      29             : {
      30             :   namespace signals2
      31             :   {
      32             :     inline void null_deleter(const void*) {}
      33             :     namespace detail
      34             :     {
      35             :       // This lock maintains a list of shared_ptr<void>
      36             :       // which will be destroyed only after the lock
      37             :       // has released its mutex.  Used to garbage
      38             :       // collect disconnected slots
      39             :       template<typename Mutex>
      40             :       class garbage_collecting_lock: public noncopyable
      41             :       {
      42             :       public:
      43      167700 :         garbage_collecting_lock(Mutex &m):
      44       83850 :           lock(m)
      45      167700 :         {}
      46         336 :         void add_trash(const shared_ptr<void> &piece_of_trash)
      47             :         {
      48         336 :           garbage.push_back(piece_of_trash);
      49         336 :         }
      50             :       private:
      51             :         // garbage must be declared before lock
      52             :         // to insure it is destroyed after lock is
      53             :         // destroyed.
      54             :         auto_buffer<shared_ptr<void>, store_n_objects<10> > garbage;
      55             :         unique_lock<Mutex> lock;
      56             :       };
      57             :       
      58             :       class connection_body_base
      59             :       {
      60             :       public:
      61        1424 :         connection_body_base():
      62         712 :           _connected(true), m_slot_refcount(1)
      63         712 :         {
      64         712 :         }
      65         364 :         virtual ~connection_body_base() {}
      66         336 :         void disconnect()
      67             :         {
      68         336 :           garbage_collecting_lock<connection_body_base> local_lock(*this);
      69         336 :           nolock_disconnect(local_lock);
      70         336 :         }
      71             :         template<typename Mutex>
      72         336 :         void nolock_disconnect(garbage_collecting_lock<Mutex> &lock_arg) const
      73             :         {
      74         336 :           if(_connected)
      75             :           {
      76         336 :             _connected = false;
      77         336 :             dec_slot_refcount(lock_arg);
      78         336 :           }
      79         336 :         }
      80             :         virtual bool connected() const = 0;
      81             :         shared_ptr<void> get_blocker()
      82             :         {
      83             :           unique_lock<connection_body_base> local_lock(*this);
      84             :           shared_ptr<void> blocker = _weak_blocker.lock();
      85             :           if(blocker == shared_ptr<void>())
      86             :           {
      87             :             blocker.reset(this, &null_deleter);
      88             :             _weak_blocker = blocker;
      89             :           }
      90             :           return blocker;
      91             :         }
      92         235 :         bool blocked() const
      93             :         {
      94         235 :           return !_weak_blocker.expired();
      95             :         }
      96         235 :         bool nolock_nograb_blocked() const
      97             :         {
      98         235 :           return nolock_nograb_connected() == false || blocked();
      99             :         }
     100        1041 :         bool nolock_nograb_connected() const {return _connected;}
     101             :         // expose part of Lockable concept of mutex
     102             :         virtual void lock() = 0;
     103             :         virtual void unlock() = 0;
     104             : 
     105             :         // Slot refcount should be incremented while
     106             :         // a signal invocation is using the slot, in order
     107             :         // to prevent slot from being destroyed mid-invocation.
     108             :         // garbage_collecting_lock parameter enforces 
     109             :         // the existance of a lock before this
     110             :         // method is called
     111             :         template<typename Mutex>
     112         235 :         void inc_slot_refcount(const garbage_collecting_lock<Mutex> &)
     113             :         {
     114         235 :           BOOST_ASSERT(m_slot_refcount != 0);
     115         235 :           ++m_slot_refcount;
     116         235 :         }
     117             :         // if slot refcount decrements to zero due to this call, 
     118             :         // it puts a
     119             :         // shared_ptr to the slot in the garbage collecting lock,
     120             :         // which will destroy the slot only after it unlocks.
     121             :         template<typename Mutex>
     122         571 :         void dec_slot_refcount(garbage_collecting_lock<Mutex> &lock_arg) const
     123             :         {
     124         571 :           BOOST_ASSERT(m_slot_refcount != 0);
     125         571 :           if(--m_slot_refcount == 0)
     126             :           {
     127         336 :             lock_arg.add_trash(release_slot());
     128         336 :           }
     129         571 :         }
     130             : 
     131             :       protected:
     132             :         virtual shared_ptr<void> release_slot() const = 0;
     133             : 
     134             :         weak_ptr<void> _weak_blocker;
     135             :       private:
     136             :         mutable bool _connected;
     137             :         mutable unsigned m_slot_refcount;
     138             :       };
     139             : 
     140             :       template<typename GroupKey, typename SlotType, typename Mutex>
     141             :       class connection_body: public connection_body_base
     142             :       {
     143             :       public:
     144             :         typedef Mutex mutex_type;
     145        2136 :         connection_body(const SlotType &slot_in, const boost::shared_ptr<mutex_type> &signal_mutex):
     146         712 :           m_slot(new SlotType(slot_in)), _mutex(signal_mutex)
     147        1424 :         {
     148        1424 :         }
     149         728 :         virtual ~connection_body() {}
     150           0 :         virtual bool connected() const
     151             :         {
     152           0 :           garbage_collecting_lock<mutex_type> local_lock(*_mutex);
     153           0 :           nolock_grab_tracked_objects(local_lock, detail::null_output_iterator());
     154           0 :           return nolock_nograb_connected();
     155           0 :         }
     156         336 :         const GroupKey& group_key() const {return _group_key;}
     157         712 :         void set_group_key(const GroupKey &key) {_group_key = key;}
     158             :         template<typename M>
     159         336 :         void disconnect_expired_slot(garbage_collecting_lock<M> &lock_arg)
     160             :         {
     161         336 :           if(!m_slot) return;
     162           0 :           bool expired = slot().expired();
     163           0 :           if(expired == true)
     164             :           {
     165           0 :             nolock_disconnect(lock_arg);
     166           0 :           }
     167         336 :         }
     168             :         template<typename M, typename OutputIterator>
     169         235 :         void nolock_grab_tracked_objects(garbage_collecting_lock<M> &lock_arg,
     170             :           OutputIterator inserter) const
     171             :         {
     172         235 :           if(!m_slot) return;
     173         235 :           slot_base::tracked_container_type::const_iterator it;
     174         461 :           for(it = slot().tracked_objects().begin();
     175         461 :             it != slot().tracked_objects().end();
     176         226 :             ++it)
     177             :           {
     178             :             void_shared_ptr_variant locked_object
     179             :             (
     180         226 :               apply_visitor
     181             :               (
     182             :                 detail::lock_weak_ptr_visitor(),
     183         226 :                 *it
     184             :               )
     185             :             );
     186         226 :             if(apply_visitor(detail::expired_weak_ptr_visitor(), *it))
     187             :             {
     188           0 :               nolock_disconnect(lock_arg);
     189           0 :               return;
     190             :             }
     191         226 :             *inserter++ = locked_object;
     192         226 :           }
     193         235 :         }
     194             :         // expose Lockable concept of mutex
     195         806 :         virtual void lock()
     196             :         {
     197         806 :           _mutex->lock();
     198         806 :         }
     199         806 :         virtual void unlock()
     200             :         {
     201         806 :           _mutex->unlock();
     202         806 :         }
     203         235 :         SlotType &slot()
     204             :         {
     205         235 :           return *m_slot;
     206             :         }
     207         696 :         const SlotType &slot() const
     208             :         {
     209         696 :           return *m_slot;
     210             :         }
     211             :       protected:
     212         336 :         virtual shared_ptr<void> release_slot() const
     213             :         {
     214             :           
     215         336 :           shared_ptr<void> released_slot = m_slot;
     216         336 :           m_slot.reset();
     217         336 :           return released_slot;
     218         336 :         }
     219             :       private:
     220             :         mutable boost::shared_ptr<SlotType> m_slot;
     221             :         const boost::shared_ptr<mutex_type> _mutex;
     222             :         GroupKey _group_key;
     223             :       };
     224             :     }
     225             : 
     226             :     class shared_connection_block;
     227             : 
     228             :     class connection
     229             :     {
     230             :     public:
     231             :       friend class shared_connection_block;
     232             : 
     233        1168 :       connection() BOOST_NOEXCEPT {}
     234             :       connection(const connection &other) BOOST_NOEXCEPT: _weak_connection_body(other._weak_connection_body)
     235             :       {}
     236        1424 :       connection(const boost::weak_ptr<detail::connection_body_base> &connectionBody) BOOST_NOEXCEPT:
     237         712 :         _weak_connection_body(connectionBody)
     238        1424 :       {}
     239             :       
     240             :       // move support
     241             : #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
     242           0 :       connection(connection && other) BOOST_NOEXCEPT: _weak_connection_body(std::move(other._weak_connection_body))
     243           0 :       {
     244             :         // make sure other is reset, in case it is a scoped_connection (so it
     245             :         // won't disconnect on destruction after being moved away from).
     246           0 :         other._weak_connection_body.reset();
     247           0 :       }
     248         684 :       connection & operator=(connection && other) BOOST_NOEXCEPT
     249             :       {
     250         684 :         if(&other == this) return *this;
     251         684 :         _weak_connection_body = std::move(other._weak_connection_body);
     252             :         // make sure other is reset, in case it is a scoped_connection (so it
     253             :         // won't disconnect on destruction after being moved away from).
     254         684 :         other._weak_connection_body.reset();
     255         684 :         return *this;
     256         684 :       }
     257             : #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
     258             :       connection & operator=(const connection & other) BOOST_NOEXCEPT
     259             :       {
     260             :         if(&other == this) return *this;
     261             :         _weak_connection_body = other._weak_connection_body;
     262             :         return *this;
     263             :       }
     264             : 
     265        1424 :       ~connection() {}
     266         336 :       void disconnect() const
     267             :       {
     268         336 :         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
     269         336 :         if(connectionBody == 0) return;
     270         336 :         connectionBody->disconnect();
     271         336 :       }
     272             :       bool connected() const
     273             :       {
     274             :         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
     275             :         if(connectionBody == 0) return false;
     276             :         return connectionBody->connected();
     277             :       }
     278             :       bool blocked() const
     279             :       {
     280             :         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
     281             :         if(connectionBody == 0) return true;
     282             :         return connectionBody->blocked();
     283             :       }
     284             :       bool operator==(const connection& other) const
     285             :       {
     286             :         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
     287             :         boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
     288             :         return connectionBody == otherConnectionBody;
     289             :       }
     290             :       bool operator!=(const connection& other) const
     291             :       {
     292             :         return !(*this == other);
     293             :       }
     294             :       bool operator<(const connection& other) const
     295             :       {
     296             :         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
     297             :         boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
     298             :         return connectionBody < otherConnectionBody;
     299             :       }
     300             :       void swap(connection &other) BOOST_NOEXCEPT
     301             :       {
     302             :         using std::swap;
     303             :         swap(_weak_connection_body, other._weak_connection_body);
     304             :       }
     305             :     protected:
     306             : 
     307             :       boost::weak_ptr<detail::connection_body_base> _weak_connection_body;
     308             :     };
     309             :     inline void swap(connection &conn1, connection &conn2) BOOST_NOEXCEPT
     310             :     {
     311             :       conn1.swap(conn2);
     312             :     }
     313             : 
     314             :     class scoped_connection: public connection
     315             :     {
     316             :     public:
     317             :       scoped_connection() BOOST_NOEXCEPT {}
     318             :       scoped_connection(const connection &other) BOOST_NOEXCEPT:
     319             :         connection(other)
     320             :       {}
     321           0 :       ~scoped_connection()
     322           0 :       {
     323           0 :         disconnect();
     324           0 :       }
     325             :       scoped_connection& operator=(const connection &rhs) BOOST_NOEXCEPT
     326             :       {
     327             :         disconnect();
     328             :         connection::operator=(rhs);
     329             :         return *this;
     330             :       }
     331             : 
     332             :       // move support
     333             : #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
     334             :       scoped_connection(scoped_connection && other) BOOST_NOEXCEPT: connection(std::move(other))
     335             :       {
     336             :       }
     337           0 :       scoped_connection(connection && other) BOOST_NOEXCEPT: connection(std::move(other))
     338           0 :       {
     339           0 :       }
     340             :       scoped_connection & operator=(scoped_connection && other) BOOST_NOEXCEPT
     341             :       {
     342             :         if(&other == this) return *this;
     343             :         disconnect();
     344             :         connection::operator=(std::move(other));
     345             :         return *this;
     346             :       }
     347             :       scoped_connection & operator=(connection && other) BOOST_NOEXCEPT
     348             :       {
     349             :         if(&other == this) return *this;
     350             :         disconnect();
     351             :         connection::operator=(std::move(other));
     352             :         return *this;
     353             :       }
     354             : #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
     355             : 
     356             :       connection release()
     357             :       {
     358             :         connection conn(_weak_connection_body);
     359             :         _weak_connection_body.reset();
     360             :         return conn;
     361             :       }
     362             :     private:
     363             :       scoped_connection(const scoped_connection &other);
     364             :       scoped_connection& operator=(const scoped_connection &rhs);
     365             :     };
     366             :     // Sun 5.9 compiler doesn't find the swap for base connection class when
     367             :     // arguments are scoped_connection, so we provide this explicitly.
     368             :     inline void swap(scoped_connection &conn1, scoped_connection &conn2) BOOST_NOEXCEPT
     369             :     {
     370             :       conn1.swap(conn2);
     371             :     }
     372             :   }
     373             : }
     374             : 
     375             : #endif  // BOOST_SIGNALS2_CONNECTION_HPP

Generated by: LCOV version 1.16