Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r56639 - in trunk: boost/signals2 boost/signals2/detail libs/signals2/test
From: fmhess_at_[hidden]
Date: 2009-10-07 16:56:57


Author: fmhess
Date: 2009-10-07 16:56:56 EDT (Wed, 07 Oct 2009)
New Revision: 56639
URL: http://svn.boost.org/trac/boost/changeset/56639

Log:
Added support for tracking of objects owned by non-boost
shared_ptr. No documentation yet.

Added:
   trunk/boost/signals2/detail/foreign_ptr.hpp (contents, props changed)
Text files modified:
   trunk/boost/signals2/connection.hpp | 30 ++++++++++++++++++------------
   trunk/boost/signals2/detail/replace_slot_function.hpp | 7 +------
   trunk/boost/signals2/detail/slot_call_iterator.hpp | 2 +-
   trunk/boost/signals2/detail/slot_template.hpp | 25 ++++++++++++++++++++++---
   trunk/boost/signals2/slot_base.hpp | 40 ++++++++++++++++++++++++++++++++--------
   trunk/libs/signals2/test/track_test.cpp | 32 ++++++++++++++++++++++++++++++++
   6 files changed, 106 insertions(+), 30 deletions(-)

Modified: trunk/boost/signals2/connection.hpp
==============================================================================
--- trunk/boost/signals2/connection.hpp (original)
+++ trunk/boost/signals2/connection.hpp 2009-10-07 16:56:56 EDT (Wed, 07 Oct 2009)
@@ -108,19 +108,25 @@
         template<typename OutputIterator>
           void nolock_grab_tracked_objects(OutputIterator inserter) const
         {
- slot_base::tracked_container_type::const_iterator it;
- for(it = slot.tracked_objects().begin();
- it != slot.tracked_objects().end();
- ++it)
+ 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))
             {
- boost::shared_ptr<void> locked_object = it->lock();
- boost::shared_ptr<void> empty;
- if(!(empty < locked_object) && !(locked_object < empty))
- {
- _connected = false;
- return;
- }
- *inserter++ = locked_object;
+ _connected = false;
+ return;
+ }
+ *inserter++ = locked_object;
           }
         }
         // expose Lockable concept of mutex

Added: trunk/boost/signals2/detail/foreign_ptr.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/signals2/detail/foreign_ptr.hpp 2009-10-07 16:56:56 EDT (Wed, 07 Oct 2009)
@@ -0,0 +1,182 @@
+
+// helper code for dealing with tracking non-boost shared_ptr/weak_ptr
+
+// Copyright Frank Mori Hess 2009.
+// 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_FOREIGN_PTR_HPP
+#define BOOST_SIGNALS2_FOREIGN_PTR_HPP
+
+#include <algorithm>
+#include <boost/assert.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/smart_ptr/bad_weak_ptr.hpp>
+#include <boost/utility/swap.hpp>
+
+namespace std
+{
+ template<typename T> class shared_ptr;
+ template<typename T> class weak_ptr;
+}
+
+namespace boost
+{
+ template<typename T> class shared_ptr;
+ template<typename T> class weak_ptr;
+
+ namespace signals2
+ {
+ template<typename WeakPtr> struct weak_ptr_traits
+ {};
+ template<typename T> struct weak_ptr_traits<boost::weak_ptr<T> >
+ {
+ typedef boost::shared_ptr<T> shared_type;
+ };
+ template<typename T> struct weak_ptr_traits<std::weak_ptr<T> >
+ {
+ typedef std::shared_ptr<T> shared_type;
+ };
+
+ template<typename SharedPtr> struct shared_ptr_traits
+ {};
+
+ template<typename T> struct shared_ptr_traits<boost::shared_ptr<T> >
+ {
+ typedef boost::weak_ptr<T> weak_type;
+ };
+ template<typename T> struct shared_ptr_traits<std::shared_ptr<T> >
+ {
+ typedef std::weak_ptr<T> weak_type;
+ };
+
+ namespace detail
+ {
+ struct foreign_shared_ptr_impl_base
+ {
+ virtual ~foreign_shared_ptr_impl_base() {}
+ virtual void* get() const = 0;
+ virtual foreign_shared_ptr_impl_base * clone() const = 0;
+ };
+
+ template<typename FSP>
+ class foreign_shared_ptr_impl: public foreign_shared_ptr_impl_base
+ {
+ public:
+ foreign_shared_ptr_impl(const FSP &p): _p(p)
+ {}
+ virtual void * get() const
+ {
+ return _p.get();
+ }
+ virtual foreign_shared_ptr_impl * clone() const
+ {
+ return new foreign_shared_ptr_impl(*this);
+ }
+ private:
+ FSP _p;
+ };
+
+ class foreign_void_shared_ptr
+ {
+ public:
+ foreign_void_shared_ptr():
+ _p(0)
+ {}
+ foreign_void_shared_ptr(const foreign_void_shared_ptr &other):
+ _p(other._p->clone())
+ {}
+ template<typename FSP>
+ explicit foreign_void_shared_ptr(const FSP &fsp):
+ _p(new foreign_shared_ptr_impl<FSP>(fsp))
+ {}
+ ~foreign_void_shared_ptr()
+ {
+ delete _p;
+ }
+ foreign_void_shared_ptr & operator=(const foreign_void_shared_ptr &other)
+ {
+ if(&other == this) return *this;
+ foreign_void_shared_ptr(other).swap(*this);
+ return *this;
+ }
+ void swap(foreign_void_shared_ptr &other)
+ {
+ boost::swap(_p, other._p);
+ }
+ private:
+ foreign_shared_ptr_impl_base *_p;
+ };
+
+ struct foreign_weak_ptr_impl_base
+ {
+ virtual ~foreign_weak_ptr_impl_base() {}
+ virtual foreign_void_shared_ptr lock() const = 0;
+ virtual bool expired() const = 0;
+ virtual foreign_weak_ptr_impl_base * clone() const = 0;
+ };
+
+ template<typename FWP>
+ class foreign_weak_ptr_impl: public foreign_weak_ptr_impl_base
+ {
+ public:
+ foreign_weak_ptr_impl(const FWP &p): _p(p)
+ {}
+ virtual foreign_void_shared_ptr lock() const
+ {
+ return foreign_void_shared_ptr(_p.lock());
+ }
+ virtual bool expired() const
+ {
+ return _p.expired();
+ }
+ virtual foreign_weak_ptr_impl * clone() const
+ {
+ return new foreign_weak_ptr_impl(*this);
+ }
+ private:
+ FWP _p;
+ };
+
+ class foreign_void_weak_ptr
+ {
+ public:
+ foreign_void_weak_ptr()
+ {}
+ foreign_void_weak_ptr(const foreign_void_weak_ptr &other):
+ _p(other._p->clone())
+ {}
+ template<typename FWP>
+ explicit foreign_void_weak_ptr(const FWP &fwp):
+ _p(new foreign_weak_ptr_impl<FWP>(fwp))
+ {}
+ foreign_void_weak_ptr & operator=(const foreign_void_weak_ptr &other)
+ {
+ if(&other == this) return *this;
+ foreign_void_weak_ptr(other).swap(*this);
+ return *this;
+ }
+ void swap(foreign_void_weak_ptr &other)
+ {
+ boost::swap(_p, other._p);
+ }
+ foreign_void_shared_ptr lock() const
+ {
+ return _p->lock();
+ }
+ bool expired() const
+ {
+ return _p->expired();
+ }
+ private:
+ boost::scoped_ptr<foreign_weak_ptr_impl_base> _p;
+ };
+ } // namespace detail
+
+ } // namespace signals2
+} // namespace boost
+
+#endif // BOOST_SIGNALS2_FOREIGN_PTR_HPP

Modified: trunk/boost/signals2/detail/replace_slot_function.hpp
==============================================================================
--- trunk/boost/signals2/detail/replace_slot_function.hpp (original)
+++ trunk/boost/signals2/detail/replace_slot_function.hpp 2009-10-07 16:56:56 EDT (Wed, 07 Oct 2009)
@@ -22,12 +22,7 @@
         ResultSlot replace_slot_function(const SlotIn &slot_in, const SlotFunction &fun)
       {
         ResultSlot slot(fun);
- slot_base::tracked_container_type tracked_objects = slot_in.tracked_objects();
- slot_base::tracked_container_type::const_iterator it;
- for(it = tracked_objects.begin(); it != tracked_objects.end(); ++it)
- {
- slot.track(*it);
- }
+ slot.track(slot_in);
         return slot;
       }
     } // namespace detail

Modified: trunk/boost/signals2/detail/slot_call_iterator.hpp
==============================================================================
--- trunk/boost/signals2/detail/slot_call_iterator.hpp (original)
+++ trunk/boost/signals2/detail/slot_call_iterator.hpp 2009-10-07 16:56:56 EDT (Wed, 07 Oct 2009)
@@ -36,7 +36,7 @@
           disconnected_slot_count(0)
         {}
         optional<ResultType> result;
- typedef auto_buffer<boost::shared_ptr<void>, store_n_objects<10> > tracked_ptrs_type;
+ typedef auto_buffer<void_shared_ptr_variant, store_n_objects<10> > tracked_ptrs_type;
         tracked_ptrs_type tracked_ptrs;
         Function f;
         unsigned connected_slot_count;

Modified: trunk/boost/signals2/detail/slot_template.hpp
==============================================================================
--- trunk/boost/signals2/detail/slot_template.hpp (original)
+++ trunk/boost/signals2/detail/slot_template.hpp 2009-10-07 16:56:56 EDT (Wed, 07 Oct 2009)
@@ -108,8 +108,7 @@
         return _slot_function(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
       }
       // tracking
- BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)& track(const weak_ptr<void> &tracked)
- {
+ BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)& track(const weak_ptr<void> &tracked) {
         _tracked_objects.push_back(tracked);
         return *this;
       }
@@ -123,10 +122,30 @@
         tracked_container_type::const_iterator it;
         for(it = slot.tracked_objects().begin(); it != slot.tracked_objects().end(); ++it)
         {
- track(*it);
+ _tracked_objects.push_back(*it);
         }
         return *this;
       }
+ template<typename ForeignWeakPtr>
+ BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)& track_foreign(const ForeignWeakPtr &tracked,
+ typename weak_ptr_traits<ForeignWeakPtr>::shared_type * /*SFINAE*/ = 0)
+ {
+ _tracked_objects.push_back(detail::foreign_void_weak_ptr(tracked));
+ return *this;
+ }
+ template<typename ForeignSharedPtr>
+ BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)& track_foreign(const ForeignSharedPtr &tracked,
+ typename shared_ptr_traits<ForeignSharedPtr>::weak_type * /*SFINAE*/ = 0)
+ {
+ _tracked_objects.push_back
+ (
+ detail::foreign_void_weak_ptr
+ (
+ typename shared_ptr_traits<ForeignSharedPtr>::weak_type(tracked)
+ )
+ );
+ return *this;
+ }
 
       const slot_function_type& slot_function() const {return _slot_function;}
       slot_function_type& slot_function() {return _slot_function;}

Modified: trunk/boost/signals2/slot_base.hpp
==============================================================================
--- trunk/boost/signals2/slot_base.hpp (original)
+++ trunk/boost/signals2/slot_base.hpp 2009-10-07 16:56:56 EDT (Wed, 07 Oct 2009)
@@ -12,10 +12,14 @@
 #ifndef BOOST_SIGNALS2_SLOT_BASE_HPP
 #define BOOST_SIGNALS2_SLOT_BASE_HPP
 
+#include <boost/any.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/weak_ptr.hpp>
+#include <boost/signals2/detail/foreign_ptr.hpp>
 #include <boost/signals2/signal_base.hpp>
 #include <boost/throw_exception.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant.hpp>
 #include <vector>
 
 namespace boost
@@ -25,6 +29,29 @@
     namespace detail
     {
       class tracked_objects_visitor;
+
+ typedef boost::variant<boost::weak_ptr<void>, detail::foreign_void_weak_ptr > void_weak_ptr_variant;
+ typedef boost::variant<boost::shared_ptr<void>, detail::foreign_void_shared_ptr > void_shared_ptr_variant;
+ class lock_weak_ptr_visitor
+ {
+ public:
+ typedef void_shared_ptr_variant result_type;
+ template<typename WeakPtr>
+ result_type operator()(const WeakPtr &wp) const
+ {
+ return wp.lock();
+ }
+ };
+ class expired_weak_ptr_visitor
+ {
+ public:
+ typedef bool result_type;
+ template<typename WeakPtr>
+ bool operator()(const WeakPtr &wp) const
+ {
+ return wp.expired();
+ }
+ };
     }
 
     class expired_slot: public bad_weak_ptr
@@ -39,8 +66,8 @@
     class slot_base
     {
     public:
- typedef std::vector<boost::weak_ptr<void> > tracked_container_type;
- typedef std::vector<boost::shared_ptr<void> > locked_container_type;
+ typedef std::vector<detail::void_weak_ptr_variant> tracked_container_type;
+ typedef std::vector<detail::void_shared_ptr_variant> locked_container_type;
 
       const tracked_container_type& tracked_objects() const {return _tracked_objects;}
       locked_container_type lock() const
@@ -49,11 +76,8 @@
         tracked_container_type::const_iterator it;
         for(it = tracked_objects().begin(); it != tracked_objects().end(); ++it)
         {
- try
- {
- locked_objects.push_back(shared_ptr<void>(*it));
- }
- catch(const bad_weak_ptr &)
+ locked_objects.push_back(apply_visitor(detail::lock_weak_ptr_visitor(), *it));
+ if(apply_visitor(detail::expired_weak_ptr_visitor(), *it))
           {
             boost::throw_exception(expired_slot());
           }
@@ -65,7 +89,7 @@
         tracked_container_type::const_iterator it;
         for(it = tracked_objects().begin(); it != tracked_objects().end(); ++it)
         {
- if(it->expired()) return true;
+ if(apply_visitor(detail::expired_weak_ptr_visitor(), *it)) return true;
         }
         return false;
       }

Modified: trunk/libs/signals2/test/track_test.cpp
==============================================================================
--- trunk/libs/signals2/test/track_test.cpp (original)
+++ trunk/libs/signals2/test/track_test.cpp 2009-10-07 16:56:56 EDT (Wed, 07 Oct 2009)
@@ -9,6 +9,7 @@
 
 // For more information, see http://www.boost.org
 
+#include <memory>
 #include <boost/optional.hpp>
 #include <boost/ref.hpp>
 #include <boost/shared_ptr.hpp>
@@ -108,5 +109,36 @@
     BOOST_CHECK(s1(2) == 2);
   }
   BOOST_CHECK(s1(2) == 0);
+
+// there isn't a boost config macro that detects the existance of std::shared_ptr or std::weak_ptr,
+// so we rely on BOOST_NO_VARIADIC_TEMPLATES as a hack
+#ifndef BOOST_NO_VARIADIC_TEMPLATES
+ // Test tracking through std::shared_ptr/weak_ptr
+ BOOST_CHECK(s1(5) == 0);
+ {
+ std::shared_ptr<int> shorty(new int());
+ s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track_foreign(shorty));
+ BOOST_CHECK(s1(5) == 5);
+ }
+ BOOST_CHECK(s1(5) == 0);
+ {
+ std::shared_ptr<int> shorty(new int());
+ s1.connect
+ (
+ sig_type::slot_type
+ (
+ swallow(),
+ shorty.get(),
+ _1
+ ).track_foreign
+ (
+ std::weak_ptr<int>(shorty)
+ )
+ );
+ BOOST_CHECK(s1(5) == 5);
+ }
+ BOOST_CHECK(s1(5) == 0);
+#endif
+
   return 0;
 }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk