Chromium Code Reviews| 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 |