| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 | /*  boost::signals2::connection provides a handle to a signal/slot connection.  Author: Frank Mori Hess <fmhess@users.sourceforge.net>  Begin: 2007-01-23*/// Copyright Frank Mori Hess 2007-2008.// Distributed under the Boost Software License, Version// 1.0. (See accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt)// See http://www.boost.org/libs/signals2 for library home page.#ifndef BOOST_SIGNALS2_CONNECTION_HPP#define BOOST_SIGNALS2_CONNECTION_HPP#include <boost/function.hpp>#include <boost/mpl/bool.hpp>#include <boost/noncopyable.hpp>#include <boost/shared_ptr.hpp>#include <boost/signals2/detail/auto_buffer.hpp>#include <boost/signals2/detail/null_output_iterator.hpp>#include <boost/signals2/detail/unique_lock.hpp>#include <boost/signals2/slot.hpp>#include <boost/weak_ptr.hpp>namespace boost{  namespace signals2  {    inline void null_deleter(const void*) {}    namespace detail    {      // This lock maintains a list of shared_ptr<void>      // which will be destroyed only after the lock      // has released its mutex.  Used to garbage      // collect disconnected slots      template<typename Mutex>      class garbage_collecting_lock: public noncopyable      {      public:        garbage_collecting_lock(Mutex &m):          lock(m)        {}        void add_trash(const shared_ptr<void> &piece_of_trash)        {          garbage.push_back(piece_of_trash);        }      private:        // garbage must be declared before lock        // to insure it is destroyed after lock is        // destroyed.        auto_buffer<shared_ptr<void>, store_n_objects<10> > garbage;        unique_lock<Mutex> lock;      };            class connection_body_base      {      public:        connection_body_base():          _connected(true), m_slot_refcount(1)        {        }        virtual ~connection_body_base() {}        void disconnect()        {          garbage_collecting_lock<connection_body_base> local_lock(*this);          nolock_disconnect(local_lock);        }        template<typename Mutex>        void nolock_disconnect(garbage_collecting_lock<Mutex> &lock_arg) const        {          if(_connected)          {            _connected = false;            dec_slot_refcount(lock_arg);          }        }        virtual bool connected() const = 0;        shared_ptr<void> get_blocker()        {          unique_lock<connection_body_base> local_lock(*this);          shared_ptr<void> blocker = _weak_blocker.lock();          if(blocker == shared_ptr<void>())          {            blocker.reset(this, &null_deleter);            _weak_blocker = blocker;          }          return blocker;        }        bool blocked() const        {          return !_weak_blocker.expired();        }        bool nolock_nograb_blocked() const        {          return nolock_nograb_connected() == false || blocked();        }        bool nolock_nograb_connected() const {return _connected;}        // expose part of Lockable concept of mutex        virtual void lock() = 0;        virtual void unlock() = 0;        // Slot refcount should be incremented while        // a signal invocation is using the slot, in order        // to prevent slot from being destroyed mid-invocation.        // garbage_collecting_lock parameter enforces         // the existance of a lock before this        // method is called        template<typename Mutex>        void inc_slot_refcount(const garbage_collecting_lock<Mutex> &)        {          BOOST_ASSERT(m_slot_refcount != 0);          ++m_slot_refcount;        }        // if slot refcount decrements to zero due to this call,         // it puts a        // shared_ptr to the slot in the garbage collecting lock,        // which will destroy the slot only after it unlocks.        template<typename Mutex>        void dec_slot_refcount(garbage_collecting_lock<Mutex> &lock_arg) const        {          BOOST_ASSERT(m_slot_refcount != 0);          if(--m_slot_refcount == 0)          {            lock_arg.add_trash(release_slot());          }        }      protected:        virtual shared_ptr<void> release_slot() const = 0;        weak_ptr<void> _weak_blocker;      private:        mutable bool _connected;        mutable unsigned m_slot_refcount;      };      template<typename GroupKey, typename SlotType, typename Mutex>      class connection_body: public connection_body_base      {      public:        typedef Mutex mutex_type;        connection_body(const SlotType &slot_in, const boost::shared_ptr<mutex_type> &signal_mutex):          m_slot(new SlotType(slot_in)), _mutex(signal_mutex)        {        }        virtual ~connection_body() {}        virtual bool connected() const        {          garbage_collecting_lock<mutex_type> local_lock(*_mutex);          nolock_grab_tracked_objects(local_lock, detail::null_output_iterator());          return nolock_nograb_connected();        }        const GroupKey& group_key() const {return _group_key;}        void set_group_key(const GroupKey &key) {_group_key = key;}        template<typename M>        void disconnect_expired_slot(garbage_collecting_lock<M> &lock_arg)        {          if(!m_slot) return;          bool expired = slot().expired();          if(expired == true)          {            nolock_disconnect(lock_arg);          }        }        template<typename M, typename OutputIterator>        void nolock_grab_tracked_objects(garbage_collecting_lock<M> &lock_arg,          OutputIterator inserter) const        {          if(!m_slot) return;          slot_base::tracked_container_type::const_iterator it;          for(it = slot().tracked_objects().begin();            it != slot().tracked_objects().end();            ++it)          {            void_shared_ptr_variant locked_object            (              apply_visitor              (                detail::lock_weak_ptr_visitor(),                *it              )            );            if(apply_visitor(detail::expired_weak_ptr_visitor(), *it))            {              nolock_disconnect(lock_arg);              return;            }            *inserter++ = locked_object;          }        }        // expose Lockable concept of mutex        virtual void lock()        {          _mutex->lock();        }        virtual void unlock()        {          _mutex->unlock();        }        SlotType &slot()        {          return *m_slot;        }        const SlotType &slot() const        {          return *m_slot;        }      protected:        virtual shared_ptr<void> release_slot() const        {                    shared_ptr<void> released_slot = m_slot;          m_slot.reset();          return released_slot;        }      private:        mutable boost::shared_ptr<SlotType> m_slot;        const boost::shared_ptr<mutex_type> _mutex;        GroupKey _group_key;      };    }    class shared_connection_block;    class connection    {    public:      friend class shared_connection_block;      connection() {}      connection(const connection &other): _weak_connection_body(other._weak_connection_body)      {}      connection(const boost::weak_ptr<detail::connection_body_base> &connectionBody):        _weak_connection_body(connectionBody)      {}            // move support#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)      connection(connection && other): _weak_connection_body(std::move(other._weak_connection_body))      {        // make sure other is reset, in case it is a scoped_connection (so it        // won't disconnect on destruction after being moved away from).        other._weak_connection_body.reset();      }      connection & operator=(connection && other)      {        if(&other == this) return *this;        _weak_connection_body = std::move(other._weak_connection_body);        // make sure other is reset, in case it is a scoped_connection (so it        // won't disconnect on destruction after being moved away from).        other._weak_connection_body.reset();        return *this;      }#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)      connection & operator=(const connection & other)      {        if(&other == this) return *this;        _weak_connection_body = other._weak_connection_body;        return *this;      }      ~connection() {}      void disconnect() const      {        boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());        if(connectionBody == 0) return;        connectionBody->disconnect();      }      bool connected() const      {        boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());        if(connectionBody == 0) return false;        return connectionBody->connected();      }      bool blocked() const      {        boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());        if(connectionBody == 0) return true;        return connectionBody->blocked();      }      bool operator==(const connection& other) const      {        boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());        boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());        return connectionBody == otherConnectionBody;      }      bool operator!=(const connection& other) const      {        return !(*this == other);      }      bool operator<(const connection& other) const      {        boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());        boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());        return connectionBody < otherConnectionBody;      }      void swap(connection &other)      {        using std::swap;        swap(_weak_connection_body, other._weak_connection_body);      }    protected:      boost::weak_ptr<detail::connection_body_base> _weak_connection_body;    };    inline void swap(connection &conn1, connection &conn2)    {      conn1.swap(conn2);    }    class scoped_connection: public connection    {    public:      scoped_connection() {}      scoped_connection(const connection &other):        connection(other)      {}      ~scoped_connection()      {        disconnect();      }      scoped_connection& operator=(const connection &rhs)      {        disconnect();        connection::operator=(rhs);        return *this;      }      // move support#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)      scoped_connection(scoped_connection && other): connection(std::move(other))      {      }      scoped_connection(connection && other): connection(std::move(other))      {      }      scoped_connection & operator=(scoped_connection && other)      {        if(&other == this) return *this;        disconnect();        connection::operator=(std::move(other));        return *this;      }      scoped_connection & operator=(connection && other)      {        if(&other == this) return *this;        disconnect();        connection::operator=(std::move(other));        return *this;      }#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)      connection release()      {        connection conn(_weak_connection_body);        _weak_connection_body.reset();        return conn;      }    private:      scoped_connection(const scoped_connection &other);      scoped_connection& operator=(const scoped_connection &rhs);    };    // Sun 5.9 compiler doesn't find the swap for base connection class when    // arguments are scoped_connection, so we provide this explicitly.    inline void swap(scoped_connection &conn1, scoped_connection &conn2)    {      conn1.swap(conn2);    }  }}#endif  // BOOST_SIGNALS2_CONNECTION_HPP
 |