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_PREBIND_H | |
6 #define BASE_PREBIND_H | |
7 | |
8 #include <tr1/functional> | |
9 | |
10 #include <base/ref_counted.h> | |
11 #include <base/closure.h> // For UnretainedWrapper | |
12 #include <base/tracked.h> | |
13 | |
14 namespace base { | |
15 | |
16 class ThunkState : public RefCountedThreadSafe<ThunkState> { | |
17 public: | |
18 tracked_objects::Tracked tracked_; | |
willchan no longer on Chromium
2011/01/05 00:59:01
Similar comment as I made on the ClosureState thin
awong
2011/01/05 03:17:42
Okay, I whacked it for now.
| |
19 | |
20 // If we used a list here, we'd have really nice resource management. | |
21 ::std::tr1::function<void(void)> cleanup_; | |
22 | |
23 template <typename T> | |
24 void RetainObject(T* obj) { | |
25 obj->AddRef(); | |
26 cleanup_ = ::std::tr1::bind(&T::Release, obj); | |
27 } | |
28 }; | |
29 | |
30 template <typename O> | |
31 struct RetainTraits; | |
32 | |
33 template <typename O> | |
34 struct RetainTraits<O*> { | |
35 typedef O type; | |
36 static O* unwrap(O* o) { return o; } | |
37 static void RetainObject(ThunkState* state, O* o) { | |
38 state->RetainObject(o); | |
39 } | |
40 }; | |
41 | |
42 template <typename O> | |
43 struct RetainTraits<UnretainedWrapper<O> > { | |
44 typedef O type; | |
45 static O* unwrap(const UnretainedWrapper<O>& o) { return o.get(); } | |
46 static void RetainObject(ThunkState* state, O* o) {} | |
47 }; | |
48 | |
49 template <typename Sig> | |
50 class Thunk; | |
willchan no longer on Chromium
2011/01/05 00:59:01
I'm not sure if thunk is as commonly used a term a
awong
2011/01/05 03:17:42
I don't like Thunk either. After we settle on a p
| |
51 | |
52 template <typename R> | |
53 class Thunk<R(void)> { | |
54 public: | |
55 typedef ::std::tr1::function<R(void)> ThunkType; | |
56 ThunkType f_; | |
57 scoped_refptr<ThunkState> state_; | |
58 | |
59 explicit Thunk(ThunkType f) : f_(f), state_(new ThunkState()) {} | |
60 | |
61 R operator()(void) { | |
62 return f_(); | |
63 } | |
64 }; | |
65 | |
66 template <typename R, typename A0> | |
67 class Thunk<R(A0)> { | |
68 public: | |
69 typedef ::std::tr1::function<R(A0)> ThunkType; | |
70 ThunkType f_; | |
71 scoped_refptr<ThunkState> state_; | |
72 | |
73 explicit Thunk(ThunkType f) : f_(f), state_(new ThunkState()) {} | |
74 | |
75 R operator()(A0& a0) { | |
76 return f_(a0); | |
77 } | |
78 }; | |
79 | |
80 template <typename R, typename A0, typename A1> | |
81 class Thunk<R(A0, A1)> { | |
82 public: | |
83 typedef ::std::tr1::function<R(A0,A1)> ThunkType; | |
84 ThunkType f_; | |
85 ::std::tr1::function<void(void)> cleanup_; | |
86 scoped_refptr<ThunkState> state_; | |
87 | |
88 explicit Thunk(ThunkType f) : f_(f), state_(new ThunkState()) {} | |
89 | |
90 R operator()(const A0& a0, const A1& a1) { | |
91 return f_(a0, a1); | |
92 } | |
93 }; | |
94 | |
95 // Note that when declaring these template parameters, the types used in the | |
96 // function signature MUST not be shared with the types used in the arguments. | |
97 // If they are shared, then automatic conversions break. For example, this | |
98 // should work: | |
99 // | |
100 // void foo(double d); | |
101 // function<void(void)> f = Prebind(&foo, 2); | |
102 // | |
103 // However, if you declare the template for prebind as follows: | |
104 // | |
105 // template <typename R, typename P0> | |
106 // function<R(void)> Prebind(R(*)(P0), P0 p0); | |
107 // | |
108 // Then the line invoking Prebind will fail because 2 is an integer, and P0 is | |
109 // locked to be a double. If instead, you declare the template to not tie the | |
110 // function signature directly to the parameters, the compiler will have the | |
111 // flexibility to do the right conversion. Thus, the correct declaration will | |
112 // look like this: | |
113 // | |
114 // template <typename R, typename X0, typename P0> | |
115 // function<R(void)> Prebind(R(*)(X0), P0 p0); | |
116 // | |
117 // The signature uses the type X0, and the argument uses the type P0. There is | |
118 // no directly relationship enforced by the template declaration. Instead, we | |
119 // rely on the compiler to output in an error of P0 is not converatble to X0. | |
120 // | |
121 | |
122 | |
123 // 1 -> 0 | |
124 template <typename R, typename X0, typename P0> | |
125 Thunk<R(void)> | |
126 Prebind(R(*f)(P0), P0 p0) { | |
127 return Thunk<R(void)>(::std::tr1::bind(f, p0)); | |
128 } | |
129 | |
130 // 2 -> 0 | |
131 template <typename R, typename X0, typename X1, typename P0, typename P1> | |
132 Thunk<R(void)> | |
133 Prebind(R(*f)(X0, X1), P0 p0, P1 p1) { | |
134 return Thunk<R(void)>(::std::tr1::bind(f, p0, p1)); | |
135 } | |
136 | |
137 // 2 -> 1 | |
138 template <typename R, typename X0, typename P0, typename A0> | |
139 Thunk<R(A0)> | |
140 Prebind(R(*f)(X0, A0), P0 p0) { | |
141 return Thunk<R(A0)>(::std::tr1::bind(f, p0, ::std::tr1::placeholders::_1)); | |
142 } | |
143 | |
144 // (curry) 1 -> 0 | |
145 template <typename R, typename X0, typename P0> | |
146 Thunk<R(void)> | |
147 Prebind(Thunk<R(X0)> f, P0 p0) { | |
148 return Thunk<R(void)>(::std::tr1::bind(f, p0)); | |
149 } | |
150 | |
151 // (curry) 2 -> 0 | |
152 template <typename R, typename X0, typename X1, typename P0, typename P1> | |
153 Thunk<R(void)> | |
154 Prebind(Thunk<R(X0, X1)> f, P0 p0, P1 p1) { | |
155 return Thunk<R(void)>(::std::tr1::bind(f, p0, p1)); | |
156 } | |
157 | |
158 // (curry) 2 -> 1 | |
159 template <typename R, typename X0, typename P0, typename A0> | |
160 Thunk<R(A0)> | |
161 Prebind(Thunk<R(X0, A0)> f, P0 p0) { | |
162 return Thunk<R(A0)>(::std::tr1::bind(f, p0, ::std::tr1::placeholders::_1)); | |
163 } | |
164 | |
165 // Method 0 -> 0 | |
166 template <typename R, typename O, typename T> | |
167 Thunk<R(void)> | |
168 Prebind(R(O::*f)(), T t) { | |
169 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
170 Thunk<R(void)> thunk(::std::tr1::bind(f, object_)); | |
171 RetainTraits<T>::RetainObject(thunk.state_.get(), object_); | |
172 return thunk; | |
173 } | |
174 | |
175 // Method 1 -> 0 | |
176 template <typename R, typename O, typename T, typename X0, typename P0> | |
177 Thunk<R(void)> | |
178 Prebind(R(O::*f)(X0), T t, P0 p0) { | |
179 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
180 Thunk<R(void)> thunk(::std::tr1::bind(f, object_, p0)); | |
181 RetainTraits<T>::RetainObject(thunk.state_.get(), object_); | |
182 return thunk; | |
183 } | |
184 | |
185 // Method 1 -> 1 | |
186 template <typename R, typename O, typename T, typename A0> | |
187 Thunk<R(A0)> | |
188 Prebind(R(O::*f)(A0), T t) { | |
189 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
190 Thunk<R(A0)> thunk(::std::tr1::bind(f, object_)); | |
191 RetainTraits<T>::RetainObject(thunk.state_.get(), object_); | |
192 return thunk; | |
193 } | |
194 | |
195 // Method 2 -> 0 | |
196 template <typename R, typename O, typename T, typename X0, typename X1, typename P0, typename P1> | |
197 Thunk<R(void)> | |
198 Prebind(R(O::*f)(X0, X1), T t, P0 p0, P1 p1) { | |
199 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
200 Thunk<R(void)> thunk(::std::tr1::bind(f, object_, p0, p1)); | |
201 RetainTraits<T>::RetainObject(thunk.state_.get(), object_); | |
202 return thunk; | |
203 } | |
204 | |
205 // Method 2 -> 1 | |
206 template <typename R, typename O, typename T, typename X0, typename P0, typename A0> | |
207 Thunk<R(A0)> | |
208 Prebind(R(O::*f)(X0, A0), T t, P0 p0) { | |
209 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
210 Thunk<R(A0)> thunk(::std::tr1::bind(f, object_, p0, ::std::tr1::placeholders:: _1)); | |
211 RetainTraits<T>::RetainObject(thunk.state_.get(), object_); | |
212 return thunk; | |
213 } | |
214 | |
215 // Method 2 -> 2 | |
216 template <typename R, typename O, typename T, typename A0, typename A1> | |
217 Thunk<R(A0, A1)> | |
218 Prebind(R(O::*f)(A0, A1), T t) { | |
219 typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t)); | |
220 Thunk<R(A0,A1)> thunk(::std::tr1::bind(f, object_, | |
221 ::std::tr1::placeholders::_1, | |
222 ::std::tr1::placeholders::_2)); | |
223 RetainTraits<T>::RetainObject(thunk.state_.get(), object_); | |
224 return thunk; | |
225 } | |
226 | |
227 // Method 5 -> 2 ...yeah, I skipped a few...got bored of typing it. | |
228 template <typename R, typename O, typename T, | |
229 typename X0, typename X1, typename X2, | |
230 typename P0, typename P1, typename P2, | |
231 typename A0, typename A1> | |
232 Thunk<R(A0, A1)> | |
233 Prebind(R(O::*f)(X0, X1, X2, A0, A1), T t, P0 p0, P1 p1, P2 p2) { | |
234 O* object_(RetainTraits<T>::unwrap(t)); | |
235 Thunk<R(A0,A1)> thunk(::std::tr1::bind(f, object_, p0, p1, p2, | |
236 ::std::tr1::placeholders::_1, | |
237 ::std::tr1::placeholders::_2)); | |
238 RetainTraits<T>::RetainObject(thunk.state_.get(), object_); | |
239 return thunk; | |
240 } | |
241 | |
242 // Wraps a Thunk to automatically cancel a task when the ThunkCanceller is | |
243 // deleted. This allows a caller to "nop" all outstanding callbacks registered | |
244 // with the ThunkCanceller. | |
245 // | |
246 // Note that if you're also looking at the Closure code, this is nearly | |
247 // identical to ClosureCanceller. In fact, it can be used interchangeably, but | |
248 // I put a forked version here just for completeness. | |
249 class ThunkCanceller { | |
250 public: | |
251 ThunkCanceller() : cancel_state_(new CancelState()) {} | |
252 | |
253 ~ThunkCanceller() { | |
254 cancel_state_->is_canceled = true; | |
255 } | |
256 | |
257 template <typename T> | |
258 Thunk<void(void)> Wrap(T c) { | |
259 using ::std::tr1::bind; | |
260 return base::Thunk<void(void)>(Prebind(&ThunkCanceller::Run<T>, cancel_state _, c)); | |
261 } | |
262 | |
263 bool empty() const { | |
264 // The ThunkCanceller has the only reference, no tasks are outstanding. | |
265 return cancel_state_->HasOneRef(); | |
266 } | |
267 | |
268 void RevokeAll() { | |
269 // Cancel all outstanding, then create a new cancel state so this object may | |
270 // be reused. | |
271 cancel_state_->is_canceled = true; | |
272 cancel_state_ = new CancelState(); | |
273 } | |
274 | |
275 private: | |
276 // The ScopedRunnableMethodFactory uses a WeakPtr. This is because it is | |
277 // actually reimplementing the storage for the task object, so a pointer is | |
278 // necessary and thus WeakPtr can be overloaded to serve as a flag. | |
279 // | |
280 // In this design, it seems overkill to use WeakPtr instead of a simple flag | |
281 // class (which WeakPtr eventually devolves into anyways). | |
282 class CancelState : public RefCounted<CancelState> { | |
283 public: | |
284 CancelState() : is_canceled(false) {} | |
285 | |
286 bool is_canceled; | |
287 }; | |
288 | |
289 template <typename T> | |
290 static void Run(scoped_refptr<CancelState> cancel_state, T c) { | |
291 if (!cancel_state->is_canceled) { | |
292 c(); | |
293 } | |
294 } | |
295 | |
296 scoped_refptr<CancelState> cancel_state_; | |
297 }; | |
298 | |
299 } // namespace base | |
300 | |
301 #endif // BASE_PREBIND_H | |
OLD | NEW |