OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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_PREBIND_H | |
6 #define BASE_PREBIND_H | |
7 | |
8 #include <tr1/functional> | |
9 | |
10 #include <base/ref_counted.h> | |
11 | |
12 namespace base { | |
13 | |
14 // These are needed to implement a wrapper that disables refcounting on | |
15 // objects used with a Thunk. | |
16 template <typename O> | |
17 class UnretainedWrapper { | |
18 public: | |
19 explicit UnretainedWrapper(O* o) : obj_(o) {} | |
20 O* get() const { return obj_; } | |
21 | |
22 private: | |
23 O* obj_; | |
24 }; | |
25 | |
26 template <typename O> | |
27 UnretainedWrapper<O> Unretained(O* o) { | |
28 return UnretainedWrapper<O>(o); | |
29 } | |
30 | |
31 // Invoker is adds a level of indirection into the function call using syntax | |
32 // that will work with either a raw pointer to an object, or a scoped_refptr. | |
33 // | |
34 // This allows us to pass a scoped_refptr into bind for an object we wish to | |
35 // retrain and maintain the same syntax for invoking its methods. | |
36 // | |
37 // O is either a scoped_refptr<T> or T* where T is the target object. | |
38 template <typename O, typename Sig> | |
39 struct Invoker; | |
40 | |
41 template <typename O, typename R, typename T> | |
42 struct Invoker<O, R(T::*)(void)> { | |
43 static R invoke(R(T::*f)(void), const O& o) { | |
44 return (o->*f)(); | |
45 } | |
46 }; | |
47 | |
48 template <typename O, typename R, typename T, typename A0> | |
49 struct Invoker<O, R(T::*)(A0)> { | |
50 static R invoke(R(T::*f)(A0), const O& o, const A0& a0) { | |
51 return (o->*f)(a0); | |
52 } | |
53 }; | |
54 | |
55 template <typename O, typename R, typename T, typename A0, typename A1> | |
56 struct Invoker<O, R(T::*)(A0, A1)> { | |
57 static R invoke(R(T::*f)(A0, A1), const O& o, const A0& a0, const A1& a1) { | |
58 return (o->*f)(a0, a1); | |
59 } | |
60 }; | |
61 | |
62 template <typename O, typename R, typename T, typename A0, typename A1, | |
63 typename A2> | |
64 struct Invoker<O, R(T::*)(A0, A1, A2)> { | |
65 static R invoke(R(T::*f)(A0, A1, A2), const O& o, const A0& a0, const A1& a1, | |
66 const A2& a2) { | |
67 return (o->*f)(a0, a1, a2); | |
68 } | |
69 }; | |
70 | |
71 template <typename O, typename R, typename T, typename A0, typename A1, | |
72 typename A2, typename A3> | |
73 struct Invoker<O, R(T::*)(A0, A1, A2, A3)> { | |
74 static R invoke(R(T::*f)(A0, A1, A2, A3), const O& o, const A0& a0, | |
75 const A1& a1, const A2& a2, const A3& a3) { | |
76 return (o->*f)(a0, a1, a2, a3); | |
77 } | |
78 }; | |
79 | |
80 template <typename O, typename R, typename T, typename A0, typename A1, | |
81 typename A2, typename A3, typename A4> | |
82 struct Invoker<O, R(T::*)(A0, A1, A2, A3, A4)> { | |
83 static R invoke(R(T::*f)(A0, A1, A2, A3, A4), const O& o, const A0& a0, | |
84 const A1& a1, const A2& a2, const A3& a3, const A4& a4) { | |
85 return (o->*f)(a0, a1, a2, a3, a4); | |
86 } | |
87 }; | |
88 | |
89 template <typename O> | |
90 struct RetainTraits; | |
91 | |
92 template <typename O> | |
93 struct RetainTraits<O*> { | |
94 // TODO(ajwong): Do we need the "type" typedef? Can't we just use O* in | |
95 // prebind since O != T? | |
96 typedef O type; | |
97 typedef scoped_refptr<O> prebind_type; | |
98 | |
99 static O* unwrap(O* o) { return o; } | |
100 static prebind_type MaybeScopedRefptr(O* o) { return o; } | |
101 }; | |
102 | |
103 template <typename O> | |
104 struct RetainTraits<UnretainedWrapper<O> > { | |
105 typedef O type; | |
106 typedef O* prebind_type; | |
107 | |
108 static O* unwrap(const UnretainedWrapper<O>& o) { return o.get(); } | |
109 static prebind_type MaybeScopedRefptr(O* o) { return o; } | |
110 }; | |
111 | |
112 template <typename Sig> | |
113 class Thunk; | |
114 | |
115 // TODO(ajwong): Thunk should have a pointer that can be set to refer to a | |
116 // "tracked" object. This should be set/unset by messageloop when it creates | |
117 // the pending task. That should give nearly equivalent functionality to | |
118 // Task inheriting from Tracked. | |
119 template <typename R> | |
120 class Thunk<R(void)> { | |
121 public: | |
122 typedef std::tr1::function<R(void)> ThunkType; | |
123 ThunkType f_; | |
124 | |
125 explicit Thunk(ThunkType f) : f_(f) {} | |
126 | |
127 R operator()(void) { | |
128 return f_(); | |
129 } | |
130 }; | |
131 | |
132 template <typename R, typename A0> | |
133 class Thunk<R(A0)> { | |
134 public: | |
135 typedef std::tr1::function<R(A0)> ThunkType; | |
136 ThunkType f_; | |
137 | |
138 explicit Thunk(ThunkType f) : f_(f) {} | |
139 | |
140 R operator()(A0& a0) { | |
141 return f_(a0); | |
142 } | |
143 }; | |
144 | |
145 template <typename R, typename A0, typename A1> | |
146 class Thunk<R(A0, A1)> { | |
147 public: | |
148 typedef std::tr1::function<R(A0,A1)> ThunkType; | |
149 ThunkType f_; | |
150 std::tr1::function<void(void)> cleanup_; | |
151 | |
152 explicit Thunk(ThunkType f) : f_(f) {} | |
153 | |
154 R operator()(const A0& a0, const A1& a1) { | |
155 return f_(a0, a1); | |
156 } | |
157 }; | |
158 | |
159 // Note that when declaring these template parameters, the types used in the | |
160 // function signature MUST not be shared with the types used in the arguments. | |
161 // If they are shared, then automatic conversions break. For example, this | |
162 // should work: | |
163 // | |
164 // void foo(double d); | |
165 // function<void(void)> f = Prebind(&foo, 2); | |
166 // | |
167 // However, if you declare the template for prebind as follows: | |
168 // | |
169 // template <typename R, typename P0> | |
170 // function<R(void)> Prebind(R(*)(P0), P0 p0); | |
171 // | |
172 // Then the line invoking Prebind will fail because 2 is an integer, and P0 is | |
173 // locked to be a double. If instead, you declare the template to not tie the | |
174 // function signature directly to the parameters, the compiler will have the | |
175 // flexibility to do the right conversion. Thus, the correct declaration will | |
176 // look like this: | |
177 // | |
178 // template <typename R, typename X0, typename P0> | |
179 // function<R(void)> Prebind(R(*)(X0), P0 p0); | |
180 // | |
181 // The signature uses the type X0, and the argument uses the type P0. There is | |
182 // no directly relationship enforced by the template declaration. Instead, we | |
183 // rely on the compiler to output in an error of P0 is not converatble to X0. | |
184 // | |
185 | |
186 | |
187 // 1 -> 0 | |
188 template <typename R, typename X0, typename P0> | |
189 Thunk<R(void)> | |
190 Prebind(R(*f)(X0), P0 p0) { | |
191 return Thunk<R(void)>(std::tr1::bind(f, p0)); | |
192 } | |
193 | |
194 // 2 -> 0 | |
195 template <typename R, typename X0, typename X1, typename P0, typename P1> | |
196 Thunk<R(void)> | |
197 Prebind(R(*f)(X0, X1), P0 p0, P1 p1) { | |
198 return Thunk<R(void)>(std::tr1::bind(f, p0, p1)); | |
199 } | |
200 | |
201 // 2 -> 1 | |
202 template <typename R, typename X0, typename P0, typename A0> | |
203 Thunk<R(A0)> | |
204 Prebind(R(*f)(X0, A0), P0 p0) { | |
205 return Thunk<R(A0)>(std::tr1::bind(f, p0, std::tr1::placeholders::_1)); | |
206 } | |
207 | |
208 // (curry) 1 -> 0 | |
209 template <typename R, typename X0, typename P0> | |
210 Thunk<R(void)> | |
211 Prebind(Thunk<R(X0)> f, P0 p0) { | |
212 return Thunk<R(void)>(std::tr1::bind(f, p0)); | |
213 } | |
214 | |
215 // (curry) 2 -> 0 | |
216 template <typename R, typename X0, typename X1, typename P0, typename P1> | |
217 Thunk<R(void)> | |
218 Prebind(Thunk<R(X0, X1)> f, P0 p0, P1 p1) { | |
219 return Thunk<R(void)>(std::tr1::bind(f, p0, p1)); | |
220 } | |
221 | |
222 // (curry) 2 -> 1 | |
223 template <typename R, typename X0, typename P0, typename A0> | |
224 Thunk<R(A0)> | |
225 Prebind(Thunk<R(X0, A0)> f, P0 p0) { | |
226 return Thunk<R(A0)>(std::tr1::bind(f, p0, std::tr1::placeholders::_1)); | |
227 } | |
228 | |
229 // Method 0 -> 0 | |
230 template <typename R, typename O, typename T> | |
231 Thunk<R(void)> | |
232 Prebind(R(O::*f)(), T t) { | |
233 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
willchan no longer on Chromium
2011/01/05 19:44:09
Here you take T, which may be scoped_refptr<O>, an
| |
234 return Thunk<R(void)>( | |
235 std::tr1::bind( | |
236 &Invoker<typename RetainTraits<T>::prebind_type, | |
237 R(O::*)(void)>::invoke, | |
238 f, | |
239 RetainTraits<T>::MaybeScopedRefptr(object_))); | |
willchan no longer on Chromium
2011/01/05 19:44:09
MaybeScopedRefptr() basically always forces using
| |
240 } | |
241 | |
242 // Method 1 -> 0 | |
243 template <typename R, typename O, typename T, typename X0, typename P0> | |
244 Thunk<R(void)> | |
245 Prebind(R(O::*f)(X0), T t, P0 p0) { | |
246 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
247 | |
248 return Thunk<R(void)>( | |
249 std::tr1::bind( | |
250 &Invoker<typename RetainTraits<T>::prebind_type, | |
251 R(O::*)(X0)>::invoke, | |
252 f, | |
253 RetainTraits<T>::MaybeScopedRefptr(object_), | |
254 p0)); | |
255 } | |
256 | |
257 // Method 1 -> 1 | |
258 template <typename R, typename O, typename T, typename A0> | |
259 Thunk<R(A0)> | |
260 Prebind(R(O::*f)(A0), T t) { | |
261 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
262 | |
263 return Thunk<R(void)>( | |
264 std::tr1::bind( | |
265 &Invoker<typename RetainTraits<T>::prebind_type, | |
266 R(O::*)(A0)>::invoke, | |
267 f, | |
268 RetainTraits<T>::MaybeScopedRefptr(object_), | |
269 std::tr1::placeholders::_1)); | |
270 } | |
271 | |
272 // Method 2 -> 0 | |
273 template <typename R, typename O, typename T, typename X0, typename X1, | |
274 typename P0, typename P1> | |
275 Thunk<R(void)> | |
276 Prebind(R(O::*f)(X0, X1), T t, P0 p0, P1 p1) { | |
277 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
278 return Thunk<R(void)>( | |
279 std::tr1::bind( | |
280 &Invoker<typename RetainTraits<T>::prebind_type, | |
281 R(O::*)(X0,X1)>::invoke, | |
282 f, | |
283 RetainTraits<T>::MaybeScopedRefptr(object_), | |
284 p0, | |
285 p1)); | |
286 } | |
287 | |
288 // Method 2 -> 1 | |
289 template <typename R, typename O, typename T, typename X0, typename P0, | |
290 typename A0> | |
291 Thunk<R(A0)> | |
292 Prebind(R(O::*f)(X0, A0), T t, P0 p0) { | |
293 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
294 return Thunk<R(A0)>( | |
295 std::tr1::bind( | |
296 &Invoker<typename RetainTraits<T>::prebind_type, | |
297 R(O::*)(X0, A0)>::invoke, | |
298 f, | |
299 RetainTraits<T>::MaybeScopedRefptr(object_), | |
300 p0, | |
301 std::tr1::placeholders::_1)); | |
302 } | |
303 | |
304 // Method 2 -> 2 | |
305 template <typename R, typename O, typename T, typename A0, typename A1> | |
306 Thunk<R(A0, A1)> | |
307 Prebind(R(O::*f)(A0, A1), T t) { | |
308 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
309 | |
310 return Thunk<R(A0, A1)>( | |
311 std::tr1::bind( | |
312 &Invoker<typename RetainTraits<T>::prebind_type, | |
313 R(O::*)(A0, A1)>::invoke, | |
314 f, | |
315 RetainTraits<T>::MaybeScopedRefptr(object_), | |
316 std::tr1::placeholders::_1, | |
317 std::tr1::placeholders::_2)); | |
318 } | |
319 | |
320 // Method 5 -> 2 ...yeah, I skipped a few...got bored of typing it. | |
321 template <typename R, typename O, typename T, | |
322 typename X0, typename X1, typename X2, | |
323 typename P0, typename P1, typename P2, | |
324 typename A0, typename A1> | |
325 Thunk<R(A0, A1)> | |
326 Prebind(R(O::*f)(X0, X1, X2, A0, A1), T t, P0 p0, P1 p1, P2 p2) { | |
327 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
328 | |
329 return Thunk<R(A0, A1)>( | |
330 std::tr1::bind( | |
331 &Invoker<typename RetainTraits<T>::prebind_type, | |
332 R(O::*)(X0, X1, X2, A0, A1)>::invoke, | |
333 f, | |
334 RetainTraits<T>::MaybeScopedRefptr(object_), | |
335 p0, p1, p2, | |
336 std::tr1::placeholders::_1, | |
337 std::tr1::placeholders::_2)); | |
338 } | |
339 | |
340 // Wraps a Thunk to automatically cancel a task when the ThunkCanceller is | |
341 // deleted. This allows a caller to "nop" all outstanding callbacks registered | |
342 // with the ThunkCanceller. | |
343 // | |
344 // Note that if you're also looking at the Closure code, this is nearly | |
345 // identical to ClosureCanceller. In fact, it can be used interchangeably, but | |
346 // I put a forked version here just for completeness. | |
347 class ThunkCanceller { | |
348 public: | |
349 ThunkCanceller() : cancel_state_(new CancelState()) {} | |
350 | |
351 ~ThunkCanceller() { | |
352 cancel_state_->is_canceled = true; | |
353 } | |
354 | |
355 template <typename T> | |
356 Thunk<void(void)> Wrap(T c) { | |
357 using std::tr1::bind; | |
358 return base::Thunk<void(void)>( | |
359 Prebind(&ThunkCanceller::Run<T>, cancel_state_, c)); | |
360 } | |
361 | |
362 bool empty() const { | |
363 // The ThunkCanceller has the only reference, no tasks are outstanding. | |
364 return cancel_state_->HasOneRef(); | |
365 } | |
366 | |
367 void RevokeAll() { | |
368 // Cancel all outstanding, then create a new cancel state so this object may | |
369 // be reused. | |
370 cancel_state_->is_canceled = true; | |
371 cancel_state_ = new CancelState(); | |
372 } | |
373 | |
374 private: | |
375 // The ecopedRunnableMethodFactory uses a WeakPtr. This is because it is | |
376 // actually reimplementing the storage for the task object, so a pointer is | |
377 // necessary and thus WeakPtr can be overloaded to serve as a flag. | |
378 // | |
379 // In this design, it seems overkill to use WeakPtr instead of a simple flag | |
380 // class (which WeakPtr eventually devolves into anyways). | |
381 class CancelState : public RefCounted<CancelState> { | |
382 public: | |
383 CancelState() : is_canceled(false) {} | |
384 | |
385 bool is_canceled; | |
386 }; | |
387 | |
388 template <typename T> | |
389 static void Run(scoped_refptr<CancelState> cancel_state, T c) { | |
390 if (!cancel_state->is_canceled) { | |
391 c(); | |
392 } | |
393 } | |
394 | |
395 scoped_refptr<CancelState> cancel_state_; | |
396 | |
397 DISALLOW_COPY_AND_ASSIGN(ThunkCanceller); | |
398 }; | |
399 | |
400 } // namespace base | |
401 | |
402 #endif // BASE_PREBIND_H | |
OLD | NEW |