Boost logo

Boost-Commit :

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


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