Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: base/prebind.h

Issue 6094005: Create "Prebind" a wrapper to tr1::bind. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/base
Patch Set: Remove closure.h and ThunkState Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/message_loop.cc ('k') | base/task.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « base/message_loop.cc ('k') | base/task.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698