slot_call_iterator.hpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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/core/no_exceptions_support.hpp>
  13. #include <boost/iterator/iterator_facade.hpp>
  14. #include <boost/optional.hpp>
  15. #include <boost/scoped_ptr.hpp>
  16. #include <boost/signals2/connection.hpp>
  17. #include <boost/signals2/slot_base.hpp>
  18. #include <boost/signals2/detail/auto_buffer.hpp>
  19. #include <boost/signals2/detail/unique_lock.hpp>
  20. #include <boost/type_traits/add_const.hpp>
  21. #include <boost/type_traits/add_reference.hpp>
  22. #include <boost/type_traits/aligned_storage.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. {
  73. typedef boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>,
  74. typename Function::result_type,
  75. boost::single_pass_traversal_tag>
  76. inherited;
  77. typedef typename Function::result_type result_type;
  78. typedef slot_call_iterator_cache<result_type, Function> cache_type;
  79. friend class boost::iterator_core_access;
  80. public:
  81. slot_call_iterator_t(Iterator iter_in, Iterator end_in,
  82. cache_type &c):
  83. iter(iter_in), end(end_in),
  84. cache(&c), callable_iter(end_in)
  85. {
  86. lock_next_callable();
  87. }
  88. typename inherited::reference
  89. dereference() const
  90. {
  91. if (!cache->result) {
  92. BOOST_TRY
  93. {
  94. cache->result = cache->f(*iter);
  95. }
  96. BOOST_CATCH(expired_slot &)
  97. {
  98. (*iter)->disconnect();
  99. BOOST_RETHROW
  100. }
  101. BOOST_CATCH_END
  102. }
  103. return cache->result.get();
  104. }
  105. void increment()
  106. {
  107. ++iter;
  108. lock_next_callable();
  109. cache->result.reset();
  110. }
  111. bool equal(const slot_call_iterator_t& other) const
  112. {
  113. return iter == other.iter;
  114. }
  115. private:
  116. typedef garbage_collecting_lock<connection_body_base> lock_type;
  117. void set_callable_iter(lock_type &lock, Iterator newValue) const
  118. {
  119. callable_iter = newValue;
  120. if(callable_iter == end)
  121. cache->set_active_slot(lock, 0);
  122. else
  123. cache->set_active_slot(lock, (*callable_iter).get());
  124. }
  125. void lock_next_callable() const
  126. {
  127. if(iter == callable_iter)
  128. {
  129. return;
  130. }
  131. for(;iter != end; ++iter)
  132. {
  133. cache->tracked_ptrs.clear();
  134. lock_type lock(**iter);
  135. (*iter)->nolock_grab_tracked_objects(lock, std::back_inserter(cache->tracked_ptrs));
  136. if((*iter)->nolock_nograb_connected())
  137. {
  138. ++cache->connected_slot_count;
  139. }else
  140. {
  141. ++cache->disconnected_slot_count;
  142. }
  143. if((*iter)->nolock_nograb_blocked() == false)
  144. {
  145. set_callable_iter(lock, iter);
  146. break;
  147. }
  148. }
  149. if(iter == end)
  150. {
  151. if(callable_iter != end)
  152. {
  153. lock_type lock(**callable_iter);
  154. set_callable_iter(lock, end);
  155. }
  156. }
  157. }
  158. mutable Iterator iter;
  159. Iterator end;
  160. cache_type *cache;
  161. mutable Iterator callable_iter;
  162. };
  163. } // end namespace detail
  164. } // end namespace BOOST_SIGNALS_NAMESPACE
  165. } // end namespace boost
  166. #endif // BOOST_SIGNALS2_SLOT_CALL_ITERATOR_HPP