1 // Boost.Signals2 library 2 3 // Copyright Douglas Gregor 2001-2004. 4 // Copyright Frank Mori Hess 2007-2008. 5 // Use, modification and 6 // distribution is subject to the Boost Software License, Version 7 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at 8 // http://www.boost.org/LICENSE_1_0.txt) 9 10 // For more information, see http://www.boost.org 11 12 #ifndef BOOST_SIGNALS2_SLOT_CALL_ITERATOR_HPP 13 #define BOOST_SIGNALS2_SLOT_CALL_ITERATOR_HPP 14 15 #include <boost/assert.hpp> 16 #include <boost/aligned_storage.hpp> 17 #include <boost/iterator/iterator_facade.hpp> 18 #include <boost/optional.hpp> 19 #include <boost/scoped_ptr.hpp> 20 #include <boost/signals2/connection.hpp> 21 #include <boost/signals2/slot_base.hpp> 22 #include <boost/signals2/detail/auto_buffer.hpp> 23 #include <boost/signals2/detail/unique_lock.hpp> 24 #include <boost/weak_ptr.hpp> 25 26 namespace boost { 27 namespace signals2 { 28 namespace detail { 29 template<typename ResultType, typename Function> 30 class slot_call_iterator_cache 31 { 32 public: slot_call_iterator_cache(const Function & f_arg)33 slot_call_iterator_cache(const Function &f_arg): 34 f(f_arg), 35 connected_slot_count(0), 36 disconnected_slot_count(0) 37 {} 38 optional<ResultType> result; 39 typedef auto_buffer<void_shared_ptr_variant, store_n_objects<10> > tracked_ptrs_type; 40 tracked_ptrs_type tracked_ptrs; 41 Function f; 42 unsigned connected_slot_count; 43 unsigned disconnected_slot_count; 44 }; 45 46 // Generates a slot call iterator. Essentially, this is an iterator that: 47 // - skips over disconnected slots in the underlying list 48 // - calls the connected slots when dereferenced 49 // - caches the result of calling the slots 50 template<typename Function, typename Iterator, typename ConnectionBody> 51 class slot_call_iterator_t 52 : public boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, 53 typename Function::result_type, 54 boost::single_pass_traversal_tag, 55 typename Function::result_type const&> 56 { 57 typedef boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, 58 typename Function::result_type, 59 boost::single_pass_traversal_tag, 60 typename Function::result_type const&> 61 inherited; 62 63 typedef typename Function::result_type result_type; 64 65 friend class boost::iterator_core_access; 66 67 public: slot_call_iterator_t(Iterator iter_in,Iterator end_in,slot_call_iterator_cache<result_type,Function> & c)68 slot_call_iterator_t(Iterator iter_in, Iterator end_in, 69 slot_call_iterator_cache<result_type, Function> &c): 70 iter(iter_in), end(end_in), 71 cache(&c), callable_iter(end_in) 72 { 73 lock_next_callable(); 74 } 75 76 typename inherited::reference dereference() const77 dereference() const 78 { 79 if (!cache->result) { 80 try 81 { 82 cache->result.reset(cache->f(*iter)); 83 } 84 catch(expired_slot &) 85 { 86 (*iter)->disconnect(); 87 throw; 88 } 89 } 90 return cache->result.get(); 91 } 92 increment()93 void increment() 94 { 95 ++iter; 96 lock_next_callable(); 97 cache->result.reset(); 98 } 99 equal(const slot_call_iterator_t & other) const100 bool equal(const slot_call_iterator_t& other) const 101 { 102 return iter == other.iter; 103 } 104 105 private: 106 typedef unique_lock<connection_body_base> lock_type; 107 lock_next_callable() const108 void lock_next_callable() const 109 { 110 if(iter == callable_iter) 111 { 112 return; 113 } 114 for(;iter != end; ++iter) 115 { 116 lock_type lock(**iter); 117 cache->tracked_ptrs.clear(); 118 (*iter)->nolock_grab_tracked_objects(std::back_inserter(cache->tracked_ptrs)); 119 if((*iter)->nolock_nograb_connected()) 120 { 121 ++cache->connected_slot_count; 122 }else 123 { 124 ++cache->disconnected_slot_count; 125 } 126 if((*iter)->nolock_nograb_blocked() == false) 127 { 128 callable_iter = iter; 129 break; 130 } 131 } 132 if(iter == end) 133 { 134 callable_iter = end; 135 } 136 } 137 138 mutable Iterator iter; 139 Iterator end; 140 slot_call_iterator_cache<result_type, Function> *cache; 141 mutable Iterator callable_iter; 142 }; 143 } // end namespace detail 144 } // end namespace BOOST_SIGNALS_NAMESPACE 145 } // end namespace boost 146 147 #endif // BOOST_SIGNALS2_SLOT_CALL_ITERATOR_HPP 148