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 PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ | |
6 #define PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ | |
7 | |
8 #include "ppapi/cpp/completion_callback.h" | |
9 #include "ppapi/utility/non_thread_safe_ref_count.h" | |
10 | |
11 namespace pp { | |
12 | |
13 /// CompletionCallbackFactory<T> may be used to create CompletionCallback | |
14 /// objects that are bound to member functions. | |
15 /// | |
16 /// If a factory is destroyed, then any pending callbacks will be cancelled | |
17 /// preventing any bound member functions from being called. The CancelAll() | |
18 /// method allows pending callbacks to be cancelled without destroying the | |
19 /// factory. | |
20 /// | |
21 /// <strong>Note: </strong><code>CompletionCallbackFactory<T></code> isn't | |
22 /// thread safe, but you can make it more thread-friendly by passing a | |
23 /// thread-safe refcounting class as the second template element. However, it | |
24 /// only guarantees safety for creating a callback from another thread, the | |
25 /// callback itself needs to execute on the same thread as the thread that | |
26 /// creates/destroys the factory. With this restriction, it is safe to create | |
27 /// the <code>CompletionCallbackFactory</code> on the main thread, create | |
28 /// callbacks from any thread and pass them to CallOnMainThread(). | |
29 /// | |
30 /// <strong>Example: </strong> | |
31 /// | |
32 /// @code | |
33 /// | |
34 /// class MyHandler { | |
35 /// public: | |
36 /// // If an compiler warns on following using |this| in the initializer | |
37 /// // list, use PP_ALLOW_THIS_IN_INITIALIZER_LIST macro. | |
38 /// MyHandler() : factory_(this), offset_(0) { | |
39 /// } | |
40 /// | |
41 /// void ProcessFile(const FileRef& file) { | |
42 /// CompletionCallback cc = factory_.NewRequiredCallback( | |
43 /// &MyHandler::DidOpen); | |
44 /// int32_t rv = fio_.Open(file, PP_FileOpenFlag_Read, cc); | |
45 /// CHECK(rv == PP_OK_COMPLETIONPENDING); | |
46 /// } | |
47 /// | |
48 /// private: | |
49 /// CompletionCallback NewCallback() { | |
50 /// return factory_.NewCallback(&MyHandler::DidCompleteIO); | |
51 /// } | |
52 /// | |
53 /// void DidOpen(int32_t result) { | |
54 /// if (result == PP_OK) { | |
55 /// // The file is open, and we can begin reading. | |
56 /// offset_ = 0; | |
57 /// ReadMore(); | |
58 /// } else { | |
59 /// // Failed to open the file with error given by 'result'. | |
60 /// } | |
61 /// } | |
62 /// | |
63 /// void DidRead(int32_t result) { | |
64 /// if (result > 0) { | |
65 /// // buf_ now contains 'result' number of bytes from the file. | |
66 /// ProcessBytes(buf_, result); | |
67 /// offset_ += result; | |
68 /// ReadMore(); | |
69 /// } else { | |
70 /// // Done reading (possibly with an error given by 'result'). | |
71 /// } | |
72 /// } | |
73 /// | |
74 /// void ReadMore() { | |
75 /// CompletionCallback cc = | |
76 /// factory_.NewOptionalCallback(&MyHandler::DidRead); | |
77 /// int32_t rv = fio_.Read(offset_, buf_, sizeof(buf_), | |
78 /// cc.pp_completion_callback()); | |
79 /// if (rv != PP_OK_COMPLETIONPENDING) | |
80 /// cc.Run(rv); | |
81 /// } | |
82 /// | |
83 /// void ProcessBytes(const char* bytes, int32_t length) { | |
84 /// // Do work ... | |
85 /// } | |
86 /// | |
87 /// pp::CompletionCallbackFactory<MyHandler> factory_; | |
88 /// pp::FileIO fio_; | |
89 /// char buf_[4096]; | |
90 /// int64_t offset_; | |
91 /// }; | |
92 /// | |
93 /// @endcode | |
94 /// | |
95 template <typename T, typename RefCount = NonThreadSafeRefCount> | |
96 class CompletionCallbackFactory { | |
97 public: | |
98 | |
99 /// This constructor creates a <code>CompletionCallbackFactory</code> | |
100 /// bound to an object. If the constructor is called without an argument, | |
101 /// the default value of <code>NULL</code> is used. The user then must call | |
102 /// Initialize() to initialize the object. | |
103 /// | |
104 /// param[in] object Optional parameter. An object whose member functions | |
105 /// are to be bound to CompletionCallbacks created by this | |
106 /// <code>CompletionCallbackFactory</code>. The default value of this | |
107 /// parameter is <code>NULL</code>. | |
108 explicit CompletionCallbackFactory(T* object = NULL) | |
109 : object_(object) { | |
110 InitBackPointer(); | |
111 } | |
112 | |
113 /// Destructor. | |
114 ~CompletionCallbackFactory() { | |
115 ResetBackPointer(); | |
116 } | |
117 | |
118 /// CancelAll() cancels all <code>CompletionCallbacks</code> allocated from | |
119 /// this factory. | |
120 void CancelAll() { | |
121 ResetBackPointer(); | |
122 InitBackPointer(); | |
123 } | |
124 /// Initialize() binds the <code>CallbackFactory</code> to a particular | |
125 /// object. Use this when the object is not available at | |
126 /// <code>CallbackFactory</code> creation, and the <code>NULL</code> default | |
127 /// is passed to the constructor. The object may only be initialized once, | |
128 /// either by the constructor, or by a call to Initialize(). | |
129 /// | |
130 /// @param[in] object The object whose member functions are to be bound to | |
131 /// the <code>CompletionCallback</code> created by this | |
132 /// <code>CompletionCallbackFactory</code>. | |
133 void Initialize(T* object) { | |
134 PP_DCHECK(object); | |
135 PP_DCHECK(!object_); // May only initialize once! | |
136 object_ = object; | |
137 } | |
138 | |
139 /// GetObject() returns the object that was passed at initialization to | |
140 /// Intialize(). | |
141 /// | |
142 /// @return the object passed to the constructor or Intialize(). | |
143 T* GetObject() { | |
144 return object_; | |
145 } | |
146 | |
147 /// NewCallback allocates a new, single-use <code>CompletionCallback</code>. | |
148 /// The <code>CompletionCallback</code> must be run in order for the memory | |
149 /// allocated by the methods to be freed. | |
150 /// NewCallback() is equivalent to NewRequiredCallback() below. | |
151 /// | |
152 /// @param[in] method The method to be invoked upon completion of the | |
153 /// operation. | |
154 /// | |
155 /// @return A <code>CompletionCallback</code>. | |
156 template <typename Method> | |
157 CompletionCallback NewCallback(Method method) { | |
158 PP_DCHECK(object_); | |
159 return NewCallbackHelper(Dispatcher0<Method>(method)); | |
160 } | |
161 | |
162 /// NewRequiredCallback() allocates a new, single-use | |
163 /// <code>CompletionCallback</code> that will always run. The | |
164 /// <code>CompletionCallback</code> must be run in order for the memory | |
165 /// allocated by the methods to be freed. | |
166 /// | |
167 /// @param[in] method The method to be invoked upon completion of the | |
168 /// operation. | |
169 /// | |
170 /// @return A <code>CompletionCallback</code>. | |
171 template <typename Method> | |
172 CompletionCallback NewRequiredCallback(Method method) { | |
173 CompletionCallback cc = NewCallback(method); | |
174 cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
175 return cc; | |
176 } | |
177 | |
178 /// NewOptionalCallback() allocates a new, single-use | |
179 /// <code>CompletionCallback</code> that might not run if the method | |
180 /// taking it can complete synchronously. Thus, if after passing the | |
181 /// CompletionCallback to a Pepper method, the method does not return | |
182 /// PP_OK_COMPLETIONPENDING, then you should manually call the | |
183 /// CompletionCallback's Run method, or memory will be leaked. | |
184 /// | |
185 /// @param[in] method The method to be invoked upon completion of the | |
186 /// operation. | |
187 /// | |
188 /// @return A <code>CompletionCallback</code>. | |
189 template <typename Method> | |
190 CompletionCallback NewOptionalCallback(Method method) { | |
191 CompletionCallback cc = NewCallback(method); | |
192 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
193 return cc; | |
194 } | |
195 | |
196 /// NewCallback() allocates a new, single-use <code>CompletionCallback</code>. | |
197 /// The <code>CompletionCallback</code> must be run in order for the memory | |
198 /// allocated by the methods to be freed. | |
199 /// NewCallback() is equivalent to NewRequiredCallback() below. | |
200 /// | |
201 /// @param[in] method The method to be invoked upon completion of the | |
202 /// operation. Method should be of type: | |
203 /// <code>void (T::*)(int32_t result, const A& a)</code> | |
204 /// | |
205 /// @param[in] a Passed to <code>method</code> when the completion callback | |
206 /// runs. | |
207 /// | |
208 /// @return A <code>CompletionCallback</code>. | |
209 template <typename Method, typename A> | |
210 CompletionCallback NewCallback(Method method, const A& a) { | |
211 PP_DCHECK(object_); | |
212 return NewCallbackHelper(Dispatcher1<Method, A>(method, a)); | |
213 } | |
214 | |
215 /// NewRequiredCallback() allocates a new, single-use | |
216 /// <code>CompletionCallback</code> that will always run. The | |
217 /// <code>CompletionCallback</code> must be run in order for the memory | |
218 /// allocated by the methods to be freed. | |
219 /// | |
220 /// @param[in] method The method to be invoked upon completion of the | |
221 /// operation. Method should be of type: | |
222 /// <code>void (T::*)(int32_t result, const A& a)</code> | |
223 /// | |
224 /// @param[in] a Passed to <code>method</code> when the completion callback | |
225 /// runs. | |
226 /// | |
227 /// @return A <code>CompletionCallback</code>. | |
228 template <typename Method, typename A> | |
229 CompletionCallback NewRequiredCallback(Method method, const A& a) { | |
230 CompletionCallback cc = NewCallback(method, a); | |
231 cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
232 return cc; | |
233 } | |
234 | |
235 /// NewOptionalCallback() allocates a new, single-use | |
236 /// <code>CompletionCallback</code> that might not run if the method | |
237 /// taking it can complete synchronously. Thus, if after passing the | |
238 /// CompletionCallback to a Pepper method, the method does not return | |
239 /// PP_OK_COMPLETIONPENDING, then you should manually call the | |
240 /// CompletionCallback's Run method, or memory will be leaked. | |
241 /// | |
242 /// @param[in] method The method to be invoked upon completion of the | |
243 /// operation. Method should be of type: | |
244 /// <code>void (T::*)(int32_t result, const A& a)</code> | |
245 /// | |
246 /// @param[in] a Passed to <code>method</code> when the completion callback | |
247 /// runs. | |
248 /// | |
249 /// @return A <code>CompletionCallback</code>. | |
250 template <typename Method, typename A> | |
251 CompletionCallback NewOptionalCallback(Method method, const A& a) { | |
252 CompletionCallback cc = NewCallback(method, a); | |
253 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
254 return cc; | |
255 } | |
256 | |
257 /// NewCallback() allocates a new, single-use | |
258 /// <code>CompletionCallback</code>. | |
259 /// The <code>CompletionCallback</code> must be run in order for the memory | |
260 /// allocated by the methods to be freed. | |
261 /// NewCallback() is equivalent to NewRequiredCallback() below. | |
262 /// | |
263 /// @param method The method taking the callback. Method should be of type: | |
264 /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code> | |
265 /// | |
266 /// @param[in] a Passed to <code>method</code> when the completion callback | |
267 /// runs. | |
268 /// | |
269 /// @param[in] b Passed to <code>method</code> when the completion callback | |
270 /// runs. | |
271 /// | |
272 /// @return A <code>CompletionCallback</code>. | |
273 template <typename Method, typename A, typename B> | |
274 CompletionCallback NewCallback(Method method, const A& a, const B& b) { | |
275 PP_DCHECK(object_); | |
276 return NewCallbackHelper(Dispatcher2<Method, A, B>(method, a, b)); | |
277 } | |
278 | |
279 /// NewRequiredCallback() allocates a new, single-use | |
280 /// <code>CompletionCallback</code> that will always run. The | |
281 /// <code>CompletionCallback</code> must be run in order for the memory | |
282 /// allocated by the methods to be freed. | |
283 /// | |
284 /// @param method The method taking the callback. Method should be of type: | |
285 /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code> | |
286 /// | |
287 /// @param[in] a Passed to <code>method</code> when the completion callback | |
288 /// runs. | |
289 /// | |
290 /// @param[in] b Passed to <code>method</code> when the completion callback | |
291 /// runs. | |
292 /// | |
293 /// @return A <code>CompletionCallback</code>. | |
294 template <typename Method, typename A, typename B> | |
295 CompletionCallback NewRequiredCallback(Method method, const A& a, | |
296 const B& b) { | |
297 CompletionCallback cc = NewCallback(method, a, b); | |
298 cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
299 return cc; | |
300 } | |
301 | |
302 /// NewOptionalCallback() allocates a new, single-use | |
303 /// <code>CompletionCallback</code> that might not run if the method | |
304 /// taking it can complete synchronously. Thus, if after passing the | |
305 /// CompletionCallback to a Pepper method, the method does not return | |
306 /// PP_OK_COMPLETIONPENDING, then you should manually call the | |
307 /// CompletionCallback's Run method, or memory will be leaked. | |
308 /// | |
309 /// @param[in] method The method taking the callback. Method should be of | |
310 /// type: | |
311 /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code> | |
312 /// | |
313 /// @param[in] a Passed to <code>method</code> when the completion callback | |
314 /// runs. | |
315 /// | |
316 /// @param[in] b Passed to <code>method</code> when the completion callback | |
317 /// runs. | |
318 /// | |
319 /// @return A <code>CompletionCallback</code>. | |
320 template <typename Method, typename A, typename B> | |
321 CompletionCallback NewOptionalCallback(Method method, const A& a, | |
322 const B& b) { | |
323 CompletionCallback cc = NewCallback(method, a, b); | |
324 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
325 return cc; | |
326 } | |
327 | |
328 /// NewCallback() allocates a new, single-use | |
329 /// <code>CompletionCallback</code>. | |
330 /// The <code>CompletionCallback</code> must be run in order for the memory | |
331 /// allocated by the methods to be freed. | |
332 /// NewCallback() is equivalent to NewRequiredCallback() below. | |
333 /// | |
334 /// @param method The method taking the callback. Method should be of type: | |
335 /// <code> | |
336 /// void (T::*)(int32_t result, const A& a, const B& b, const C& c) | |
337 /// </code> | |
338 /// | |
339 /// @param[in] a Passed to <code>method</code> when the completion callback | |
340 /// runs. | |
341 /// | |
342 /// @param[in] b Passed to <code>method</code> when the completion callback | |
343 /// runs. | |
344 /// | |
345 /// @param[in] c Passed to <code>method</code> when the completion callback | |
346 /// runs. | |
347 /// | |
348 /// @return A <code>CompletionCallback</code>. | |
349 template <typename Method, typename A, typename B, typename C> | |
350 CompletionCallback NewCallback(Method method, const A& a, const B& b, | |
351 const C& c) { | |
352 PP_DCHECK(object_); | |
353 return NewCallbackHelper(Dispatcher3<Method, A, B, C>(method, a, b, c)); | |
354 } | |
355 | |
356 /// NewRequiredCallback() allocates a new, single-use | |
357 /// <code>CompletionCallback</code> that will always run. The | |
358 /// <code>CompletionCallback</code> must be run in order for the memory | |
359 /// allocated by the methods to be freed. | |
360 /// | |
361 /// @param method The method taking the callback. Method should be of type: | |
362 /// <code> | |
363 /// void (T::*)(int32_t result, const A& a, const B& b, const C& c) | |
364 /// </code> | |
365 /// | |
366 /// @param[in] a Passed to <code>method</code> when the completion callback | |
367 /// runs. | |
368 /// | |
369 /// @param[in] b Passed to <code>method</code> when the completion callback | |
370 /// runs. | |
371 /// | |
372 /// @param[in] c Passed to <code>method</code> when the completion callback | |
373 /// runs. | |
374 /// | |
375 /// @return A <code>CompletionCallback</code>. | |
376 template <typename Method, typename A, typename B, typename C> | |
377 CompletionCallback NewRequiredCallback(Method method, const A& a, | |
378 const B& b, const C& c) { | |
379 CompletionCallback cc = NewCallback(method, a, b, c); | |
380 cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
381 return cc; | |
382 } | |
383 | |
384 /// NewOptionalCallback() allocates a new, single-use | |
385 /// <code>CompletionCallback</code> that might not run if the method | |
386 /// taking it can complete synchronously. Thus, if after passing the | |
387 /// CompletionCallback to a Pepper method, the method does not return | |
388 /// PP_OK_COMPLETIONPENDING, then you should manually call the | |
389 /// CompletionCallback's Run method, or memory will be leaked. | |
390 /// | |
391 /// @param[in] method The method taking the callback. Method should be of | |
392 /// type: | |
393 /// <code> | |
394 /// void (T::*)(int32_t result, const A& a, const B& b, const C& c) | |
395 /// </code> | |
396 /// | |
397 /// @param[in] a Passed to <code>method</code> when the completion callback | |
398 /// runs. | |
399 /// | |
400 /// @param[in] b Passed to <code>method</code> when the completion callback | |
401 /// runs. | |
402 /// | |
403 /// @param[in] c Passed to <code>method</code> when the completion callback | |
404 /// runs. | |
405 /// | |
406 /// @return A <code>CompletionCallback</code>. | |
407 template <typename Method, typename A, typename B, typename C> | |
408 CompletionCallback NewOptionalCallback(Method method, const A& a, | |
409 const B& b, const C& c) { | |
410 CompletionCallback cc = NewCallback(method, a, b, c); | |
411 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); | |
412 return cc; | |
413 } | |
414 | |
415 private: | |
416 class BackPointer { | |
417 public: | |
418 typedef CompletionCallbackFactory<T, RefCount> FactoryType; | |
419 | |
420 BackPointer(FactoryType* factory) | |
421 : factory_(factory) { | |
422 } | |
423 | |
424 void AddRef() { | |
425 ref_.AddRef(); | |
426 } | |
427 | |
428 void Release() { | |
429 if (ref_.Release() == 0) | |
430 delete this; | |
431 } | |
432 | |
433 void DropFactory() { | |
434 factory_ = NULL; | |
435 } | |
436 | |
437 T* GetObject() { | |
438 return factory_ ? factory_->GetObject() : NULL; | |
439 } | |
440 | |
441 private: | |
442 RefCount ref_; | |
443 FactoryType* factory_; | |
444 }; | |
445 | |
446 template <typename Dispatcher> | |
447 class CallbackData { | |
448 public: | |
449 CallbackData(BackPointer* back_pointer, const Dispatcher& dispatcher) | |
450 : back_pointer_(back_pointer), | |
451 dispatcher_(dispatcher) { | |
452 back_pointer_->AddRef(); | |
453 } | |
454 | |
455 ~CallbackData() { | |
456 back_pointer_->Release(); | |
457 } | |
458 | |
459 static void Thunk(void* user_data, int32_t result) { | |
460 Self* self = static_cast<Self*>(user_data); | |
461 T* object = self->back_pointer_->GetObject(); | |
462 if (object) | |
463 self->dispatcher_(object, result); | |
464 delete self; | |
465 } | |
466 | |
467 private: | |
468 typedef CallbackData<Dispatcher> Self; | |
469 BackPointer* back_pointer_; | |
470 Dispatcher dispatcher_; | |
471 }; | |
472 | |
473 template <typename Method> | |
474 class Dispatcher0 { | |
475 public: | |
476 Dispatcher0(Method method) : method_(method) { | |
477 } | |
478 void operator()(T* object, int32_t result) { | |
479 (object->*method_)(result); | |
480 } | |
481 private: | |
482 Method method_; | |
483 }; | |
484 | |
485 template <typename Method, typename A> | |
486 class Dispatcher1 { | |
487 public: | |
488 Dispatcher1(Method method, const A& a) | |
489 : method_(method), | |
490 a_(a) { | |
491 } | |
492 void operator()(T* object, int32_t result) { | |
493 (object->*method_)(result, a_); | |
494 } | |
495 private: | |
496 Method method_; | |
497 A a_; | |
498 }; | |
499 | |
500 template <typename Method, typename A, typename B> | |
501 class Dispatcher2 { | |
502 public: | |
503 Dispatcher2(Method method, const A& a, const B& b) | |
504 : method_(method), | |
505 a_(a), | |
506 b_(b) { | |
507 } | |
508 void operator()(T* object, int32_t result) { | |
509 (object->*method_)(result, a_, b_); | |
510 } | |
511 private: | |
512 Method method_; | |
513 A a_; | |
514 B b_; | |
515 }; | |
516 | |
517 template <typename Method, typename A, typename B, typename C> | |
518 class Dispatcher3 { | |
519 public: | |
520 Dispatcher3(Method method, const A& a, const B& b, const C& c) | |
521 : method_(method), | |
522 a_(a), | |
523 b_(b), | |
524 c_(c) { | |
525 } | |
526 void operator()(T* object, int32_t result) { | |
527 (object->*method_)(result, a_, b_, c_); | |
528 } | |
529 private: | |
530 Method method_; | |
531 A a_; | |
532 B b_; | |
533 C c_; | |
534 }; | |
535 | |
536 void InitBackPointer() { | |
537 back_pointer_ = new BackPointer(this); | |
538 back_pointer_->AddRef(); | |
539 } | |
540 | |
541 void ResetBackPointer() { | |
542 back_pointer_->DropFactory(); | |
543 back_pointer_->Release(); | |
544 } | |
545 | |
546 template <typename Dispatcher> | |
547 CompletionCallback NewCallbackHelper(const Dispatcher& dispatcher) { | |
548 PP_DCHECK(object_); // Expects a non-null object! | |
549 return CompletionCallback( | |
550 &CallbackData<Dispatcher>::Thunk, | |
551 new CallbackData<Dispatcher>(back_pointer_, dispatcher)); | |
552 } | |
553 | |
554 // Disallowed: | |
555 CompletionCallbackFactory(const CompletionCallbackFactory&); | |
556 CompletionCallbackFactory& operator=(const CompletionCallbackFactory&); | |
557 | |
558 T* object_; | |
559 BackPointer* back_pointer_; | |
560 }; | |
561 | |
562 } // namespace pp | |
563 | |
564 #endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ | |
OLD | NEW |