]>
Commit | Line | Data |
---|---|---|
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/core/no_exceptions_support.hpp> | |
18 | #include <boost/iterator/iterator_facade.hpp> | |
19 | #include <boost/optional.hpp> | |
20 | #include <boost/scoped_ptr.hpp> | |
21 | #include <boost/signals2/connection.hpp> | |
22 | #include <boost/signals2/slot_base.hpp> | |
23 | #include <boost/signals2/detail/auto_buffer.hpp> | |
24 | #include <boost/signals2/detail/unique_lock.hpp> | |
25 | #include <boost/type_traits/add_const.hpp> | |
26 | #include <boost/type_traits/add_reference.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 | slot_call_iterator_cache(const Function &f_arg): | |
37 | f(f_arg), | |
38 | connected_slot_count(0), | |
39 | disconnected_slot_count(0), | |
40 | m_active_slot(0) | |
41 | {} | |
42 | ||
43 | ~slot_call_iterator_cache() | |
44 | { | |
45 | if(m_active_slot) | |
46 | { | |
47 | garbage_collecting_lock<connection_body_base> lock(*m_active_slot); | |
48 | m_active_slot->dec_slot_refcount(lock); | |
49 | } | |
50 | } | |
51 | ||
52 | template<typename M> | |
53 | void set_active_slot(garbage_collecting_lock<M> &lock, | |
54 | connection_body_base *active_slot) | |
55 | { | |
56 | if(m_active_slot) | |
57 | m_active_slot->dec_slot_refcount(lock); | |
58 | m_active_slot = active_slot; | |
59 | if(m_active_slot) | |
60 | m_active_slot->inc_slot_refcount(lock); | |
61 | } | |
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 | typename boost::add_const<typename boost::add_reference<typename Function::result_type>::type>::type > | |
82 | { | |
83 | typedef boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, | |
84 | typename Function::result_type, | |
85 | boost::single_pass_traversal_tag, | |
86 | typename boost::add_const<typename boost::add_reference<typename Function::result_type>::type>::type > | |
87 | inherited; | |
88 | ||
89 | typedef typename Function::result_type result_type; | |
90 | ||
91 | typedef slot_call_iterator_cache<result_type, Function> cache_type; | |
92 | ||
93 | friend class boost::iterator_core_access; | |
94 | ||
95 | public: | |
96 | slot_call_iterator_t(Iterator iter_in, Iterator end_in, | |
97 | cache_type &c): | |
98 | iter(iter_in), end(end_in), | |
99 | cache(&c), callable_iter(end_in) | |
100 | { | |
101 | lock_next_callable(); | |
102 | } | |
103 | ||
104 | typename inherited::reference | |
105 | dereference() const | |
106 | { | |
107 | if (!cache->result) { | |
108 | BOOST_TRY | |
109 | { | |
110 | cache->result.reset(cache->f(*iter)); | |
111 | } | |
112 | BOOST_CATCH(expired_slot &) | |
113 | { | |
114 | (*iter)->disconnect(); | |
115 | BOOST_RETHROW | |
116 | } | |
117 | BOOST_CATCH_END | |
118 | } | |
119 | return cache->result.get(); | |
120 | } | |
121 | ||
122 | void increment() | |
123 | { | |
124 | ++iter; | |
125 | lock_next_callable(); | |
126 | cache->result.reset(); | |
127 | } | |
128 | ||
129 | bool equal(const slot_call_iterator_t& other) const | |
130 | { | |
131 | return iter == other.iter; | |
132 | } | |
133 | ||
134 | private: | |
135 | typedef garbage_collecting_lock<connection_body_base> lock_type; | |
136 | ||
137 | void set_callable_iter(lock_type &lock, Iterator newValue) const | |
138 | { | |
139 | callable_iter = newValue; | |
140 | if(callable_iter == end) | |
141 | cache->set_active_slot(lock, 0); | |
142 | else | |
143 | cache->set_active_slot(lock, (*callable_iter).get()); | |
144 | } | |
145 | ||
146 | void lock_next_callable() const | |
147 | { | |
148 | if(iter == callable_iter) | |
149 | { | |
150 | return; | |
151 | } | |
152 | if(iter == end) | |
153 | { | |
154 | if(callable_iter != end) | |
155 | { | |
156 | lock_type lock(**callable_iter); | |
157 | set_callable_iter(lock, end); | |
158 | return; | |
159 | } | |
160 | } | |
161 | // we're only locking the first connection body, | |
162 | // but it doesn't matter they all use the same mutex | |
163 | lock_type lock(**iter); | |
164 | for(;iter != end; ++iter) | |
165 | { | |
166 | cache->tracked_ptrs.clear(); | |
167 | (*iter)->nolock_grab_tracked_objects(lock, std::back_inserter(cache->tracked_ptrs)); | |
168 | if((*iter)->nolock_nograb_connected()) | |
169 | { | |
170 | ++cache->connected_slot_count; | |
171 | }else | |
172 | { | |
173 | ++cache->disconnected_slot_count; | |
174 | } | |
175 | if((*iter)->nolock_nograb_blocked() == false) | |
176 | { | |
177 | set_callable_iter(lock, iter); | |
178 | break; | |
179 | } | |
180 | } | |
181 | if(iter == end) | |
182 | { | |
183 | set_callable_iter(lock, end); | |
184 | } | |
185 | } | |
186 | ||
187 | mutable Iterator iter; | |
188 | Iterator end; | |
189 | cache_type *cache; | |
190 | mutable Iterator callable_iter; | |
191 | }; | |
192 | } // end namespace detail | |
193 | } // end namespace BOOST_SIGNALS_NAMESPACE | |
194 | } // end namespace boost | |
195 | ||
196 | #endif // BOOST_SIGNALS2_SLOT_CALL_ITERATOR_HPP |