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

Side by Side Diff: base/closure.h

Issue 6052006: Proof of concept for tr1-based Task replacement. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/net/base
Patch Set: Examples of replacing CreateFunctor, ScopedRMF, CompletionCallback Created 9 years, 12 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/base.gypi ('k') | base/message_loop.h » ('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) 2009 The Chromium Authors. All rights reserved.
brettw 2011/01/04 19:12:17 Copyright is 2 years out of date.
awong 2011/01/04 20:57:13 Done.
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)
brettw 2011/01/04 19:12:17 I think we'd want the implementation of all of the
awong 2011/01/04 20:57:13 Right...I'd like to avoid breaking out a cc file f
31 : tracked_(tracked) {
32 }
33
34 ~ClosureState() {
35 release_thunk_();
willchan no longer on Chromium 2011/01/04 22:27:23 Why? We don't do this for Tasks.
36 }
37
38 tracked_objects::Tracked* tracked() const {
39 return tracked_.get();
40 }
41
42 private:
43 scoped_ptr<tracked_objects::Tracked> tracked_;
willchan no longer on Chromium 2011/01/04 22:27:23 I'm not sure, but this might be a design flaw. Cl
44 };
brettw 2011/01/04 19:12:17 DISALLOW_COPY_AND_ASSIGN?
awong 2011/01/04 20:57:13 Done.
45
46
47 // These are needed to implement a wrapper that disables refcounting on
48 // objects used with a Closure.
49 //
50 // TODO(ajwong): If we implement this similar to std::tr1::reference_wrapper we
51 // can probably simplify the ObjectTraits below and remove one specialization.
52 template <typename O>
53 class UnretainedWrapper {
54 public:
55 explicit UnretainedWrapper(O* o) : obj_(o) {}
56 O* get() { return obj_; }
57
58 private:
59 O* obj_;
60 };
61
62 template <typename O>
63 UnretainedWrapper<O> Unretained(O* o) {
64 return UnretainedWrapper<O>(o);
65 }
66
67 // Note, Closure does not support binding a member function to a reference
68 // object. That is, this will not compile:
brettw 2011/01/04 19:12:17 I find the existence of this "wrong" code confusin
awong 2011/01/04 20:57:13 Removed the incorrect code, and added a comment.
69 //
70 // Foo f;
71 // Closure c = Closure(&Foo::func, f);
72 //
73 // You have to pass in a pointer to it.
74 //
75 // Foo f;
76 // Closure c = Closure(&Foo::func, &f);
77 //
78 // We can make the syntax work out, but it's extra complex and given that we
79 // expect Closure's to refcount the member functions they abstract unless
80 // explicitly told not to, allowing pass by reference doesn't make much sense.
81 class Closure {
82 public:
83
84 // --- Traits object defintions --
brettw 2011/01/04 19:12:17 I'd make sure everything inside the class is inden
awong 2011/01/04 20:57:13 fixed.
85 // This handle changing the syntax, and refcounting for the various types of
86 // parameters that can be passed in.
87
88 template <typename O, bool is_member_function_pointer>
89 struct ObjectTraits;
90
91 // Handle regular pointers.
92 template <typename O>
93 struct ObjectTraits<O*, true> {
94 static O* Unwrap(O* o) {
95 return o;
96 }
97
98 static ::std::tr1::function<void()> RefThunk(O* o) {
brettw 2011/01/04 19:12:17 I've never seen us write "::std" (everywhere we ju
awong 2011/01/04 20:57:13 Done.
99 return ::std::tr1::bind(&O::AddRef, o);
100 }
101 static ::std::tr1::function<void()> ReleaseThunk(O* o) {
102 return ::std::tr1::bind(&O::Release, o);
103 }
104 };
105
106 // If it's not a member function, there is no refcounting, and pass through
107 // the object.
108 template <typename O>
109 struct ObjectTraits<O, false> {
110 static O Unwrap(O o) {
111 return o;
112 }
113
114 static ::std::tr1::function<void()> RefThunk(O o) {
115 return ::std::tr1::bind(&DoNothing);
116 }
117 static ::std::tr1::function<void()> ReleaseThunk(O o) {
118 return ::std::tr1::bind(&DoNothing);
119 }
120 };
121
122 // Object wrapped in Unretained() should not refcount anything, and should
123 // unwrap to a pointer to their type.
124 template <typename O>
125 struct ObjectTraits<UnretainedWrapper<O>, true> {
126 static O* Unwrap(UnretainedWrapper<O> o) {
127 return o.get();
128 }
129
130 static ::std::tr1::function<void()> RefThunk(UnretainedWrapper<O> o) {
131 return ::std::tr1::bind(&DoNothing);
132 }
133
134 static ::std::tr1::function<void()> ReleaseThunk(UnretainedWrapper<O> o) {
135 return ::std::tr1::bind(&DoNothing);
136 }
137 };
138
139
140 // ---- Constructors ----
141 template <typename Sig>
142 Closure(Sig f)
143 : state_(new ClosureState(new tracked_objects::Tracked())) {
brettw 2011/01/04 19:12:17 All these wrapped initializers should be indented
awong 2011/01/04 20:57:13 Done.
144 func_ = ::std::tr1::bind(f);
145 state_->release_thunk_ = ::std::tr1::bind(&DoNothing);
146 }
147
148 template <typename Sig, typename A1>
149 Closure(Sig f, A1 a1)
150 : state_(new ClosureState(new tracked_objects::Tracked())) {
151 using std::tr1::is_member_function_pointer;
152 func_ = ::std::tr1::bind(
153 f,
154 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1));
155
156 // Handle the refcounting.
157 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
158 state_->release_thunk_ =
159 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
160 ReleaseThunk(a1);
161 }
162
163 template <typename Sig, typename A1, typename A2>
164 Closure(Sig f, A1 a1, A2 a2)
165 : state_(new ClosureState(new tracked_objects::Tracked())) {
166 using std::tr1::is_member_function_pointer;
167 func_ = ::std::tr1::bind(
168 f,
169 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
170 a2);
171
172 // Handle the refcounting.
173 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
174 state_->release_thunk_ =
175 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
176 ReleaseThunk(a1);
177 }
178
179 template <typename Sig, typename A1, typename A2, typename A3>
180 Closure(Sig f, A1 a1, A2 a2, A3 a3)
181 : state_(new ClosureState(new tracked_objects::Tracked())) {
182 using std::tr1::is_member_function_pointer;
183 func_ = ::std::tr1::bind(
184 f,
185 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
186 a2,
187 a3);
188
189 // Handle the refcounting.
190 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
191 state_->release_thunk_ =
192 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
193 ReleaseThunk(a1);
194 }
195
196 template <typename Sig, typename A1, typename A2, typename A3,
197 typename A4>
198 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4)
199 : state_(new ClosureState(new tracked_objects::Tracked())) {
brettw 2011/01/04 19:12:17 bind makes an object on the heap underneath, right
brettw 2011/01/04 19:14:58 Actually NewRunnableMethod of course make a "new"
awong 2011/01/04 20:57:13 Right...really, the tr1::function<> reference shou
willchan no longer on Chromium 2011/01/04 22:27:23 I don't think tr1::bind exposes the allocator as a
200 using std::tr1::is_member_function_pointer;
201 func_ = ::std::tr1::bind(
202 f,
203 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
204 a2,
205 a3,
206 a4);
207
208 // Handle the refcounting.
209 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
210 state_->release_thunk_ =
211 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
212 ReleaseThunk(a1);
213 }
214
215 template <typename Sig, typename A1, typename A2, typename A3,
216 typename A4, typename A5>
217 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
brettw 2011/01/04 19:12:17 In NewRunnableMethod we pass the arguments as cons
awong 2011/01/04 20:57:13 Eek...good point. I was copying the tr1::bind API
willchan no longer on Chromium 2011/01/04 21:09:22 Is this correct? NewRunnableMethod() will create
218 : state_(new ClosureState(new tracked_objects::Tracked())) {
219 using std::tr1::is_member_function_pointer;
220 func_ = ::std::tr1::bind(
221 f,
222 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
223 a2,
224 a3,
225 a4,
226 a5);
227
228 // Handle the refcounting.
229 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
230 state_->release_thunk_ =
231 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
232 ReleaseThunk(a1);
233 }
234
235 template <typename Sig, typename A1, typename A2, typename A3,
236 typename A4, typename A5, typename A6>
237 Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
238 : state_(new ClosureState(new tracked_objects::Tracked())) {
239 using std::tr1::is_member_function_pointer;
240 func_ = ::std::tr1::bind(
241 f,
242 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
243 a2,
244 a3,
245 a4,
246 a5,
247 a6);
248
249 // Handle the refcounting.
250 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
251 state_->release_thunk_ =
252 ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
253 ReleaseThunk(a1);
254 }
255
256 // This is to make Closure mimic tr1::function<void()>'s interface. It could
257 // also just be void Run(), but mimicing the interface allows us to
258 // substitute Closure in whereever tr1::function<void()> could be used in the
259 // tr1 libraries.
260 void operator()() { func_(); }
261
262 tracked_objects::Tracked* tracked() {
263 return state_->tracked();
264 }
265
266 void Cancel() {
267 func_ = ::std::tr1::bind(&DoNothing);
268 }
269
270 private:
271 // Don't let us convert from tr1 quickly.
272 Closure(::std::tr1::function<void(void)> f)
273 : state_(new ClosureState(new tracked_objects::Tracked())) {
274 func_ = ::std::tr1::bind(f);
275 }
276
277 // This is the tr1 function pointer.
278 ::std::tr1::function<void()> func_;
279
280 scoped_refptr<ClosureState> state_;
281 };
282
283 // Wraps a Closure or a tr1::function<void()) to automatically cancel a task
284 // when the ClosureCanceller is deleted. This allows a caller to "nop" all
285 // outstanding callbacks registered with the ClosureCanceller.
286 class ClosureCanceller {
287 public:
288 ClosureCanceller() : cancel_state_(new CancelState()) {}
brettw 2011/01/04 19:12:17 Ditto for non-inlining these.
awong 2011/01/04 20:57:13 deferring addressing this for now.
289
290 ~ClosureCanceller() {
291 cancel_state_->is_canceled = true;
292 }
293
294 template <typename T>
295 Closure Wrap(T c) {
296 using ::std::tr1::bind;
297 return base::Closure(bind(&ClosureCanceller::Run<T>, cancel_state_, c));
298 }
299
300 bool empty() const {
brettw 2011/01/04 19:12:17 Since this calls an uppercase (non-inlinable-for-f
awong 2011/01/04 20:57:13 Was replicating the ScopedRunnableMethodFactory AP
301 // The ClosureCanceller has the only reference, no tasks are outstanding.
302 return cancel_state_->HasOneRef();
303 }
304
305 void RevokeAll() {
306 // Cancel all outstanding, then create a new cancel state so this object may
307 // be reused.
308 cancel_state_->is_canceled = true;
309 cancel_state_ = new CancelState();
310 }
311
312 private:
313 // The ScopedRunnableMethodFactory uses a WeakPtr. This is because it is
314 // actually reimplementing the storage for the task object, so a pointer is
315 // necessary and thus WeakPtr can be overloaded to serve as a flag.
316 //
317 // In this design, it seems overkill to use WeakPtr instead of a simple flag
318 // class (which WeakPtr eventually devolves into anyways).
319 class CancelState : public RefCounted<CancelState> {
brettw 2011/01/04 19:12:17 The definition of this can probably be moved to th
awong 2011/01/04 20:57:13 deferred via TODO at the top of the file.
320 public:
321 CancelState() : is_canceled(false) {}
322
323 bool is_canceled;
324 };
325
326 template <typename T>
327 static void Run(scoped_refptr<CancelState> cancel_state, T c) {
328 if (!cancel_state->is_canceled) {
329 c();
330 }
331 }
332
333 scoped_refptr<CancelState> cancel_state_;
334 };
brettw 2011/01/04 19:12:17 DISALLOW_COPY_AND_ASSIGN?
awong 2011/01/04 20:57:13 Done.
335
336 } // namespace base
337
338 #endif // BASE_CLOSURE_H_
OLDNEW
« no previous file with comments | « base/base.gypi ('k') | base/message_loop.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698