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