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