Line data Source code
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/core/no_exceptions_support.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/type_traits/add_const.hpp> 25 : #include <boost/type_traits/add_reference.hpp> 26 : #include <boost/type_traits/aligned_storage.hpp> 27 : #include <boost/weak_ptr.hpp> 28 : 29 : namespace boost { 30 : namespace signals2 { 31 : namespace detail { 32 : template<typename ResultType, typename Function> 33 : class slot_call_iterator_cache 34 : { 35 : public: 36 164664 : slot_call_iterator_cache(const Function &f_arg): 37 82332 : f(f_arg), 38 82332 : connected_slot_count(0), 39 82332 : disconnected_slot_count(0), 40 82332 : m_active_slot(0) 41 164664 : {} 42 : 43 164664 : ~slot_call_iterator_cache() 44 82332 : { 45 82332 : if(m_active_slot) 46 : { 47 0 : garbage_collecting_lock<connection_body_base> lock(*m_active_slot); 48 0 : m_active_slot->dec_slot_refcount(lock); 49 0 : } 50 164664 : } 51 : 52 : template<typename M> 53 470 : void set_active_slot(garbage_collecting_lock<M> &lock, 54 : connection_body_base *active_slot) 55 : { 56 470 : if(m_active_slot) 57 235 : m_active_slot->dec_slot_refcount(lock); 58 470 : m_active_slot = active_slot; 59 470 : if(m_active_slot) 60 235 : m_active_slot->inc_slot_refcount(lock); 61 470 : } 62 : 63 : optional<ResultType> result; 64 : typedef auto_buffer<void_shared_ptr_variant, store_n_objects<10> > tracked_ptrs_type; 65 : tracked_ptrs_type tracked_ptrs; 66 : Function f; 67 : unsigned connected_slot_count; 68 : unsigned disconnected_slot_count; 69 : connection_body_base *m_active_slot; 70 : }; 71 : 72 : // Generates a slot call iterator. Essentially, this is an iterator that: 73 : // - skips over disconnected slots in the underlying list 74 : // - calls the connected slots when dereferenced 75 : // - caches the result of calling the slots 76 : template<typename Function, typename Iterator, typename ConnectionBody> 77 : class slot_call_iterator_t 78 : : public boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, 79 : typename Function::result_type, 80 : boost::single_pass_traversal_tag> 81 : { 82 : typedef boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, 83 : typename Function::result_type, 84 : boost::single_pass_traversal_tag> 85 : inherited; 86 : 87 : typedef typename Function::result_type result_type; 88 : 89 : typedef slot_call_iterator_cache<result_type, Function> cache_type; 90 : 91 : friend class boost::iterator_core_access; 92 : 93 : public: 94 329328 : slot_call_iterator_t(Iterator iter_in, Iterator end_in, 95 : cache_type &c): 96 164664 : iter(iter_in), end(end_in), 97 164664 : cache(&c), callable_iter(end_in) 98 164664 : { 99 164664 : lock_next_callable(); 100 329328 : } 101 : 102 : typename inherited::reference 103 235 : dereference() const 104 : { 105 235 : if (!cache->result) { 106 : BOOST_TRY 107 : { 108 235 : cache->result = cache->f(*iter); 109 235 : } 110 : BOOST_CATCH(expired_slot &) 111 : { 112 0 : (*iter)->disconnect(); 113 0 : BOOST_RETHROW 114 0 : } 115 : BOOST_CATCH_END 116 235 : } 117 235 : return cache->result.get(); 118 0 : } 119 : 120 235 : void increment() 121 : { 122 235 : ++iter; 123 235 : lock_next_callable(); 124 235 : cache->result.reset(); 125 235 : } 126 : 127 82567 : bool equal(const slot_call_iterator_t& other) const 128 : { 129 82567 : return iter == other.iter; 130 : } 131 : 132 : private: 133 : typedef garbage_collecting_lock<connection_body_base> lock_type; 134 : 135 470 : void set_callable_iter(lock_type &lock, Iterator newValue) const 136 : { 137 470 : callable_iter = newValue; 138 470 : if(callable_iter == end) 139 235 : cache->set_active_slot(lock, 0); 140 : else 141 235 : cache->set_active_slot(lock, (*callable_iter).get()); 142 470 : } 143 : 144 164899 : void lock_next_callable() const 145 : { 146 164899 : if(iter == callable_iter) 147 : { 148 164429 : return; 149 : } 150 : 151 470 : for(;iter != end; ++iter) 152 : { 153 235 : cache->tracked_ptrs.clear(); 154 235 : lock_type lock(**iter); 155 235 : (*iter)->nolock_grab_tracked_objects(lock, std::back_inserter(cache->tracked_ptrs)); 156 235 : if((*iter)->nolock_nograb_connected()) 157 : { 158 235 : ++cache->connected_slot_count; 159 235 : }else 160 : { 161 0 : ++cache->disconnected_slot_count; 162 : } 163 235 : if((*iter)->nolock_nograb_blocked() == false) 164 : { 165 235 : set_callable_iter(lock, iter); 166 235 : break; 167 : } 168 235 : } 169 : 170 470 : if(iter == end) 171 : { 172 235 : if(callable_iter != end) 173 : { 174 235 : lock_type lock(**callable_iter); 175 235 : set_callable_iter(lock, end); 176 235 : } 177 235 : } 178 164899 : } 179 : 180 : mutable Iterator iter; 181 : Iterator end; 182 : cache_type *cache; 183 : mutable Iterator callable_iter; 184 : }; 185 : } // end namespace detail 186 : } // end namespace BOOST_SIGNALS_NAMESPACE 187 : } // end namespace boost 188 : 189 : #endif // BOOST_SIGNALS2_SLOT_CALL_ITERATOR_HPP