slot_call_iterator.hpp 5.8 KB

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