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

Side by Side Diff: base/closure.h

Issue 6094005: Create "Prebind" a wrapper to tr1::bind. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/base
Patch Set: Closure example ported to Prebinds 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
OLDNEW
(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_CLOSURE_H_
6 #define BASE_CLOSURE_H_
7 #pragma once
8
9 #include <tr1/functional>
10
11 #include "base/ref_counted.h"
12 #include "base/scoped_ptr.h"
13 #include "base/tracked.h"
14
15 namespace base {
16
17 extern void DoNothing(); // Defined in base/task.h.
18
19 // We are trying to mimic value-object semantics of tr1::function in the
20 // Closure API. Thus, we need to detach the tracked object, and some other
21 // state as a shared state.
22 //
23 // As is, there are some threadsafety issues, but the general idea should be
24 // correct.
25 class ClosureState : public RefCountedThreadSafe<ClosureState> {
26 public:
27 // TODO(ajwong): Put these behind an accessor.
28 ::std::tr1::function<void()> release_thunk_;
29
30 explicit ClosureState(tracked_objects::Tracked* tracked)
31 : release_thunk_(&DoNothing),
32 tracked_(tracked) {
33 }
34
35 ~ClosureState() {
36 release_thunk_();
37 }
38
39 tracked_objects::Tracked* tracked() const {
40 return tracked_.get();
41 }
42
43 private:
44 scoped_ptr<tracked_objects::Tracked> tracked_;
45 };
46
47
48 // These are needed to implement a wrapper that disables refcounting on
49 // objects used with a Closure.
50 //
51 // TODO(ajwong): If we implement this similar to std::tr1::reference_wrapper we
52 // can probably simplify the ObjectTraits below and remove one specialization.
53 template <typename O>
54 class UnretainedWrapper {
55 public:
56 explicit UnretainedWrapper(O* o) : obj_(o) {}
57 O* get() const { return obj_; }
58
59 private:
60 O* obj_;
61 };
62
63 template <typename O>
64 UnretainedWrapper<O> Unretained(O* o) {
65 return UnretainedWrapper<O>(o);
66 }
67
68 // Note, Closure does not support binding a member function to a reference
69 // object. That is, this will not compile:
70 //
71 // Foo f;
72 // Closure c = Closure(&Foo::func, f);
73 //
74 // You have to pass in a pointer to it.
75 //
76 // Foo f;
77 // Closure c = Closure(&Foo::func, &f);
78 //
79 // We can make the syntax work out, but it's extra complex and given that we
80 // expect Closure's to refcount the member functions they abstract unless
81 // explicitly told not to, allowing pass by reference doesn't make much sense.
82 class Closure {
83 public:
84
85 // --- Traits object defintions --
86 // This handle changing the syntax, and refcounting for the various types of
87 // parameters that can be passed in.
88
89 template <typename O, bool is_member_function_pointer>
90 struct ObjectTraits;
91
92 // Handle regular pointers.
93 template <typename O>
94 struct ObjectTraits<O*, true> {
95 static O* Unwrap(O* o) {
96 return o;
97 }
98
99 static ::std::tr1::function<void()> RefThunk(O* o) {
willchan no longer on Chromium 2011/01/05 00:30:17 Do we really need to use Thunks here? Is the flex
awong 2011/01/05 03:17:42 Looking at this more, I don't think it's quite tha
willchan no longer on Chromium 2011/01/05 19:44:09 I never said template parameter. I said parameter
100 return ::std::tr1::bind(&O::AddRef, o);
101 }
102 static ::std::tr1::function<void()> ReleaseThunk(O* o) {
103 return ::std::tr1::bind(&O::Release, o);
104 }
105 };
106
107 // If it's not a member function, there is no refcounting, and pass through
108 // the object.
109 template <typename O>
110 struct ObjectTraits<O, false> {
111 static O Unwrap(O o) {
112 return o;
113 }
114
115 static ::std::tr1::function<void()> RefThunk(O o) {
116 return ::std::tr1::bind(&DoNothing);
117 }
118 static ::std::tr1::function<void()> ReleaseThunk(O o) {
119 return ::std::tr1::bind(&DoNothing);
120 }
121 };
122
123 // Object wrapped in Unretained() should not refcount anything, and should
124 // unwrap to a pointer to their type.
125 template <typename O>
126 struct ObjectTraits<UnretainedWrapper<O>, true> {
127 static O* Unwrap(UnretainedWrapper<O> o) {
128 return o.get();
129 }
130
131 static ::std::tr1::function<void()> RefThunk(UnretainedWrapper<O> o) {
132 return ::std::tr1::bind(&DoNothing);
133 }
134
135 static ::std::tr1::function<void()> ReleaseThunk(UnretainedWrapper<O> o) {
136 return ::std::tr1::bind(&DoNothing);
137 }
138 };
139
140
141 // ---- Constructors ----
142 template <typename Sig>
143 Closure(Sig f)
144 : state_(new ClosureState(new tracked_objects::Tracked())) {
145 func_ = ::std::tr1::bind(f);
146 state_->release_thunk_ = ::std::tr1::bind(&DoNothing);
147 }
148
149 template <typename Sig, typename A1>
150 Closure(Sig f, A1 a1)
151 : state_(new ClosureState(new tracked_objects::Tracked())) {
152 using std::tr1::is_member_function_pointer;
153 func_ = ::std::tr1::bind(
154 f,
155 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1));
156
157 // Handle the refcounting.
158 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
159 state_->release_thunk_ =
160 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
161 ReleaseThunk(a1);
162 }
163
164 template <typename Sig, typename A1, typename A2>
165 Closure(Sig f, A1 a1, A2 a2)
166 : state_(new ClosureState(new tracked_objects::Tracked())) {
167 using std::tr1::is_member_function_pointer;
168 func_ = ::std::tr1::bind(
169 f,
170 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
171 a2);
172
173 // Handle the refcounting.
174 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
175 state_->release_thunk_ =
176 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
177 ReleaseThunk(a1);
178 }
179
180 template <typename Sig, typename A1, typename A2, typename A3>
181 Closure(Sig f, A1 a1, A2 a2, A3 a3)
182 : state_(new ClosureState(new tracked_objects::Tracked())) {
183 using std::tr1::is_member_function_pointer;
184 func_ = ::std::tr1::bind(
185 f,
186 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
187 a2,
188 a3);
189
190 // Handle the refcounting.
191 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
192 state_->release_thunk_ =
193 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
194 ReleaseThunk(a1);
195 }
196
197 template <typename Sig, typename A1, typename A2, typename A3,
198 typename A4>
199 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4)
200 : state_(new ClosureState(new tracked_objects::Tracked())) {
201 using std::tr1::is_member_function_pointer;
202 func_ = ::std::tr1::bind(
203 f,
204 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
205 a2,
206 a3,
207 a4);
208
209 // Handle the refcounting.
210 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
211 state_->release_thunk_ =
212 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
213 ReleaseThunk(a1);
214 }
215
216 template <typename Sig, typename A1, typename A2, typename A3,
217 typename A4, typename A5>
218 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
219 : state_(new ClosureState(new tracked_objects::Tracked())) {
220 using std::tr1::is_member_function_pointer;
221 func_ = ::std::tr1::bind(
222 f,
223 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
224 a2,
225 a3,
226 a4,
227 a5);
228
229 // Handle the refcounting.
230 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
231 state_->release_thunk_ =
232 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
233 ReleaseThunk(a1);
234 }
235
236 template <typename Sig, typename A1, typename A2, typename A3,
237 typename A4, typename A5, typename A6>
238 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
239 : state_(new ClosureState(new tracked_objects::Tracked())) {
240 using std::tr1::is_member_function_pointer;
241 func_ = ::std::tr1::bind(
242 f,
243 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
244 a2,
245 a3,
246 a4,
247 a5,
248 a6);
249
250 // Handle the refcounting.
251 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
252 state_->release_thunk_ =
253 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
254 ReleaseThunk(a1);
255 }
256
257 // This is to make Closure mimic tr1::function<void()>'s interface. It could
258 // also just be void Run(), but mimicing the interface allows us to
259 // substitute Closure in whereever tr1::function<void()> could be used in the
260 // tr1 libraries.
261 void operator()() { func_(); }
262
263 tracked_objects::Tracked* tracked() {
264 return state_->tracked();
265 }
266
267 void Cancel() {
268 func_ = ::std::tr1::bind(&DoNothing);
willchan no longer on Chromium 2011/01/05 00:30:17 can't this just be std::tr1::function()?
awong 2011/01/05 03:17:42 That actually asserted. However, I can remove the
willchan no longer on Chromium 2011/01/05 19:44:09 Oh really? Ok, whatever.
269 }
270
271 private:
272 // Don't let us convert from tr1 quickly.
273 Closure(::std::tr1::function<void(void)> f)
274 : state_(new ClosureState(new tracked_objects::Tracked())) {
275 func_ = ::std::tr1::bind(f);
276 }
277
278 // This is the tr1 function pointer.
279 ::std::tr1::function<void()> func_;
280
281 scoped_refptr<ClosureState> state_;
282 };
283
284 // Wraps a Closure or a tr1::function<void()) to automatically cancel a task
285 // when the ClosureCanceller is deleted. This allows a caller to "nop" all
286 // outstanding callbacks registered with the ClosureCanceller.
287 class ClosureCanceller {
288 public:
289 ClosureCanceller() : cancel_state_(new CancelState()) {}
290
291 ~ClosureCanceller() {
292 cancel_state_->is_canceled = true;
293 }
294
295 template <typename T>
296 Closure Wrap(T c) {
297 using ::std::tr1::bind;
298 return base::Closure(bind(&ClosureCanceller::Run<T>, cancel_state_, c));
299 }
300
301 bool empty() const {
302 // The ClosureCanceller has the only reference, no tasks are outstanding.
303 return cancel_state_->HasOneRef();
304 }
305
306 void RevokeAll() {
307 // Cancel all outstanding, then create a new cancel state so this object may
308 // be reused.
309 cancel_state_->is_canceled = true;
310 cancel_state_ = new CancelState();
311 }
312
313 private:
314 // The ScopedRunnableMethodFactory uses a WeakPtr. This is because it is
315 // actually reimplementing the storage for the task object, so a pointer is
316 // necessary and thus WeakPtr can be overloaded to serve as a flag.
317 //
318 // In this design, it seems overkill to use WeakPtr instead of a simple flag
319 // class (which WeakPtr eventually devolves into anyways).
320 class CancelState : public RefCounted<CancelState> {
321 public:
322 CancelState() : is_canceled(false) {}
323
324 bool is_canceled;
325 };
326
327 template <typename T>
328 static void Run(scoped_refptr<CancelState> cancel_state, T c) {
329 if (!cancel_state->is_canceled) {
330 c();
331 }
332 }
333
334 scoped_refptr<CancelState> cancel_state_;
335 };
336
337 } // namespace base
338
339 #endif // BASE_CLOSURE_H_
OLDNEW
« no previous file with comments | « base/base.gypi ('k') | base/message_loop.h » ('j') | base/prebind.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698