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

Side by Side Diff: ppapi/utility/completion_callback_factory.h

Issue 9651002: Add C++ wrappers for output parameters. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 9 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 | « ppapi/ppapi_sources.gypi ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ 5 #ifndef PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
6 #define PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ 6 #define PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
7 7
8 #include "ppapi/cpp/completion_callback.h" 8 #include "ppapi/cpp/completion_callback.h"
9 #include "ppapi/utility/non_thread_safe_ref_count.h" 9 #include "ppapi/utility/non_thread_safe_ref_count.h"
10 10
11 namespace pp { 11 namespace pp {
12 12
13 // TypeUnwrapper --------------------------------------------------------------
14
15 namespace internal {
16
17 // The TypeUnwrapper converts references and const references to the
18 // underlying type used for storage and passing as an argument. It is for
19 // internal use only.
20 template <typename T> struct TypeUnwrapper {
21 typedef T StorageType;
22 };
23 template <typename T> struct TypeUnwrapper<T&> {
24 typedef T StorageType;
25 };
26 template <typename T> struct TypeUnwrapper<const T&> {
27 typedef T StorageType;
28 };
29
30 } // namespace internal
31
32 // ----------------------------------------------------------------------------
33
13 /// CompletionCallbackFactory<T> may be used to create CompletionCallback 34 /// CompletionCallbackFactory<T> may be used to create CompletionCallback
14 /// objects that are bound to member functions. 35 /// objects that are bound to member functions.
15 /// 36 ///
16 /// If a factory is destroyed, then any pending callbacks will be cancelled 37 /// If a factory is destroyed, then any pending callbacks will be cancelled
17 /// preventing any bound member functions from being called. The CancelAll() 38 /// preventing any bound member functions from being called. The CancelAll()
18 /// method allows pending callbacks to be cancelled without destroying the 39 /// method allows pending callbacks to be cancelled without destroying the
19 /// factory. 40 /// factory.
20 /// 41 ///
21 /// <strong>Note: </strong><code>CompletionCallbackFactory<T></code> isn't 42 /// <strong>Note: </strong><code>CompletionCallbackFactory<T></code> isn't
22 /// thread safe, but you can make it more thread-friendly by passing a 43 /// 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 44 /// thread-safe refcounting class as the second template element. However, it
24 /// only guarantees safety for creating a callback from another thread, the 45 /// 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 46 /// 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 47 /// creates/destroys the factory. With this restriction, it is safe to create
27 /// the <code>CompletionCallbackFactory</code> on the main thread, create 48 /// the <code>CompletionCallbackFactory</code> on the main thread, create
28 /// callbacks from any thread and pass them to CallOnMainThread(). 49 /// callbacks from any thread and pass them to CallOnMainThread().
29 /// 50 ///
30 /// <strong>Example: </strong> 51 /// <strong>Example: </strong>
31 /// 52 ///
32 /// @code 53 /// @code
33 /// 54 /// class MyClass {
34 /// class MyHandler {
35 /// public: 55 /// public:
36 /// // If an compiler warns on following using |this| in the initializer 56 /// // If an compiler warns on following using |this| in the initializer
37 /// // list, use PP_ALLOW_THIS_IN_INITIALIZER_LIST macro. 57 /// // list, use PP_ALLOW_THIS_IN_INITIALIZER_LIST macro.
38 /// MyHandler() : factory_(this), offset_(0) { 58 /// MyClass() : factory_(this) {
39 /// } 59 /// }
40 /// 60 ///
41 /// void ProcessFile(const FileRef& file) { 61 /// void OpenFile(const pp::FileRef& file) {
42 /// CompletionCallback cc = factory_.NewCallback( 62 /// pp::CompletionCallback cc = factory_.NewCallback(&MyClass::DidOpen);
43 /// &MyHandler::DidOpen); 63 /// int32_t rv = file_io_.Open(file, PP_FileOpenFlag_Read, cc);
44 /// int32_t rv = fio_.Open(file, PP_FileOpenFlag_Read, cc);
45 /// CHECK(rv == PP_OK_COMPLETIONPENDING); 64 /// CHECK(rv == PP_OK_COMPLETIONPENDING);
46 /// } 65 /// }
47 /// 66 ///
48 /// private: 67 /// private:
49 /// CompletionCallback NewCallback() {
50 /// return factory_.NewCallback(&MyHandler::DidCompleteIO);
51 /// }
52 ///
53 /// void DidOpen(int32_t result) { 68 /// void DidOpen(int32_t result) {
54 /// if (result == PP_OK) { 69 /// if (result == PP_OK) {
55 /// // The file is open, and we can begin reading. 70 /// // The file is open, and we can begin reading.
56 /// offset_ = 0; 71 /// // ...
57 /// ReadMore();
58 /// } else { 72 /// } else {
59 /// // Failed to open the file with error given by 'result'. 73 /// // Failed to open the file with error given by 'result'.
60 /// } 74 /// }
61 /// } 75 /// }
62 /// 76 ///
63 /// void DidRead(int32_t result) { 77 /// pp::CompletionCallbackFactory<MyClass> factory_;
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 /// }; 78 /// };
92 ///
93 /// @endcode 79 /// @endcode
94 /// 80 ///
81 /// <strong>Passing additional parameters to your callback</strong>
82 ///
83 /// As a convenience, the <code>CompletionCallbackFactory</code> can optionally
84 /// create a closure with up to three bound parameters that it will pass to
85 /// your callback function. This can be useful for passing information about
86 /// the request to your callback function, which is especially useful if your
87 /// class has multiple asynchronous callbacks pending.
88 ///
89 /// For the above example, of opening a file, let's say you want to keep some
90 /// description associated with your request, you might implement your OpenFile
91 /// and DidOpen callback as follows:
92 ///
93 /// @code
94 /// void OpenFile(const pp::FileRef& file) {
95 /// std::string message = "Opening file!";
96 /// pp::CompletionCallback cc = factory_.NewCallback(&MyClass::DidOpen,
97 /// message);
98 /// int32_t rv = file_io_.Open(file, PP_FileOpenFlag_Read, cc);
99 /// CHECK(rv == PP_OK_COMPLETIONPENDING);
100 /// }
101 /// void DidOpen(int32_t result, const std::string& message) {
102 /// // "message" will be "Opening file!".
103 /// ...
104 /// }
105 /// @endcode
106 ///
107 /// <strong>Optional versus required callbacks</strong>
108 ///
109 /// When you create an "optional" callback, the browser may return the results
110 /// synchronously if they are available. This can allow for higher performance
111 /// in some cases if data is available quickly (for example, for network loads
112 /// where there may be a lot of data coming quickly). In this case, the
113 /// callback will never be run.
114 ///
115 /// When creating a new callback with the factory, there will be data allocated
116 /// on the heap that tracks the callback information and any bound arguments.
117 /// This data is freed when the callback executes. In the case of optional
118 /// callbacks, since the browser will never issue the callback, the internal
119 /// tracking data will be leaked.
120 ///
121 /// Therefore, if you use optional callbacks, it's important to manually
122 /// issue the callback to free up this data. The typical pattern is:
123 ///
124 /// @code
125 /// pp::CompletionCallback callback = callback_factory.NewOptionalCallback(
126 /// &MyClass::OnDataReady);
127 /// int32_t result = interface->GetData(callback);
128 /// if (result != PP_OK_COMPLETIONPENDING)
129 /// callback.Run(result);
130 /// @endcode
131 ///
132 /// Because of this additional complexity, it's generally recommended that
133 /// you not use optional callbacks except when performance is more important
134 /// (such as loading large resources from the network). In most other cases,
135 /// the performance difference will not be worth the additional complexity,
136 /// and most functions may never actually have the ability to complete
137 /// synchronously.
138 ///
139 /// <strong>Completion callbacks with output</strong>
140 ///
141 /// For some API calls, the browser returns data to the caller via an output
142 /// parameter. These can be difficult to manage since the output parameter
143 /// must remain valid for as long as the callback is pending. Note also that
144 /// CancelAll (or destroying the callback factory) does <i>not</i> cancel the
145 /// callback from the browser's perspective, only the execution of the callback
146 /// in the plugin code, and the output parameter will still be written to!
147 /// This means that you can't use class members as output parameters without
148 /// risking crashes.
149 ///
150 /// To make this case easier, the CompletionCallbackFactory can allocate and
151 /// manage the output data for you and pass it to your callback function. This
152 /// makes such calls more natural and less error-prone.
153 ///
154 /// To create such a callback, use NewCallbackWithOutput and specify a callback
155 /// function that takes the output parameter as its second argument. Let's say
156 /// you're calling a function GetFile which asynchronously returns a
157 /// pp::FileRef. GetFile's signature will be <code>int32_t GetFile(const
158 /// CompletionCallbackWithOutput<pp::FileRef>& callback);</code> and your
159 /// calling code would look like this:
160 ///
161 /// @code
162 /// void RequestFile() {
163 /// file_interface->GetFile(callback_factory_.NewCallbackWithOutput(
164 /// &MyClass::GotFile));
165 /// }
166 /// void GotFile(int32_t result, const pp::FileRef& file) {
167 /// if (result == PP_OK) {
168 /// ...use file...
169 /// } else {
170 /// ...handle error...
171 /// }
172 /// }
173 /// @endcode
174 ///
175 /// As with regular completion callbacks, you can optionally add up to three
176 /// bound arguments. These are passed following the output argument.
177 ///
178 /// Your callback may take the output argument as a copy (common for small
179 /// types like integers, a const reference (common for structures and
180 /// resources to avoid an extra copy), or as a non-const reference. One
181 /// optimization you can do if your callback function may take large arrays
182 /// is to accept your output argument as a non-const reference and to swap()
183 /// the argument with a vector of your own to store it. This means you don't
184 /// have to copy the buffer to consume it.
95 template <typename T, typename RefCount = NonThreadSafeRefCount> 185 template <typename T, typename RefCount = NonThreadSafeRefCount>
96 class CompletionCallbackFactory { 186 class CompletionCallbackFactory {
97 public: 187 public:
98 188
99 /// This constructor creates a <code>CompletionCallbackFactory</code> 189 /// This constructor creates a <code>CompletionCallbackFactory</code>
100 /// bound to an object. If the constructor is called without an argument, 190 /// 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 191 /// the default value of <code>NULL</code> is used. The user then must call
102 /// Initialize() to initialize the object. 192 /// Initialize() to initialize the object.
103 /// 193 ///
104 /// param[in] object Optional parameter. An object whose member functions 194 /// param[in] object Optional parameter. An object whose member functions
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 /// The <code>CompletionCallback</code> must be run in order for the memory 238 /// The <code>CompletionCallback</code> must be run in order for the memory
149 /// allocated by the methods to be freed. 239 /// allocated by the methods to be freed.
150 /// 240 ///
151 /// @param[in] method The method to be invoked upon completion of the 241 /// @param[in] method The method to be invoked upon completion of the
152 /// operation. 242 /// operation.
153 /// 243 ///
154 /// @return A <code>CompletionCallback</code>. 244 /// @return A <code>CompletionCallback</code>.
155 template <typename Method> 245 template <typename Method>
156 CompletionCallback NewCallback(Method method) { 246 CompletionCallback NewCallback(Method method) {
157 PP_DCHECK(object_); 247 PP_DCHECK(object_);
158 return NewCallbackHelper(Dispatcher0<Method>(method)); 248 return NewCallbackHelper(new Dispatcher0<Method>(method));
159 } 249 }
160 250
161 /// NewOptionalCallback() allocates a new, single-use 251 /// NewOptionalCallback() allocates a new, single-use
162 /// <code>CompletionCallback</code> that might not run if the method 252 /// <code>CompletionCallback</code> that might not run if the method
163 /// taking it can complete synchronously. Thus, if after passing the 253 /// taking it can complete synchronously. Thus, if after passing the
164 /// CompletionCallback to a Pepper method, the method does not return 254 /// CompletionCallback to a Pepper method, the method does not return
165 /// PP_OK_COMPLETIONPENDING, then you should manually call the 255 /// PP_OK_COMPLETIONPENDING, then you should manually call the
166 /// CompletionCallback's Run method, or memory will be leaked. 256 /// CompletionCallback's Run method, or memory will be leaked.
167 /// 257 ///
168 /// @param[in] method The method to be invoked upon completion of the 258 /// @param[in] method The method to be invoked upon completion of the
169 /// operation. 259 /// operation.
170 /// 260 ///
171 /// @return A <code>CompletionCallback</code>. 261 /// @return A <code>CompletionCallback</code>.
172 template <typename Method> 262 template <typename Method>
173 CompletionCallback NewOptionalCallback(Method method) { 263 CompletionCallback NewOptionalCallback(Method method) {
174 CompletionCallback cc = NewCallback(method); 264 CompletionCallback cc = NewCallback(method);
175 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); 265 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
176 return cc; 266 return cc;
177 } 267 }
178 268
269 /// NewCallbackWithOutput() allocates a new, single-use
270 /// <code>CompletionCallback</code> where the browser will pass an additional
271 /// parameter comtaining the result of the request. The
272 /// <code>CompletionCallback</code> must be run in order for the memory
273 /// allocated by the methods to be freed.
274 ///
275 /// @param[in] method The method to be invoked upon completion of the
276 /// operation.
277 ///
278 /// @return A <code>CompletionCallback</code>.
279 template <typename Output>
280 CompletionCallbackWithOutput<
281 typename internal::TypeUnwrapper<Output>::StorageType>
282 NewCallbackWithOutput(void (T::*method)(int32_t, Output)) {
283 return NewCallbackWithOutputHelper(new DispatcherWithOutput0<
284 typename internal::TypeUnwrapper<Output>::StorageType,
285 void (T::*)(int32_t, Output)>(method));
286 }
287
179 /// NewCallback() allocates a new, single-use <code>CompletionCallback</code>. 288 /// NewCallback() allocates a new, single-use <code>CompletionCallback</code>.
180 /// The <code>CompletionCallback</code> must be run in order for the memory 289 /// The <code>CompletionCallback</code> must be run in order for the memory
181 /// allocated by the methods to be freed. 290 /// allocated by the methods to be freed.
182 /// 291 ///
183 /// @param[in] method The method to be invoked upon completion of the 292 /// @param[in] method The method to be invoked upon completion of the
184 /// operation. Method should be of type: 293 /// operation. Method should be of type:
185 /// <code>void (T::*)(int32_t result, const A& a)</code> 294 /// <code>void (T::*)(int32_t result, const A& a)</code>
186 /// 295 ///
187 /// @param[in] a Passed to <code>method</code> when the completion callback 296 /// @param[in] a Passed to <code>method</code> when the completion callback
188 /// runs. 297 /// runs.
189 /// 298 ///
190 /// @return A <code>CompletionCallback</code>. 299 /// @return A <code>CompletionCallback</code>.
191 template <typename Method, typename A> 300 template <typename Method, typename A>
192 CompletionCallback NewCallback(Method method, const A& a) { 301 CompletionCallback NewCallback(Method method, const A& a) {
193 PP_DCHECK(object_); 302 PP_DCHECK(object_);
194 return NewCallbackHelper(Dispatcher1<Method, A>(method, a)); 303 return NewCallbackHelper(new Dispatcher1<Method, A>(method, a));
195 } 304 }
196 305
197 /// NewOptionalCallback() allocates a new, single-use 306 /// NewOptionalCallback() allocates a new, single-use
198 /// <code>CompletionCallback</code> that might not run if the method 307 /// <code>CompletionCallback</code> that might not run if the method
199 /// taking it can complete synchronously. Thus, if after passing the 308 /// taking it can complete synchronously. Thus, if after passing the
200 /// CompletionCallback to a Pepper method, the method does not return 309 /// CompletionCallback to a Pepper method, the method does not return
201 /// PP_OK_COMPLETIONPENDING, then you should manually call the 310 /// PP_OK_COMPLETIONPENDING, then you should manually call the
202 /// CompletionCallback's Run method, or memory will be leaked. 311 /// CompletionCallback's Run method, or memory will be leaked.
203 /// 312 ///
204 /// @param[in] method The method to be invoked upon completion of the 313 /// @param[in] method The method to be invoked upon completion of the
205 /// operation. Method should be of type: 314 /// operation. Method should be of type:
206 /// <code>void (T::*)(int32_t result, const A& a)</code> 315 /// <code>void (T::*)(int32_t result, const A& a)</code>
207 /// 316 ///
208 /// @param[in] a Passed to <code>method</code> when the completion callback 317 /// @param[in] a Passed to <code>method</code> when the completion callback
209 /// runs. 318 /// runs.
210 /// 319 ///
211 /// @return A <code>CompletionCallback</code>. 320 /// @return A <code>CompletionCallback</code>.
212 template <typename Method, typename A> 321 template <typename Method, typename A>
213 CompletionCallback NewOptionalCallback(Method method, const A& a) { 322 CompletionCallback NewOptionalCallback(Method method, const A& a) {
214 CompletionCallback cc = NewCallback(method, a); 323 CompletionCallback cc = NewCallback(method, a);
215 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); 324 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
216 return cc; 325 return cc;
217 } 326 }
218 327
328 /// NewCallbackWithOutput() allocates a new, single-use
329 /// <code>CompletionCallback</code> where the browser will pass an additional
330 /// parameter comtaining the result of the request. The
331 /// <code>CompletionCallback</code> must be run in order for the memory
332 /// allocated by the methods to be freed.
333 ///
334 /// @param[in] method The method to be invoked upon completion of the
335 /// operation.
336 ///
337 /// @param[in] a Passed to <code>method</code> when the completion callback
338 /// runs.
339 ///
340 /// @return A <code>CompletionCallback</code>.
341 template <typename Output, typename A>
342 CompletionCallbackWithOutput<
343 typename internal::TypeUnwrapper<Output>::StorageType>
344 NewCallbackWithOutput(void (T::*method)(int32_t, Output, A),
345 const A& a) {
346 return NewCallbackWithOutputHelper(new DispatcherWithOutput1<
347 typename internal::TypeUnwrapper<Output>::StorageType,
348 void (T::*)(int32_t, Output, A),
349 typename internal::TypeUnwrapper<A>::StorageType>(method, a));
350 }
351
219 /// NewCallback() allocates a new, single-use 352 /// NewCallback() allocates a new, single-use
220 /// <code>CompletionCallback</code>. 353 /// <code>CompletionCallback</code>.
221 /// The <code>CompletionCallback</code> must be run in order for the memory 354 /// The <code>CompletionCallback</code> must be run in order for the memory
222 /// allocated by the methods to be freed. 355 /// allocated by the methods to be freed.
223 /// 356 ///
224 /// @param method The method taking the callback. Method should be of type: 357 /// @param method The method taking the callback. Method should be of type:
225 /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code> 358 /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code>
226 /// 359 ///
227 /// @param[in] a Passed to <code>method</code> when the completion callback 360 /// @param[in] a Passed to <code>method</code> when the completion callback
228 /// runs. 361 /// runs.
229 /// 362 ///
230 /// @param[in] b Passed to <code>method</code> when the completion callback 363 /// @param[in] b Passed to <code>method</code> when the completion callback
231 /// runs. 364 /// runs.
232 /// 365 ///
233 /// @return A <code>CompletionCallback</code>. 366 /// @return A <code>CompletionCallback</code>.
234 template <typename Method, typename A, typename B> 367 template <typename Method, typename A, typename B>
235 CompletionCallback NewCallback(Method method, const A& a, const B& b) { 368 CompletionCallback NewCallback(Method method, const A& a, const B& b) {
236 PP_DCHECK(object_); 369 PP_DCHECK(object_);
237 return NewCallbackHelper(Dispatcher2<Method, A, B>(method, a, b)); 370 return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b));
238 } 371 }
239 372
240 /// NewOptionalCallback() allocates a new, single-use 373 /// NewOptionalCallback() allocates a new, single-use
241 /// <code>CompletionCallback</code> that might not run if the method 374 /// <code>CompletionCallback</code> that might not run if the method
242 /// taking it can complete synchronously. Thus, if after passing the 375 /// taking it can complete synchronously. Thus, if after passing the
243 /// CompletionCallback to a Pepper method, the method does not return 376 /// CompletionCallback to a Pepper method, the method does not return
244 /// PP_OK_COMPLETIONPENDING, then you should manually call the 377 /// PP_OK_COMPLETIONPENDING, then you should manually call the
245 /// CompletionCallback's Run method, or memory will be leaked. 378 /// CompletionCallback's Run method, or memory will be leaked.
246 /// 379 ///
247 /// @param[in] method The method taking the callback. Method should be of 380 /// @param[in] method The method taking the callback. Method should be of
248 /// type: 381 /// type:
249 /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code> 382 /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code>
250 /// 383 ///
251 /// @param[in] a Passed to <code>method</code> when the completion callback 384 /// @param[in] a Passed to <code>method</code> when the completion callback
252 /// runs. 385 /// runs.
253 /// 386 ///
254 /// @param[in] b Passed to <code>method</code> when the completion callback 387 /// @param[in] b Passed to <code>method</code> when the completion callback
255 /// runs. 388 /// runs.
256 /// 389 ///
257 /// @return A <code>CompletionCallback</code>. 390 /// @return A <code>CompletionCallback</code>.
258 template <typename Method, typename A, typename B> 391 template <typename Method, typename A, typename B>
259 CompletionCallback NewOptionalCallback(Method method, const A& a, 392 CompletionCallback NewOptionalCallback(Method method, const A& a,
260 const B& b) { 393 const B& b) {
261 CompletionCallback cc = NewCallback(method, a, b); 394 CompletionCallback cc = NewCallback(method, a, b);
262 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); 395 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
263 return cc; 396 return cc;
264 } 397 }
265 398
399 /// NewCallbackWithOutput() allocates a new, single-use
400 /// <code>CompletionCallback</code> where the browser will pass an additional
401 /// parameter comtaining the result of the request. The
402 /// <code>CompletionCallback</code> must be run in order for the memory
403 /// allocated by the methods to be freed.
404 ///
405 /// @param[in] method The method to be invoked upon completion of the
406 /// operation.
407 ///
408 /// @param[in] a Passed to <code>method</code> when the completion callback
409 /// runs.
410 ///
411 /// @param[in] b Passed to <code>method</code> when the completion callback
412 /// runs.
413 ///
414 /// @return A <code>CompletionCallback</code>.
415 template <typename Output, typename A, typename B>
416 CompletionCallbackWithOutput<
417 typename internal::TypeUnwrapper<Output>::StorageType>
418 NewCallbackWithOutput(void (T::*method)(int32_t, Output, A, B),
419 const A& a,
420 const B& b) {
421 return NewCallbackWithOutputHelper(new DispatcherWithOutput2<
422 typename internal::TypeUnwrapper<Output>::StorageType,
423 void (T::*)(int32_t, Output, A, B),
424 typename internal::TypeUnwrapper<A>::StorageType,
425 typename internal::TypeUnwrapper<B>::StorageType>(method, a, b));
426 }
427
266 /// NewCallback() allocates a new, single-use 428 /// NewCallback() allocates a new, single-use
267 /// <code>CompletionCallback</code>. 429 /// <code>CompletionCallback</code>.
268 /// The <code>CompletionCallback</code> must be run in order for the memory 430 /// The <code>CompletionCallback</code> must be run in order for the memory
269 /// allocated by the methods to be freed. 431 /// allocated by the methods to be freed.
270 /// 432 ///
271 /// @param method The method taking the callback. Method should be of type: 433 /// @param method The method taking the callback. Method should be of type:
272 /// <code> 434 /// <code>
273 /// void (T::*)(int32_t result, const A& a, const B& b, const C& c) 435 /// void (T::*)(int32_t result, const A& a, const B& b, const C& c)
274 /// </code> 436 /// </code>
275 /// 437 ///
276 /// @param[in] a Passed to <code>method</code> when the completion callback 438 /// @param[in] a Passed to <code>method</code> when the completion callback
277 /// runs. 439 /// runs.
278 /// 440 ///
279 /// @param[in] b Passed to <code>method</code> when the completion callback 441 /// @param[in] b Passed to <code>method</code> when the completion callback
280 /// runs. 442 /// runs.
281 /// 443 ///
282 /// @param[in] c Passed to <code>method</code> when the completion callback 444 /// @param[in] c Passed to <code>method</code> when the completion callback
283 /// runs. 445 /// runs.
284 /// 446 ///
285 /// @return A <code>CompletionCallback</code>. 447 /// @return A <code>CompletionCallback</code>.
286 template <typename Method, typename A, typename B, typename C> 448 template <typename Method, typename A, typename B, typename C>
287 CompletionCallback NewCallback(Method method, const A& a, const B& b, 449 CompletionCallback NewCallback(Method method, const A& a, const B& b,
288 const C& c) { 450 const C& c) {
289 PP_DCHECK(object_); 451 PP_DCHECK(object_);
290 return NewCallbackHelper(Dispatcher3<Method, A, B, C>(method, a, b, c)); 452 return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c));
291 } 453 }
292 454
293 /// NewOptionalCallback() allocates a new, single-use 455 /// NewOptionalCallback() allocates a new, single-use
294 /// <code>CompletionCallback</code> that might not run if the method 456 /// <code>CompletionCallback</code> that might not run if the method
295 /// taking it can complete synchronously. Thus, if after passing the 457 /// taking it can complete synchronously. Thus, if after passing the
296 /// CompletionCallback to a Pepper method, the method does not return 458 /// CompletionCallback to a Pepper method, the method does not return
297 /// PP_OK_COMPLETIONPENDING, then you should manually call the 459 /// PP_OK_COMPLETIONPENDING, then you should manually call the
298 /// CompletionCallback's Run method, or memory will be leaked. 460 /// CompletionCallback's Run method, or memory will be leaked.
299 /// 461 ///
300 /// @param[in] method The method taking the callback. Method should be of 462 /// @param[in] method The method taking the callback. Method should be of
(...skipping 13 matching lines...) Expand all
314 /// 476 ///
315 /// @return A <code>CompletionCallback</code>. 477 /// @return A <code>CompletionCallback</code>.
316 template <typename Method, typename A, typename B, typename C> 478 template <typename Method, typename A, typename B, typename C>
317 CompletionCallback NewOptionalCallback(Method method, const A& a, 479 CompletionCallback NewOptionalCallback(Method method, const A& a,
318 const B& b, const C& c) { 480 const B& b, const C& c) {
319 CompletionCallback cc = NewCallback(method, a, b, c); 481 CompletionCallback cc = NewCallback(method, a, b, c);
320 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); 482 cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
321 return cc; 483 return cc;
322 } 484 }
323 485
486 /// NewCallbackWithOutput() allocates a new, single-use
487 /// <code>CompletionCallback</code> where the browser will pass an additional
488 /// parameter comtaining the result of the request. The
489 /// <code>CompletionCallback</code> must be run in order for the memory
490 /// allocated by the methods to be freed.
491 ///
492 /// @param method The method to be run.
493 ///
494 /// @param[in] a Passed to <code>method</code> when the completion callback
495 /// runs.
496 ///
497 /// @param[in] b Passed to <code>method</code> when the completion callback
498 /// runs.
499 ///
500 /// @param[in] c Passed to <code>method</code> when the completion callback
501 /// runs.
502 ///
503 /// @return A <code>CompletionCallback</code>.
504 template <typename Output, typename A, typename B, typename C>
505 CompletionCallbackWithOutput<
506 typename internal::TypeUnwrapper<Output>::StorageType>
507 NewCallbackWithOutput(void (T::*method)(int32_t, Output, A, B, C),
508 const A& a,
509 const B& b,
510 const C& c) {
511 return NewCallbackWithOutputHelper(new DispatcherWithOutput3<
512 typename internal::TypeUnwrapper<Output>::StorageType,
513 void (T::*)(int32_t, Output, A, B, C),
514 typename internal::TypeUnwrapper<A>::StorageType,
515 typename internal::TypeUnwrapper<B>::StorageType,
516 typename internal::TypeUnwrapper<C>::StorageType>(method, a, b, c));
517 }
518
324 private: 519 private:
325 class BackPointer { 520 class BackPointer {
326 public: 521 public:
327 typedef CompletionCallbackFactory<T, RefCount> FactoryType; 522 typedef CompletionCallbackFactory<T, RefCount> FactoryType;
328 523
329 BackPointer(FactoryType* factory) 524 explicit BackPointer(FactoryType* factory)
330 : factory_(factory) { 525 : factory_(factory) {
331 } 526 }
332 527
333 void AddRef() { 528 void AddRef() {
334 ref_.AddRef(); 529 ref_.AddRef();
335 } 530 }
336 531
337 void Release() { 532 void Release() {
338 if (ref_.Release() == 0) 533 if (ref_.Release() == 0)
339 delete this; 534 delete this;
340 } 535 }
341 536
342 void DropFactory() { 537 void DropFactory() {
343 factory_ = NULL; 538 factory_ = NULL;
344 } 539 }
345 540
346 T* GetObject() { 541 T* GetObject() {
347 return factory_ ? factory_->GetObject() : NULL; 542 return factory_ ? factory_->GetObject() : NULL;
348 } 543 }
349 544
350 private: 545 private:
351 RefCount ref_; 546 RefCount ref_;
352 FactoryType* factory_; 547 FactoryType* factory_;
353 }; 548 };
354 549
355 template <typename Dispatcher> 550 template <typename Dispatcher>
356 class CallbackData { 551 class CallbackData {
357 public: 552 public:
358 CallbackData(BackPointer* back_pointer, const Dispatcher& dispatcher) 553 // Takes ownership of the given dispatcher pointer.
554 CallbackData(BackPointer* back_pointer, Dispatcher* dispatcher)
359 : back_pointer_(back_pointer), 555 : back_pointer_(back_pointer),
360 dispatcher_(dispatcher) { 556 dispatcher_(dispatcher) {
361 back_pointer_->AddRef(); 557 back_pointer_->AddRef();
362 } 558 }
363 559
364 ~CallbackData() { 560 ~CallbackData() {
365 back_pointer_->Release(); 561 back_pointer_->Release();
562 delete dispatcher_;
366 } 563 }
367 564
565 Dispatcher* dispatcher() { return dispatcher_; }
566
368 static void Thunk(void* user_data, int32_t result) { 567 static void Thunk(void* user_data, int32_t result) {
369 Self* self = static_cast<Self*>(user_data); 568 Self* self = static_cast<Self*>(user_data);
370 T* object = self->back_pointer_->GetObject(); 569 T* object = self->back_pointer_->GetObject();
371 if (object) 570 if (object)
372 self->dispatcher_(object, result); 571 (*self->dispatcher_)(object, result);
373 delete self; 572 delete self;
374 } 573 }
375 574
376 private: 575 private:
377 typedef CallbackData<Dispatcher> Self; 576 typedef CallbackData<Dispatcher> Self;
378 BackPointer* back_pointer_; 577 BackPointer* back_pointer_; // We own a ref to this refcounted object.
379 Dispatcher dispatcher_; 578 Dispatcher* dispatcher_; // We own this pointer.
579
580 // Disallow copying & assignment.
581 CallbackData(const CallbackData<Dispatcher>&);
582 CallbackData<Dispatcher>& operator=(const CallbackData<Dispatcher>&);
380 }; 583 };
381 584
382 template <typename Method> 585 template <typename Method>
383 class Dispatcher0 { 586 class Dispatcher0 {
384 public: 587 public:
385 Dispatcher0(Method method) : method_(method) { 588 Dispatcher0() : method_(NULL) {}
589 explicit Dispatcher0(Method method) : method_(method) {
386 } 590 }
387 void operator()(T* object, int32_t result) { 591 void operator()(T* object, int32_t result) {
388 (object->*method_)(result); 592 (object->*method_)(result);
389 } 593 }
390 private: 594 private:
391 Method method_; 595 Method method_;
392 }; 596 };
393 597
598 template <typename Output, typename Method>
599 class DispatcherWithOutput0 {
600 public:
601 typedef Output OutputType;
602 typedef internal::CallbackOutputTraits<Output> Traits;
603
604 DispatcherWithOutput0() : method_(NULL) {}
605 DispatcherWithOutput0(Method method) : method_(method) {
606 }
607 void operator()(T* object, int32_t result) {
608 (object->*method_)(result, Traits::StorageToPluginArg(output_));
609 }
610 typename Traits::StorageType* output() {
611 return &output_;
612 }
613 private:
614 Method method_;
615
616 typename Traits::StorageType output_;
617 };
618
394 template <typename Method, typename A> 619 template <typename Method, typename A>
395 class Dispatcher1 { 620 class Dispatcher1 {
396 public: 621 public:
622 Dispatcher1() : method_(NULL) {}
397 Dispatcher1(Method method, const A& a) 623 Dispatcher1(Method method, const A& a)
398 : method_(method), 624 : method_(method),
399 a_(a) { 625 a_(a) {
400 } 626 }
401 void operator()(T* object, int32_t result) { 627 void operator()(T* object, int32_t result) {
402 (object->*method_)(result, a_); 628 (object->*method_)(result, a_);
403 } 629 }
404 private: 630 private:
405 Method method_; 631 Method method_;
406 A a_; 632 A a_;
407 }; 633 };
408 634
635 template <typename Output, typename Method, typename A>
636 class DispatcherWithOutput1 {
637 public:
638 typedef Output OutputType;
639 typedef internal::CallbackOutputTraits<Output> Traits;
640
641 DispatcherWithOutput1() : method_(NULL) {}
642 DispatcherWithOutput1(Method method, const A& a)
643 : method_(method),
644 a_(a) {
645 }
646 void operator()(T* object, int32_t result) {
647 (object->*method_)(result, Traits::StorageToPluginArg(output_), a_);
648 }
649 typename Traits::StorageType* output() {
650 return &output_;
651 }
652 private:
653 Method method_;
654 A a_;
655
656 typename Traits::StorageType output_;
657 };
658
409 template <typename Method, typename A, typename B> 659 template <typename Method, typename A, typename B>
410 class Dispatcher2 { 660 class Dispatcher2 {
411 public: 661 public:
662 Dispatcher2() : method_(NULL) {}
412 Dispatcher2(Method method, const A& a, const B& b) 663 Dispatcher2(Method method, const A& a, const B& b)
413 : method_(method), 664 : method_(method),
414 a_(a), 665 a_(a),
415 b_(b) { 666 b_(b) {
416 } 667 }
417 void operator()(T* object, int32_t result) { 668 void operator()(T* object, int32_t result) {
418 (object->*method_)(result, a_, b_); 669 (object->*method_)(result, a_, b_);
419 } 670 }
420 private: 671 private:
421 Method method_; 672 Method method_;
422 A a_; 673 A a_;
423 B b_; 674 B b_;
424 }; 675 };
425 676
677 template <typename Output, typename Method, typename A, typename B>
678 class DispatcherWithOutput2 {
679 public:
680 typedef Output OutputType;
681 typedef internal::CallbackOutputTraits<Output> Traits;
682
683 DispatcherWithOutput2() : method_(NULL) {}
684 DispatcherWithOutput2(Method method, const A& a, const B& b)
685 : method_(method),
686 a_(a),
687 b_(b) {
688 }
689 void operator()(T* object, int32_t result) {
690 (object->*method_)(result, Traits::StorageToPluginArg(output_), a_, b_);
691 }
692 typename Traits::StorageType* output() {
693 return &output_;
694 }
695 private:
696 Method method_;
697 A a_;
698 B b_;
699
700 typename Traits::StorageType output_;
701 };
702
426 template <typename Method, typename A, typename B, typename C> 703 template <typename Method, typename A, typename B, typename C>
427 class Dispatcher3 { 704 class Dispatcher3 {
428 public: 705 public:
706 Dispatcher3() : method_(NULL) {}
429 Dispatcher3(Method method, const A& a, const B& b, const C& c) 707 Dispatcher3(Method method, const A& a, const B& b, const C& c)
430 : method_(method), 708 : method_(method),
431 a_(a), 709 a_(a),
432 b_(b), 710 b_(b),
433 c_(c) { 711 c_(c) {
434 } 712 }
435 void operator()(T* object, int32_t result) { 713 void operator()(T* object, int32_t result) {
436 (object->*method_)(result, a_, b_, c_); 714 (object->*method_)(result, a_, b_, c_);
437 } 715 }
438 private: 716 private:
439 Method method_; 717 Method method_;
440 A a_; 718 A a_;
441 B b_; 719 B b_;
442 C c_; 720 C c_;
443 }; 721 };
444 722
723 template <typename Output, typename Method, typename A, typename B,
724 typename C>
725 class DispatcherWithOutput3 {
726 public:
727 typedef Output OutputType;
728 typedef internal::CallbackOutputTraits<Output> Traits;
729
730 DispatcherWithOutput3() : method_(NULL) {}
731 DispatcherWithOutput3(Method method, const A& a, const B& b, const C& c)
732 : method_(method),
733 a_(a),
734 b_(b),
735 c_(c) {
736 }
737 void operator()(T* object, int32_t result) {
738 (object->*method_)(result, Traits::StorageToPluginArg(output_),
739 a_, b_, c_);
740 }
741 typename Traits::StorageType* output() {
742 return &output_;
743 }
744 private:
745 Method method_;
746 A a_;
747 B b_;
748 C c_;
749
750 typename Traits::StorageType output_;
751 };
752
445 void InitBackPointer() { 753 void InitBackPointer() {
446 back_pointer_ = new BackPointer(this); 754 back_pointer_ = new BackPointer(this);
447 back_pointer_->AddRef(); 755 back_pointer_->AddRef();
448 } 756 }
449 757
450 void ResetBackPointer() { 758 void ResetBackPointer() {
451 back_pointer_->DropFactory(); 759 back_pointer_->DropFactory();
452 back_pointer_->Release(); 760 back_pointer_->Release();
453 } 761 }
454 762
763 // Takes ownership of the dispatcher pointer, which should be heap allocated.
455 template <typename Dispatcher> 764 template <typename Dispatcher>
456 CompletionCallback NewCallbackHelper(const Dispatcher& dispatcher) { 765 CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) {
457 PP_DCHECK(object_); // Expects a non-null object! 766 PP_DCHECK(object_); // Expects a non-null object!
458 return CompletionCallback( 767 return CompletionCallback(
459 &CallbackData<Dispatcher>::Thunk, 768 &CallbackData<Dispatcher>::Thunk,
460 new CallbackData<Dispatcher>(back_pointer_, dispatcher)); 769 new CallbackData<Dispatcher>(back_pointer_, dispatcher));
461 } 770 }
462 771
772 // Takes ownership of the dispatcher pointer, which should be heap allocated.
773 template <typename Dispatcher> CompletionCallbackWithOutput<
774 typename internal::TypeUnwrapper<
775 typename Dispatcher::OutputType>::StorageType>
776 NewCallbackWithOutputHelper(Dispatcher* dispatcher) {
777 PP_DCHECK(object_); // Expects a non-null object!
778 CallbackData<Dispatcher>* data =
779 new CallbackData<Dispatcher>(back_pointer_, dispatcher);
780
781 return CompletionCallbackWithOutput<typename Dispatcher::OutputType>(
782 &CallbackData<Dispatcher>::Thunk,
783 data,
784 data->dispatcher()->output());
785 }
786
463 // Disallowed: 787 // Disallowed:
464 CompletionCallbackFactory(const CompletionCallbackFactory&); 788 CompletionCallbackFactory(const CompletionCallbackFactory&);
465 CompletionCallbackFactory& operator=(const CompletionCallbackFactory&); 789 CompletionCallbackFactory& operator=(const CompletionCallbackFactory&);
466 790
467 T* object_; 791 T* object_;
468 BackPointer* back_pointer_; 792 BackPointer* back_pointer_;
469 }; 793 };
470 794
471 } // namespace pp 795 } // namespace pp
472 796
473 #endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ 797 #endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
OLDNEW
« no previous file with comments | « ppapi/ppapi_sources.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698