$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r50252 - in sandbox/thread_safe_signals/trunk/boost/signals2: . detail
From: fmhess_at_[hidden]
Date: 2008-12-12 16:34:59
Author: fmhess
Date: 2008-12-12 16:34:58 EST (Fri, 12 Dec 2008)
New Revision: 50252
URL: http://svn.boost.org/trac/boost/changeset/50252
Log:
Opimized speed with respect to automatic tracking overhead
during signal invocation.
Added:
   sandbox/thread_safe_signals/trunk/boost/signals2/detail/null_output_iterator.hpp   (contents, props changed)
   sandbox/thread_safe_signals/trunk/boost/signals2/detail/stack_allocator.hpp   (contents, props changed)
   sandbox/thread_safe_signals/trunk/boost/signals2/detail/stack_vector.hpp   (contents, props changed)
Text files modified: 
   sandbox/thread_safe_signals/trunk/boost/signals2/connection.hpp                |    31 +++++++++++++++++--------------         
   sandbox/thread_safe_signals/trunk/boost/signals2/detail/signal_template.hpp    |     4 ++--                                    
   sandbox/thread_safe_signals/trunk/boost/signals2/detail/slot_call_iterator.hpp |    26 ++++++++++++++++++--------              
   3 files changed, 37 insertions(+), 24 deletions(-)
Modified: sandbox/thread_safe_signals/trunk/boost/signals2/connection.hpp
==============================================================================
--- sandbox/thread_safe_signals/trunk/boost/signals2/connection.hpp	(original)
+++ sandbox/thread_safe_signals/trunk/boost/signals2/connection.hpp	2008-12-12 16:34:58 EST (Fri, 12 Dec 2008)
@@ -18,12 +18,12 @@
 #include <boost/mpl/bool.hpp>
 #include <boost/noncopyable.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/signals2/slot.hpp>
+#include <boost/signals2/detail/null_output_iterator.hpp>
 #include <boost/signals2/detail/unique_lock.hpp>
+#include <boost/signals2/slot.hpp>
 #include <boost/type_traits.hpp>
 #include <boost/visit_each.hpp>
 #include <boost/weak_ptr.hpp>
-#include <vector>
 
 namespace boost
 {
@@ -93,7 +93,7 @@
         virtual bool connected() const
         {
           unique_lock<mutex_type> lock(_mutex);
-          nolock_grab_tracked_objects();
+          nolock_grab_tracked_objects(detail::null_output_iterator());
           return nolock_nograb_connected();
         }
         const GroupKey& group_key() const {return _group_key;}
@@ -107,19 +107,22 @@
           }
           return expired;
         }
-        typename slot_base::locked_container_type nolock_grab_tracked_objects() const
+        template<typename OutputIterator>
+          void nolock_grab_tracked_objects(OutputIterator inserter) const
         {
-          slot_base::locked_container_type locked_objects;
-          try
-          {
-            locked_objects = slot.lock();
-          }
-          catch(const expired_slot &)
-          {
-            _connected = false;
-            return locked_objects;
+            slot_base::tracked_container_type::const_iterator it;
+            for(it = slot.tracked_objects().begin();
+              it != slot.tracked_objects().end();
+              ++it)
+            {
+              boost::shared_ptr<void> locked_object = it->lock();
+              if(!locked_object)
+              {
+                _connected = false;
+                return;
+              }
+              *inserter++ = it->lock();
           }
-          return locked_objects;
         }
         // expose Lockable concept of mutex
         virtual void lock()
Added: sandbox/thread_safe_signals/trunk/boost/signals2/detail/null_output_iterator.hpp
==============================================================================
--- (empty file)
+++ sandbox/thread_safe_signals/trunk/boost/signals2/detail/null_output_iterator.hpp	2008-12-12 16:34:58 EST (Fri, 12 Dec 2008)
@@ -0,0 +1,34 @@
+/*
+  An output iterator which simply discards output.
+*/
+// Copyright Frank Mori Hess 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_NULL_OUTPUT_ITERATOR_HPP
+#define BOOST_SIGNALS2_NULL_OUTPUT_ITERATOR_HPP
+
+#include <boost/function_output_iterator.hpp>
+
+namespace boost
+{
+  namespace signals2
+  {
+    namespace detail
+    {
+      class does_nothing
+      {
+      public:
+        template<typename T>
+          void operator()(const T&) const
+          {}
+      };
+      typedef boost::function_output_iterator<does_nothing> null_output_iterator;
+    } // namespace detail
+  } // namespace signals2
+} // namespace boost
+
+#endif  // BOOST_SIGNALS2_NULL_OUTPUT_ITERATOR_HPP
Modified: sandbox/thread_safe_signals/trunk/boost/signals2/detail/signal_template.hpp
==============================================================================
--- sandbox/thread_safe_signals/trunk/boost/signals2/detail/signal_template.hpp	(original)
+++ sandbox/thread_safe_signals/trunk/boost/signals2/detail/signal_template.hpp	2008-12-12 16:34:58 EST (Fri, 12 Dec 2008)
@@ -262,7 +262,7 @@
           }
           slot_invoker invoker BOOST_PP_IF(BOOST_SIGNALS_NUM_ARGS, \
             (BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)), );
-          optional<slot_result_type> cache;
+          slot_call_iterator_cache<slot_result_type> cache;
           return local_state->combiner(
             slot_call_iterator(local_state->connection_bodies.begin(), local_state->connection_bodies.end(), invoker, cache),
             slot_call_iterator(local_state->connection_bodies.end(), local_state->connection_bodies.end(), invoker, cache));
@@ -283,7 +283,7 @@
           }
           slot_invoker invoker BOOST_PP_IF(BOOST_SIGNALS_NUM_ARGS, \
             (BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)), );
-          optional<slot_result_type> cache;
+          slot_call_iterator_cache<slot_result_type> cache;
           return const_cast<const combiner_type&>(local_state->combiner)(
             slot_call_iterator(local_state->connection_bodies.begin(), local_state->connection_bodies.end(), invoker, cache),
             slot_call_iterator(local_state->connection_bodies.end(), local_state->connection_bodies.end(), invoker, cache));
Modified: sandbox/thread_safe_signals/trunk/boost/signals2/detail/slot_call_iterator.hpp
==============================================================================
--- sandbox/thread_safe_signals/trunk/boost/signals2/detail/slot_call_iterator.hpp	(original)
+++ sandbox/thread_safe_signals/trunk/boost/signals2/detail/slot_call_iterator.hpp	2008-12-12 16:34:58 EST (Fri, 12 Dec 2008)
@@ -19,6 +19,7 @@
 #include <boost/scoped_ptr.hpp>
 #include <boost/signals2/connection.hpp>
 #include <boost/signals2/slot_base.hpp>
+#include <boost/signals2/detail/stack_vector.hpp>
 #include <boost/signals2/detail/unique_lock.hpp>
 #include <boost/type_traits.hpp>
 #include <boost/weak_ptr.hpp>
@@ -26,6 +27,15 @@
 namespace boost {
   namespace signals2 {
     namespace detail {
+      template<typename ResultType>
+        class slot_call_iterator_cache
+      {
+      public:
+        optional<ResultType> result;
+        typedef stack_vector<boost::shared_ptr<void>, 10> tracked_ptrs_type;
+        tracked_ptrs_type tracked_ptrs;
+      };
+
       // Generates a slot call iterator. Essentially, this is an iterator that:
       //   - skips over disconnected slots in the underlying list
       //   - calls the connected slots when dereferenced
@@ -49,7 +59,7 @@
 
       public:
         slot_call_iterator_t(Iterator iter_in, Iterator end_in, Function f,
-          boost::optional<result_type> &c):
+          slot_call_iterator_cache<result_type> &c):
           iter(iter_in), end(end_in), f(f),
           cache(&c), callable_iter(end_in)
         {
@@ -59,10 +69,10 @@
         typename inherited::reference
         dereference() const
         {
-          if (!(*cache)) {
+          if (!cache->result) {
             try
             {
-              cache->reset(f(*iter));
+              cache->result.reset(f(*iter));
             }
             catch(expired_slot &)
             {
@@ -70,14 +80,14 @@
               throw;
             }
           }
-          return cache->get();
+          return cache->result.get();
         }
 
         void increment()
         {
           ++iter;
           lock_next_callable();
-          cache->reset();
+          cache->result.reset();
         }
 
         bool equal(const slot_call_iterator_t& other) const
@@ -97,7 +107,8 @@
           for(;iter != end; ++iter)
           {
             lock_type lock(**iter);
-            tracked_ptrs = (*iter)->nolock_grab_tracked_objects();
+            cache->tracked_ptrs.clear();
+            (*iter)->nolock_grab_tracked_objects(std::back_inserter(cache->tracked_ptrs));
             if((*iter)->nolock_nograb_blocked() == false)
             {
               callable_iter = iter;
@@ -113,9 +124,8 @@
         mutable Iterator iter;
         Iterator end;
         Function f;
-        optional<result_type>* cache;
+        slot_call_iterator_cache<result_type> *cache;
         mutable Iterator callable_iter;
-        mutable typename slot_base::locked_container_type tracked_ptrs;
       };
     } // end namespace detail
   } // end namespace BOOST_SIGNALS_NAMESPACE
Added: sandbox/thread_safe_signals/trunk/boost/signals2/detail/stack_allocator.hpp
==============================================================================
--- (empty file)
+++ sandbox/thread_safe_signals/trunk/boost/signals2/detail/stack_allocator.hpp	2008-12-12 16:34:58 EST (Fri, 12 Dec 2008)
@@ -0,0 +1,90 @@
+/*
+	An allocator which first allocates from the stack, before falling
+	back on usual std::allocator behavior.  Used by signals2 to
+	optimize the vector of tracked shared_ptr created during signal
+	invocation.
+
+	Example usage:
+
+	static const std::size_t n = 10;
+	stack_storage<T, n> storage;
+	stack_allocator<T, n> a(&storage);
+	std::vector<T, stack_allocator<T, n> > v(a);
+
+*/
+// Copyright Frank Mori Hess 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_STACK_ALLOCATOR_HPP
+#define BOOST_SIGNALS2_STACK_ALLOCATOR_HPP
+
+#include <memory>
+#include <boost/noncopyable.hpp>
+#include <boost/type_traits/aligned_storage.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+
+namespace boost
+{
+  namespace signals2
+  {
+    namespace detail
+    {
+      template<typename T, std::size_t n_stack_elements>
+        class stack_storage: public boost::noncopyable
+      {
+      public:
+        typedef typename boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value>::type storage_type;
+        stack_storage(): is_reserved(false)
+        {
+        }
+        storage_type array[n_stack_elements];
+        bool is_reserved;
+      };
+      template<typename T, std::size_t n_stack_elements>
+        class stack_allocator: public std::allocator<T>
+      {
+        typedef std::allocator<T> base_class;
+      public:
+        template<typename U>
+          struct rebind
+        {
+          typedef stack_allocator<U, n_stack_elements> other;
+        };
+        stack_allocator(stack_storage<T, n_stack_elements> *storage = 0):
+          _storage(storage)
+        {
+        }
+        typename base_class::pointer allocate(typename base_class::size_type n_elements,
+          std::allocator<void>::const_pointer hint = 0)
+        {
+          if(_storage && _storage->is_reserved == false &&
+            n_elements <= n_stack_elements)
+          {
+            _storage->is_reserved = true;
+            return reinterpret_cast<typename base_class::pointer>(&_storage->array[0]);
+          }
+          return base_class::allocate(n_elements, hint);
+        }
+        void deallocate(typename base_class::pointer p, typename base_class::size_type n)
+        {
+          if(_storage &&
+            p == reinterpret_cast<typename base_class::pointer>(&_storage->array[0]))
+          {
+            _storage->is_reserved = false;
+          }else
+          {
+            base_class::deallocate(p, n);
+          }
+        }
+      private:
+        stack_storage<T, n_stack_elements> *_storage;
+      };
+    } // namespace detail
+  } // namespace signals2
+} // namespace boost
+
+#endif  // BOOST_SIGNALS2_STACK_ALLOCATOR_HPP
Added: sandbox/thread_safe_signals/trunk/boost/signals2/detail/stack_vector.hpp
==============================================================================
--- (empty file)
+++ sandbox/thread_safe_signals/trunk/boost/signals2/detail/stack_vector.hpp	2008-12-12 16:34:58 EST (Fri, 12 Dec 2008)
@@ -0,0 +1,48 @@
+/*
+	A non-copyable vector which first allocates from the stack, before falling
+	back on usual std::allocator behavior.
+
+*/
+// Copyright Frank Mori Hess 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_STACK_VECTOR_HPP
+#define BOOST_SIGNALS2_STACK_VECTOR_HPP
+
+#include <boost/noncopyable.hpp>
+#include <boost/signals2/detail/stack_allocator.hpp>
+#include <vector>
+
+namespace boost
+{
+  namespace signals2
+  {
+    namespace detail
+    {
+      template<typename T, std::size_t NumStackElements>
+        class stack_vector:
+        public std::vector<T, stack_allocator<T, NumStackElements> >,
+        public boost::noncopyable
+      {
+        typedef std::vector<T, stack_allocator<T, NumStackElements> > base_vector_type;
+      public:
+        static const std::size_t num_stack_elements = NumStackElements;
+        stack_vector(): base_vector_type(stack_allocator<T, num_stack_elements>(&_storage))
+        {
+          base_vector_type::reserve(num_stack_elements);
+        }
+      private:
+        stack_storage<T, num_stack_elements> _storage;
+      };
+      template<typename T, std::size_t NumStackElements>
+        const std::size_t stack_vector<T, NumStackElements>::num_stack_elements;
+
+    } // namespace detail
+  } // namespace signals2
+} // namespace boost
+
+#endif  // BOOST_SIGNALS2_STACK_VECTOR_HPP