OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef BASE_CLOSURE_H_ | |
6 #define BASE_CLOSURE_H_ | |
7 #pragma once | |
8 | |
9 #include <tr1/functional> | |
10 | |
11 #include "base/ref_counted.h" | |
12 #include "base/scoped_ptr.h" | |
13 #include "base/tracked.h" | |
14 | |
15 namespace base { | |
16 | |
17 extern void DoNothing(); // Defined in base/task.h. | |
18 | |
19 // We are trying to mimic value-object semantics of tr1::function in the | |
20 // Closure API. Thus, we need to detach the tracked object, and some other | |
21 // state as a shared state. | |
22 // | |
23 // As is, there are some threadsafety issues, but the general idea should be | |
24 // correct. | |
25 class ClosureState : public RefCountedThreadSafe<ClosureState> { | |
26 public: | |
27 // TODO(ajwong): Put these behind an accessor. | |
28 ::std::tr1::function<void()> release_thunk_; | |
29 | |
30 explicit ClosureState(tracked_objects::Tracked* tracked) | |
31 : release_thunk_(&DoNothing), | |
32 tracked_(tracked) { | |
33 } | |
34 | |
35 ~ClosureState() { | |
36 release_thunk_(); | |
37 } | |
38 | |
39 tracked_objects::Tracked* tracked() const { | |
40 return tracked_.get(); | |
41 } | |
42 | |
43 private: | |
44 scoped_ptr<tracked_objects::Tracked> tracked_; | |
45 }; | |
46 | |
47 | |
48 // These are needed to implement a wrapper that disables refcounting on | |
49 // objects used with a Closure. | |
50 // | |
51 // TODO(ajwong): If we implement this similar to std::tr1::reference_wrapper we | |
52 // can probably simplify the ObjectTraits below and remove one specialization. | |
53 template <typename O> | |
54 class UnretainedWrapper { | |
55 public: | |
56 explicit UnretainedWrapper(O* o) : obj_(o) {} | |
57 O* get() const { return obj_; } | |
58 | |
59 private: | |
60 O* obj_; | |
61 }; | |
62 | |
63 template <typename O> | |
64 UnretainedWrapper<O> Unretained(O* o) { | |
65 return UnretainedWrapper<O>(o); | |
66 } | |
67 | |
68 // Note, Closure does not support binding a member function to a reference | |
69 // object. That is, this will not compile: | |
70 // | |
71 // Foo f; | |
72 // Closure c = Closure(&Foo::func, f); | |
73 // | |
74 // You have to pass in a pointer to it. | |
75 // | |
76 // Foo f; | |
77 // Closure c = Closure(&Foo::func, &f); | |
78 // | |
79 // We can make the syntax work out, but it's extra complex and given that we | |
80 // expect Closure's to refcount the member functions they abstract unless | |
81 // explicitly told not to, allowing pass by reference doesn't make much sense. | |
82 class Closure { | |
83 public: | |
84 | |
85 // --- Traits object defintions -- | |
86 // This handle changing the syntax, and refcounting for the various types of | |
87 // parameters that can be passed in. | |
88 | |
89 template <typename O, bool is_member_function_pointer> | |
90 struct ObjectTraits; | |
91 | |
92 // Handle regular pointers. | |
93 template <typename O> | |
94 struct ObjectTraits<O*, true> { | |
95 static O* Unwrap(O* o) { | |
96 return o; | |
97 } | |
98 | |
99 static ::std::tr1::function<void()> RefThunk(O* o) { | |
willchan no longer on Chromium
2011/01/05 00:30:17
Do we really need to use Thunks here? Is the flex
awong
2011/01/05 03:17:42
Looking at this more, I don't think it's quite tha
willchan no longer on Chromium
2011/01/05 19:44:09
I never said template parameter. I said parameter
| |
100 return ::std::tr1::bind(&O::AddRef, o); | |
101 } | |
102 static ::std::tr1::function<void()> ReleaseThunk(O* o) { | |
103 return ::std::tr1::bind(&O::Release, o); | |
104 } | |
105 }; | |
106 | |
107 // If it's not a member function, there is no refcounting, and pass through | |
108 // the object. | |
109 template <typename O> | |
110 struct ObjectTraits<O, false> { | |
111 static O Unwrap(O o) { | |
112 return o; | |
113 } | |
114 | |
115 static ::std::tr1::function<void()> RefThunk(O o) { | |
116 return ::std::tr1::bind(&DoNothing); | |
117 } | |
118 static ::std::tr1::function<void()> ReleaseThunk(O o) { | |
119 return ::std::tr1::bind(&DoNothing); | |
120 } | |
121 }; | |
122 | |
123 // Object wrapped in Unretained() should not refcount anything, and should | |
124 // unwrap to a pointer to their type. | |
125 template <typename O> | |
126 struct ObjectTraits<UnretainedWrapper<O>, true> { | |
127 static O* Unwrap(UnretainedWrapper<O> o) { | |
128 return o.get(); | |
129 } | |
130 | |
131 static ::std::tr1::function<void()> RefThunk(UnretainedWrapper<O> o) { | |
132 return ::std::tr1::bind(&DoNothing); | |
133 } | |
134 | |
135 static ::std::tr1::function<void()> ReleaseThunk(UnretainedWrapper<O> o) { | |
136 return ::std::tr1::bind(&DoNothing); | |
137 } | |
138 }; | |
139 | |
140 | |
141 // ---- Constructors ---- | |
142 template <typename Sig> | |
143 Closure(Sig f) | |
144 : state_(new ClosureState(new tracked_objects::Tracked())) { | |
145 func_ = ::std::tr1::bind(f); | |
146 state_->release_thunk_ = ::std::tr1::bind(&DoNothing); | |
147 } | |
148 | |
149 template <typename Sig, typename A1> | |
150 Closure(Sig f, A1 a1) | |
151 : state_(new ClosureState(new tracked_objects::Tracked())) { | |
152 using std::tr1::is_member_function_pointer; | |
153 func_ = ::std::tr1::bind( | |
154 f, | |
155 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1)); | |
156 | |
157 // Handle the refcounting. | |
158 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)(); | |
159 state_->release_thunk_ = | |
160 ObjectTraits<A1, is_member_function_pointer<Sig>::value >:: | |
161 ReleaseThunk(a1); | |
162 } | |
163 | |
164 template <typename Sig, typename A1, typename A2> | |
165 Closure(Sig f, A1 a1, A2 a2) | |
166 : state_(new ClosureState(new tracked_objects::Tracked())) { | |
167 using std::tr1::is_member_function_pointer; | |
168 func_ = ::std::tr1::bind( | |
169 f, | |
170 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1), | |
171 a2); | |
172 | |
173 // Handle the refcounting. | |
174 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)(); | |
175 state_->release_thunk_ = | |
176 ObjectTraits<A1, is_member_function_pointer<Sig>::value >:: | |
177 ReleaseThunk(a1); | |
178 } | |
179 | |
180 template <typename Sig, typename A1, typename A2, typename A3> | |
181 Closure(Sig f, A1 a1, A2 a2, A3 a3) | |
182 : state_(new ClosureState(new tracked_objects::Tracked())) { | |
183 using std::tr1::is_member_function_pointer; | |
184 func_ = ::std::tr1::bind( | |
185 f, | |
186 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1), | |
187 a2, | |
188 a3); | |
189 | |
190 // Handle the refcounting. | |
191 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)(); | |
192 state_->release_thunk_ = | |
193 ObjectTraits<A1, is_member_function_pointer<Sig>::value >:: | |
194 ReleaseThunk(a1); | |
195 } | |
196 | |
197 template <typename Sig, typename A1, typename A2, typename A3, | |
198 typename A4> | |
199 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4) | |
200 : state_(new ClosureState(new tracked_objects::Tracked())) { | |
201 using std::tr1::is_member_function_pointer; | |
202 func_ = ::std::tr1::bind( | |
203 f, | |
204 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1), | |
205 a2, | |
206 a3, | |
207 a4); | |
208 | |
209 // Handle the refcounting. | |
210 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)(); | |
211 state_->release_thunk_ = | |
212 ObjectTraits<A1, is_member_function_pointer<Sig>::value >:: | |
213 ReleaseThunk(a1); | |
214 } | |
215 | |
216 template <typename Sig, typename A1, typename A2, typename A3, | |
217 typename A4, typename A5> | |
218 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) | |
219 : state_(new ClosureState(new tracked_objects::Tracked())) { | |
220 using std::tr1::is_member_function_pointer; | |
221 func_ = ::std::tr1::bind( | |
222 f, | |
223 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1), | |
224 a2, | |
225 a3, | |
226 a4, | |
227 a5); | |
228 | |
229 // Handle the refcounting. | |
230 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)(); | |
231 state_->release_thunk_ = | |
232 ObjectTraits<A1, is_member_function_pointer<Sig>::value >:: | |
233 ReleaseThunk(a1); | |
234 } | |
235 | |
236 template <typename Sig, typename A1, typename A2, typename A3, | |
237 typename A4, typename A5, typename A6> | |
238 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) | |
239 : state_(new ClosureState(new tracked_objects::Tracked())) { | |
240 using std::tr1::is_member_function_pointer; | |
241 func_ = ::std::tr1::bind( | |
242 f, | |
243 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1), | |
244 a2, | |
245 a3, | |
246 a4, | |
247 a5, | |
248 a6); | |
249 | |
250 // Handle the refcounting. | |
251 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)(); | |
252 state_->release_thunk_ = | |
253 ObjectTraits<A1, is_member_function_pointer<Sig>::value >:: | |
254 ReleaseThunk(a1); | |
255 } | |
256 | |
257 // This is to make Closure mimic tr1::function<void()>'s interface. It could | |
258 // also just be void Run(), but mimicing the interface allows us to | |
259 // substitute Closure in whereever tr1::function<void()> could be used in the | |
260 // tr1 libraries. | |
261 void operator()() { func_(); } | |
262 | |
263 tracked_objects::Tracked* tracked() { | |
264 return state_->tracked(); | |
265 } | |
266 | |
267 void Cancel() { | |
268 func_ = ::std::tr1::bind(&DoNothing); | |
willchan no longer on Chromium
2011/01/05 00:30:17
can't this just be std::tr1::function()?
awong
2011/01/05 03:17:42
That actually asserted.
However, I can remove the
willchan no longer on Chromium
2011/01/05 19:44:09
Oh really? Ok, whatever.
| |
269 } | |
270 | |
271 private: | |
272 // Don't let us convert from tr1 quickly. | |
273 Closure(::std::tr1::function<void(void)> f) | |
274 : state_(new ClosureState(new tracked_objects::Tracked())) { | |
275 func_ = ::std::tr1::bind(f); | |
276 } | |
277 | |
278 // This is the tr1 function pointer. | |
279 ::std::tr1::function<void()> func_; | |
280 | |
281 scoped_refptr<ClosureState> state_; | |
282 }; | |
283 | |
284 // Wraps a Closure or a tr1::function<void()) to automatically cancel a task | |
285 // when the ClosureCanceller is deleted. This allows a caller to "nop" all | |
286 // outstanding callbacks registered with the ClosureCanceller. | |
287 class ClosureCanceller { | |
288 public: | |
289 ClosureCanceller() : cancel_state_(new CancelState()) {} | |
290 | |
291 ~ClosureCanceller() { | |
292 cancel_state_->is_canceled = true; | |
293 } | |
294 | |
295 template <typename T> | |
296 Closure Wrap(T c) { | |
297 using ::std::tr1::bind; | |
298 return base::Closure(bind(&ClosureCanceller::Run<T>, cancel_state_, c)); | |
299 } | |
300 | |
301 bool empty() const { | |
302 // The ClosureCanceller has the only reference, no tasks are outstanding. | |
303 return cancel_state_->HasOneRef(); | |
304 } | |
305 | |
306 void RevokeAll() { | |
307 // Cancel all outstanding, then create a new cancel state so this object may | |
308 // be reused. | |
309 cancel_state_->is_canceled = true; | |
310 cancel_state_ = new CancelState(); | |
311 } | |
312 | |
313 private: | |
314 // The ScopedRunnableMethodFactory uses a WeakPtr. This is because it is | |
315 // actually reimplementing the storage for the task object, so a pointer is | |
316 // necessary and thus WeakPtr can be overloaded to serve as a flag. | |
317 // | |
318 // In this design, it seems overkill to use WeakPtr instead of a simple flag | |
319 // class (which WeakPtr eventually devolves into anyways). | |
320 class CancelState : public RefCounted<CancelState> { | |
321 public: | |
322 CancelState() : is_canceled(false) {} | |
323 | |
324 bool is_canceled; | |
325 }; | |
326 | |
327 template <typename T> | |
328 static void Run(scoped_refptr<CancelState> cancel_state, T c) { | |
329 if (!cancel_state->is_canceled) { | |
330 c(); | |
331 } | |
332 } | |
333 | |
334 scoped_refptr<CancelState> cancel_state_; | |
335 }; | |
336 | |
337 } // namespace base | |
338 | |
339 #endif // BASE_CLOSURE_H_ | |
OLD | NEW |