Chromium Code Reviews| Index: ppapi/utility/completion_callback_factory.h |
| diff --git a/ppapi/utility/completion_callback_factory.h b/ppapi/utility/completion_callback_factory.h |
| index b656024097c77ff338cbace98cc2703cd38ee4fe..b03f4c3473a7d97857e516819952d5d35350d351 100644 |
| --- a/ppapi/utility/completion_callback_factory.h |
| +++ b/ppapi/utility/completion_callback_factory.h |
| @@ -10,6 +10,27 @@ |
| namespace pp { |
| +// TypeUnwrapper -------------------------------------------------------------- |
| + |
| +namespace internal { |
| + |
| +// The TypeUnwrapper converts references and const references to the |
| +// underlying type used for storage and passing as an argument. It is for |
| +// internal use only. |
| +template <typename T> struct TypeUnwrapper { |
| + typedef T StorageType; |
| +}; |
| +template <typename T> struct TypeUnwrapper<T&> { |
| + typedef T StorageType; |
| +}; |
| +template <typename T> struct TypeUnwrapper<const T&> { |
| + typedef T StorageType; |
| +}; |
| + |
| +} // namespace internal |
| + |
| +// ---------------------------------------------------------------------------- |
| + |
| /// CompletionCallbackFactory<T> may be used to create CompletionCallback |
| /// objects that are bound to member functions. |
| /// |
| @@ -30,72 +51,140 @@ namespace pp { |
| /// <strong>Example: </strong> |
| /// |
| /// @code |
| -/// |
| -/// class MyHandler { |
| +/// class MyClass { |
| /// public: |
| /// // If an compiler warns on following using |this| in the initializer |
| /// // list, use PP_ALLOW_THIS_IN_INITIALIZER_LIST macro. |
| -/// MyHandler() : factory_(this), offset_(0) { |
| +/// MyClass() : factory_(this) { |
| /// } |
| /// |
| -/// void ProcessFile(const FileRef& file) { |
| -/// CompletionCallback cc = factory_.NewRequiredCallback( |
| -/// &MyHandler::DidOpen); |
| -/// int32_t rv = fio_.Open(file, PP_FileOpenFlag_Read, cc); |
| +/// void OpenFile(const pp::FileRef& file) { |
| +/// pp::CompletionCallback cc = factory_.NewCallback(&MyClass::DidOpen); |
| +/// int32_t rv = file_io_.Open(file, PP_FileOpenFlag_Read, cc); |
| /// CHECK(rv == PP_OK_COMPLETIONPENDING); |
| /// } |
| /// |
| /// private: |
| -/// CompletionCallback NewCallback() { |
| -/// return factory_.NewCallback(&MyHandler::DidCompleteIO); |
| -/// } |
| -/// |
| /// void DidOpen(int32_t result) { |
| /// if (result == PP_OK) { |
| /// // The file is open, and we can begin reading. |
| -/// offset_ = 0; |
| -/// ReadMore(); |
| +/// // ... |
| /// } else { |
| /// // Failed to open the file with error given by 'result'. |
| /// } |
| /// } |
| /// |
| -/// void DidRead(int32_t result) { |
| -/// if (result > 0) { |
| -/// // buf_ now contains 'result' number of bytes from the file. |
| -/// ProcessBytes(buf_, result); |
| -/// offset_ += result; |
| -/// ReadMore(); |
| -/// } else { |
| -/// // Done reading (possibly with an error given by 'result'). |
| -/// } |
| -/// } |
| +/// pp::CompletionCallbackFactory<MyHandler> factory_; |
| +/// }; |
| +/// @endcode |
| /// |
| -/// void ReadMore() { |
| -/// CompletionCallback cc = |
| -/// factory_.NewOptionalCallback(&MyHandler::DidRead); |
| -/// int32_t rv = fio_.Read(offset_, buf_, sizeof(buf_), |
| -/// cc.pp_completion_callback()); |
| -/// if (rv != PP_OK_COMPLETIONPENDING) |
| -/// cc.Run(rv); |
| -/// } |
| +/// <strong>Passing additional parameters to your callback</strong> |
| /// |
| -/// void ProcessBytes(const char* bytes, int32_t length) { |
| -/// // Do work ... |
| -/// } |
| +/// As a convenience, the <code>CompletionCallbackFactory</code> can optionally |
| +/// create a closure with up to three bound parameters that it will pass to |
| +/// your callback function. This can be useful for passing information about |
| +/// the request to your callback function, which is especially useful if your |
| +/// class has multiple asynchronous callbacks pending. |
| /// |
| -/// pp::CompletionCallbackFactory<MyHandler> factory_; |
| -/// pp::FileIO fio_; |
| -/// char buf_[4096]; |
| -/// int64_t offset_; |
| -/// }; |
| +/// For the above example, of opening a file, let's say you want to keep some |
| +/// description associated with your request, you might implement your OpenFile |
| +/// and DidOpen callback as follows: |
| /// |
| +/// @code |
| +/// void OpenFile(const pp::FileRef& file) { |
| +/// std::string message = "Opening file!"; |
| +/// pp::CompletionCallback cc = factory_.NewCallback(&MyClass::DidOpen, |
| +/// message); |
| +/// int32_t rv = file_io_.Open(file, PP_FileOpenFlag_Read, cc); |
| +/// CHECK(rv == PP_OK_COMPLETIONPENDING); |
| +/// } |
| +/// void DidOpen(int32_t result, const std::string& message) { |
| +/// // "message" will be "Opening file!". |
| +/// ... |
| +/// } |
| /// @endcode |
| /// |
| +/// <strong>Optional versus required callbacks</strong> |
| +/// |
| +/// When you create an "optional" callback, the browser may return the results |
| +/// synchronously if they are available. This can allow for higher performance |
| +/// in some cases if data is available quickly (for example, for network loads |
| +/// where there may be a lot of data coming quickly). In this case, the |
| +/// callback will never be run. |
| +/// |
| +/// When creating a new callback with the factory, there will be data allocated |
| +/// on the heap that tracks the callback information and any bound arguments. |
| +/// This data is freed when the callback executes. In the case of optional |
| +/// callbacks, since the browser will never issue the callback, the internal |
| +/// tracking data will be leaked. |
| +/// |
| +/// Therefore, if you use optional callbacks, it's important to manually |
| +/// issue the callback to free up this data. The typical pattern is: |
| +/// |
| +/// @code |
| +/// pp::CompletionCallback callback = callback_factory.NewOptionalCallback( |
| +/// &MyClass::OnDataReady); |
| +/// int32_t result = interface->GetData(callback); |
| +/// if (result != PP_OK_COMPLETIONPENDING) |
| +/// callback.Run(result); |
| +/// @endcode |
| +/// |
| +/// Because of this additional complexity, it's generally recommended that |
| +/// you not use optional callbacks except when performance is more important |
| +/// (such as loading large resources from the network). In most other cases, |
| +/// the performance difference will not be worth the additional complexity, |
| +/// and most functions may never actually have the ability to complete |
| +/// synchronously. |
| +/// |
| +/// <strong>Completion callbacks with output</strong> |
| +/// |
| +/// For some API calls, the browser returns data to the caller via an output |
| +/// parameter. These can be difficult to manage since the output parameter |
| +/// must remain valid for as long as the callback is pending. Note also that |
| +/// CancelAll (or destroying the callback factory) does <i>not</i> cancel the |
| +/// callback from the browser's perspective, only the execution of the callback |
| +/// in the plugin code, and the output parameter will still be written to! |
| +/// This means that you can't use class members as output parameters without |
| +/// risking crashes. |
| +/// |
| +/// To make this case easier, the CompletionCallbackFactory can allocate and |
| +/// manage the output data for you and pass it to your callback function. This |
| +/// makes such calls more natural and less error-prone. |
| +/// |
| +/// To create such a callback, use NewCallbackWithOutput and specify a callback |
| +/// function that takes the output parameter as its second argument. Let's say |
| +/// you're calling a function GetFile which asynchronously returns a |
| +/// pp::FileRef. GetFile's signature will be <code>int32_t GetFile(const |
| +/// CompletionCallbackWithOutput<pp::FileRef>& callback);</code> and your |
| +/// calling code would look like this: |
| +/// |
| +/// @code |
| +/// void RequestFile() { |
| +/// file_interface->GetFile(callback_factory_.NewCallbackWithOutput( |
| +/// &MyClass::GotFile)); |
| +/// } |
| +/// void GotFile(int32_t result, const pp::FileRef& file) { |
| +/// if (result == PP_OK) { |
| +/// ...use file... |
| +/// } else { |
| +/// ...handle error... |
| +/// } |
| +/// } |
| +/// @endcode |
| +/// |
| +/// As with regular completion callbacks, you can optionally add up to three |
| +/// bound arguments. These are passed following the output argument. |
| +/// |
| +/// Your callback may take the output argument as a copy (common for small |
| +/// types like integers, a const reference (common for structures and |
| +/// resources to avoid an extra copy), or as a non-const reference. One |
| +/// optimization you can do if your callback function may take large arrays |
| +/// is to accept your output argument as a non-const reference and to swap() |
| +/// the argument with a vector of your own to store it. This means you don't |
| +/// have to copy the buffer to consume it. |
| template <typename T, typename RefCount = NonThreadSafeRefCount> |
| class CompletionCallbackFactory { |
| public: |
| - |
| /// This constructor creates a <code>CompletionCallbackFactory</code> |
| /// bound to an object. If the constructor is called without an argument, |
| /// the default value of <code>NULL</code> is used. The user then must call |
| @@ -147,7 +236,7 @@ class CompletionCallbackFactory { |
| /// NewCallback allocates a new, single-use <code>CompletionCallback</code>. |
| /// The <code>CompletionCallback</code> must be run in order for the memory |
| /// allocated by the methods to be freed. |
| - /// NewCallback() is equivalent to NewRequiredCallback() below. |
| + /// NewCallback() is equivalent to NewCallback() below. |
| /// |
| /// @param[in] method The method to be invoked upon completion of the |
| /// operation. |
| @@ -156,23 +245,8 @@ class CompletionCallbackFactory { |
| template <typename Method> |
| CompletionCallback NewCallback(Method method) { |
| PP_DCHECK(object_); |
| - return NewCallbackHelper(Dispatcher0<Method>(method)); |
| - } |
| - |
| - /// NewRequiredCallback() allocates a new, single-use |
| - /// <code>CompletionCallback</code> that will always run. The |
| - /// <code>CompletionCallback</code> must be run in order for the memory |
| - /// allocated by the methods to be freed. |
| - /// |
| - /// @param[in] method The method to be invoked upon completion of the |
| - /// operation. |
| - /// |
| - /// @return A <code>CompletionCallback</code>. |
| - template <typename Method> |
| - CompletionCallback NewRequiredCallback(Method method) { |
| - CompletionCallback cc = NewCallback(method); |
| - cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); |
| - return cc; |
| + Dispatcher0<Method> disp(method); |
| + return NewCallbackHelper(disp); |
| } |
| /// NewOptionalCallback() allocates a new, single-use |
| @@ -193,28 +267,27 @@ class CompletionCallbackFactory { |
| return cc; |
| } |
| - /// NewCallback() allocates a new, single-use <code>CompletionCallback</code>. |
| - /// The <code>CompletionCallback</code> must be run in order for the memory |
| + /// NewCallbackWithOutput() allocates a new, single-use |
| + /// <code>CompletionCallback</code> where the browser will pass an additional |
| + /// parameter comtaining the result of the request. The |
| + /// <code>CompletionCallback</code> must be run in order for the memory |
| /// allocated by the methods to be freed. |
| - /// NewCallback() is equivalent to NewRequiredCallback() below. |
| /// |
| /// @param[in] method The method to be invoked upon completion of the |
| - /// operation. Method should be of type: |
| - /// <code>void (T::*)(int32_t result, const A& a)</code> |
| - /// |
| - /// @param[in] a Passed to <code>method</code> when the completion callback |
| - /// runs. |
| + /// operation. |
| /// |
| /// @return A <code>CompletionCallback</code>. |
| - template <typename Method, typename A> |
| - CompletionCallback NewCallback(Method method, const A& a) { |
| - PP_DCHECK(object_); |
| - return NewCallbackHelper(Dispatcher1<Method, A>(method, a)); |
| + template <typename Output> |
| + CompletionCallbackWithOutput< |
| + typename internal::TypeUnwrapper<Output>::StorageType> |
| + NewCallbackWithOutput(void (T::*method)(int32_t, Output)) { |
| + return NewCallbackWithOutputHelper(DispatcherWithOutput0< |
| + typename internal::TypeUnwrapper<Output>::StorageType, |
| + void (T::*)(int32_t, Output)>(method)); |
| } |
| - /// NewRequiredCallback() allocates a new, single-use |
| - /// <code>CompletionCallback</code> that will always run. The |
| - /// <code>CompletionCallback</code> must be run in order for the memory |
| + /// NewCallback() allocates a new, single-use <code>CompletionCallback</code>. |
| + /// The <code>CompletionCallback</code> must be run in order for the memory |
| /// allocated by the methods to be freed. |
| /// |
| /// @param[in] method The method to be invoked upon completion of the |
| @@ -226,13 +299,12 @@ class CompletionCallbackFactory { |
| /// |
| /// @return A <code>CompletionCallback</code>. |
| template <typename Method, typename A> |
| - CompletionCallback NewRequiredCallback(Method method, const A& a) { |
| - CompletionCallback cc = NewCallback(method, a); |
| - cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); |
| - return cc; |
| + CompletionCallback NewCallback(Method method, const A& a) { |
| + PP_DCHECK(object_); |
| + Dispatcher1<Method, A> disp(method, a); |
| + return NewCallbackHelper(disp); |
| } |
| - /// NewOptionalCallback() allocates a new, single-use |
| /// <code>CompletionCallback</code> that might not run if the method |
| /// taking it can complete synchronously. Thus, if after passing the |
| /// CompletionCallback to a Pepper method, the method does not return |
| @@ -254,31 +326,33 @@ class CompletionCallbackFactory { |
| return cc; |
| } |
| - /// NewCallback() allocates a new, single-use |
| - /// <code>CompletionCallback</code>. |
| - /// The <code>CompletionCallback</code> must be run in order for the memory |
| + /// NewCallbackWithOutput() allocates a new, single-use |
| + /// <code>CompletionCallback</code> where the browser will pass an additional |
| + /// parameter comtaining the result of the request. The |
| + /// <code>CompletionCallback</code> must be run in order for the memory |
| /// allocated by the methods to be freed. |
| - /// NewCallback() is equivalent to NewRequiredCallback() below. |
| /// |
| - /// @param method The method taking the callback. Method should be of type: |
| - /// <code>void (T::*)(int32_t result, const A& a, const B& b)</code> |
| + /// @param[in] method The method to be invoked upon completion of the |
| + /// operation. |
| /// |
| /// @param[in] a Passed to <code>method</code> when the completion callback |
| /// runs. |
| /// |
| - /// @param[in] b Passed to <code>method</code> when the completion callback |
| - /// runs. |
| - /// |
| /// @return A <code>CompletionCallback</code>. |
| - template <typename Method, typename A, typename B> |
| - CompletionCallback NewCallback(Method method, const A& a, const B& b) { |
| - PP_DCHECK(object_); |
| - return NewCallbackHelper(Dispatcher2<Method, A, B>(method, a, b)); |
| + template <typename Output, typename A> |
| + CompletionCallbackWithOutput< |
| + typename internal::TypeUnwrapper<Output>::StorageType> |
| + NewCallbackWithOutput(void (T::*method)(int32_t, Output, A), |
| + const A& a) { |
| + return NewCallbackWithOutputHelper(DispatcherWithOutput1< |
| + typename internal::TypeUnwrapper<Output>::StorageType, |
| + void (T::*)(int32_t, Output, A), |
| + typename internal::TypeUnwrapper<A>::StorageType>(method, a)); |
| } |
| - /// NewRequiredCallback() allocates a new, single-use |
| - /// <code>CompletionCallback</code> that will always run. The |
| - /// <code>CompletionCallback</code> must be run in order for the memory |
| + /// NewCallback() allocates a new, single-use |
| + /// <code>CompletionCallback</code>. |
| + /// The <code>CompletionCallback</code> must be run in order for the memory |
| /// allocated by the methods to be freed. |
| /// |
| /// @param method The method taking the callback. Method should be of type: |
| @@ -292,11 +366,10 @@ class CompletionCallbackFactory { |
| /// |
| /// @return A <code>CompletionCallback</code>. |
| template <typename Method, typename A, typename B> |
| - CompletionCallback NewRequiredCallback(Method method, const A& a, |
| - const B& b) { |
| - CompletionCallback cc = NewCallback(method, a, b); |
| - cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); |
| - return cc; |
| + CompletionCallback NewCallback(Method method, const A& a, const B& b) { |
| + PP_DCHECK(object_); |
| + Dispatcher2<Method, A, B> disp(method, a, b); |
| + return NewCallbackHelper(disp); |
| } |
| /// NewOptionalCallback() allocates a new, single-use |
| @@ -325,16 +398,13 @@ class CompletionCallbackFactory { |
| return cc; |
| } |
| - /// NewCallback() allocates a new, single-use |
| - /// <code>CompletionCallback</code>. |
| - /// The <code>CompletionCallback</code> must be run in order for the memory |
| + /// NewCallbackWithOutput() allocates a new, single-use |
| + /// <code>CompletionCallback</code> where the browser will pass an additional |
| + /// parameter comtaining the result of the request. The |
| + /// <code>CompletionCallback</code> must be run in order for the memory |
| /// allocated by the methods to be freed. |
| - /// NewCallback() is equivalent to NewRequiredCallback() below. |
| /// |
| - /// @param method The method taking the callback. Method should be of type: |
| - /// <code> |
| - /// void (T::*)(int32_t result, const A& a, const B& b, const C& c) |
| - /// </code> |
| + /// @param[in] method The method to be run. |
| /// |
| /// @param[in] a Passed to <code>method</code> when the completion callback |
| /// runs. |
| @@ -342,20 +412,23 @@ class CompletionCallbackFactory { |
| /// @param[in] b Passed to <code>method</code> when the completion callback |
| /// runs. |
| /// |
| - /// @param[in] c Passed to <code>method</code> when the completion callback |
| - /// runs. |
| - /// |
| /// @return A <code>CompletionCallback</code>. |
| - template <typename Method, typename A, typename B, typename C> |
| - CompletionCallback NewCallback(Method method, const A& a, const B& b, |
| - const C& c) { |
| - PP_DCHECK(object_); |
| - return NewCallbackHelper(Dispatcher3<Method, A, B, C>(method, a, b, c)); |
| + template <typename Output, typename A, typename B> |
| + CompletionCallbackWithOutput< |
| + typename internal::TypeUnwrapper<Output>::StorageType> |
| + NewCallbackWithOutput(void (T::*method)(int32_t, Output, A, B), |
| + const A& a, |
| + const B& b) { |
| + return NewCallbackWithOutputHelper(DispatcherWithOutput2< |
| + typename internal::TypeUnwrapper<Output>::StorageType, |
| + void (T::*)(int32_t, Output, A, B), |
| + typename internal::TypeUnwrapper<A>::StorageType, |
| + typename internal::TypeUnwrapper<B>::StorageType>(method, a, b)); |
| } |
| - /// NewRequiredCallback() allocates a new, single-use |
| - /// <code>CompletionCallback</code> that will always run. The |
| - /// <code>CompletionCallback</code> must be run in order for the memory |
| + /// NewCallback() allocates a new, single-use |
| + /// <code>CompletionCallback</code>. |
| + /// The <code>CompletionCallback</code> must be run in order for the memory |
| /// allocated by the methods to be freed. |
| /// |
| /// @param method The method taking the callback. Method should be of type: |
| @@ -374,11 +447,11 @@ class CompletionCallbackFactory { |
| /// |
| /// @return A <code>CompletionCallback</code>. |
| template <typename Method, typename A, typename B, typename C> |
| - CompletionCallback NewRequiredCallback(Method method, const A& a, |
| - const B& b, const C& c) { |
| - CompletionCallback cc = NewCallback(method, a, b, c); |
| - cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); |
| - return cc; |
| + CompletionCallback NewCallback(Method method, const A& a, const B& b, |
| + const C& c) { |
| + PP_DCHECK(object_); |
| + Dispatcher3<Method, A, B, C> disp(method, a, b, c); |
| + return NewCallbackHelper(disp); |
| } |
| /// NewOptionalCallback() allocates a new, single-use |
| @@ -412,6 +485,39 @@ class CompletionCallbackFactory { |
| return cc; |
| } |
| + /// NewCallbackWithOutput() allocates a new, single-use |
| + /// <code>CompletionCallback</code> where the browser will pass an additional |
| + /// parameter comtaining the result of the request. The |
| + /// <code>CompletionCallback</code> must be run in order for the memory |
| + /// allocated by the methods to be freed. |
| + /// |
| + /// @param method The method to be run. |
| + /// |
| + /// @param[in] a Passed to <code>method</code> when the completion callback |
| + /// runs. |
| + /// |
| + /// @param[in] b Passed to <code>method</code> when the completion callback |
| + /// runs. |
| + /// |
| + /// @param[in] c Passed to <code>method</code> when the completion callback |
| + /// runs. |
| + /// |
| + /// @return A <code>CompletionCallback</code>. |
| + template <typename Output, typename A, typename B, typename C> |
| + CompletionCallbackWithOutput< |
| + typename internal::TypeUnwrapper<Output>::StorageType> |
| + NewCallbackWithOutput(void (T::*method)(int32_t, Output, A, B, C), |
| + const A& a, |
| + const B& b, |
| + const C& c) { |
| + return NewCallbackWithOutputHelper(DispatcherWithOutput3< |
| + typename internal::TypeUnwrapper<Output>::StorageType, |
| + void (T::*)(int32_t, Output, A, B, C), |
| + typename internal::TypeUnwrapper<A>::StorageType, |
| + typename internal::TypeUnwrapper<B>::StorageType, |
| + typename internal::TypeUnwrapper<C>::StorageType>(method, a, b, c)); |
| + } |
| + |
| private: |
| class BackPointer { |
| public: |
| @@ -446,16 +552,19 @@ class CompletionCallbackFactory { |
| template <typename Dispatcher> |
| class CallbackData { |
| public: |
| - CallbackData(BackPointer* back_pointer, const Dispatcher& dispatcher) |
| - : back_pointer_(back_pointer), |
| - dispatcher_(dispatcher) { |
| + // Swaps the given dispatcher with the class member to avoid a copy. |
| + CallbackData(BackPointer* back_pointer, Dispatcher& dispatcher) |
| + : back_pointer_(back_pointer) { |
| back_pointer_->AddRef(); |
| + dispatcher_.swap(dispatcher); |
| } |
| ~CallbackData() { |
| back_pointer_->Release(); |
| } |
| + Dispatcher& dispatcher() { return dispatcher_; } |
| + |
| static void Thunk(void* user_data, int32_t result) { |
| Self* self = static_cast<Self*>(user_data); |
| T* object = self->back_pointer_->GetObject(); |
| @@ -473,18 +582,48 @@ class CompletionCallbackFactory { |
| template <typename Method> |
| class Dispatcher0 { |
| public: |
| + Dispatcher0() : method_(NULL) {} |
| Dispatcher0(Method method) : method_(method) { |
|
dmichael (off chromium)
2012/03/13 05:04:04
nit: explicit
|
| } |
| void operator()(T* object, int32_t result) { |
| (object->*method_)(result); |
| } |
| + void swap(Dispatcher0<Method>& other) { |
| + std::swap(method_, other.method_); |
| + } |
| + private: |
| + Method method_; |
| + }; |
| + |
| + template <typename Output, typename Method> |
| + class DispatcherWithOutput0 { |
| + public: |
| + typedef Output OutputType; |
| + typedef internal::CallbackOutputTraits<Output> Traits; |
| + |
| + DispatcherWithOutput0() : method_(NULL) {} |
| + DispatcherWithOutput0(Method method) : method_(method) { |
|
dmichael (off chromium)
2012/03/13 05:04:04
nit: explicit
|
| + } |
| + void operator()(T* object, int32_t result) { |
| + (object->*method_)(result, Traits::StorageToPluginArg(output_)); |
| + } |
| + typename Traits::StorageType* output() { |
| + return &output_; |
| + } |
| + void swap(DispatcherWithOutput0<Output, Method>& other) { |
| + std::swap(method_, other.method_); |
| + std::swap(output_, other.output_); |
| + } |
| private: |
| Method method_; |
| + |
| + typename Traits::StorageType output_; |
| }; |
| template <typename Method, typename A> |
| class Dispatcher1 { |
| public: |
| + Dispatcher1() : method_(NULL) {} |
| Dispatcher1(Method method, const A& a) |
| : method_(method), |
| a_(a) { |
| @@ -492,14 +631,48 @@ class CompletionCallbackFactory { |
| void operator()(T* object, int32_t result) { |
| (object->*method_)(result, a_); |
| } |
| + void swap(Dispatcher1<Method, A>& other) { |
| + std::swap(method_, other.method_); |
| + std::swap(a_, other.a_); |
| + } |
| + private: |
| + Method method_; |
| + A a_; |
| + }; |
| + |
| + template <typename Output, typename Method, typename A> |
| + class DispatcherWithOutput1 { |
| + public: |
| + typedef Output OutputType; |
| + typedef internal::CallbackOutputTraits<Output> Traits; |
| + |
| + DispatcherWithOutput1() : method_(NULL) {} |
| + DispatcherWithOutput1(Method method, const A& a) |
| + : method_(method), |
| + a_(a) { |
| + } |
| + void operator()(T* object, int32_t result) { |
| + (object->*method_)(result, Traits::StorageToPluginArg(output_), a_); |
| + } |
| + typename Traits::StorageType* output() { |
| + return &output_; |
| + } |
| + void swap(DispatcherWithOutput1<Output, Method, A>& other) { |
| + std::swap(method_, other.method_); |
| + std::swap(output_, other.output_); |
| + std::swap(a_, other.a_); |
| + } |
| private: |
| Method method_; |
| A a_; |
| + |
| + typename Traits::StorageType output_; |
| }; |
| template <typename Method, typename A, typename B> |
| class Dispatcher2 { |
| public: |
| + Dispatcher2() : method_(NULL) {} |
| Dispatcher2(Method method, const A& a, const B& b) |
| : method_(method), |
| a_(a), |
| @@ -508,15 +681,53 @@ class CompletionCallbackFactory { |
| void operator()(T* object, int32_t result) { |
| (object->*method_)(result, a_, b_); |
| } |
| + void swap(Dispatcher2<Method, A, B>& other) { |
| + std::swap(method_, other.method_); |
| + std::swap(a_, other.a_); |
| + std::swap(b_, other.b_); |
| + } |
| + private: |
| + Method method_; |
| + A a_; |
| + B b_; |
| + }; |
| + |
| + template <typename Output, typename Method, typename A, typename B> |
| + class DispatcherWithOutput2 { |
| + public: |
| + typedef Output OutputType; |
| + typedef internal::CallbackOutputTraits<Output> Traits; |
| + |
| + DispatcherWithOutput2() : method_(NULL) {} |
| + DispatcherWithOutput2(Method method, const A& a, const B& b) |
| + : method_(method), |
| + a_(a), |
| + b_(b) { |
| + } |
| + void operator()(T* object, int32_t result) { |
| + (object->*method_)(result, Traits::StorageToPluginArg(output_), a_, b_); |
| + } |
| + typename Traits::StorageType* output() { |
| + return &output_; |
| + } |
| + void swap(DispatcherWithOutput2<Output, Method, A, B>& other) { |
| + std::swap(method_, other.method_); |
| + std::swap(output_, other.output_); |
| + std::swap(a_, other.a_); |
| + std::swap(b_, other.b_); |
| + } |
| private: |
| Method method_; |
| A a_; |
| B b_; |
| + |
| + typename Traits::StorageType output_; |
| }; |
| template <typename Method, typename A, typename B, typename C> |
| class Dispatcher3 { |
| public: |
| + Dispatcher3() : method_(NULL) {} |
| Dispatcher3(Method method, const A& a, const B& b, const C& c) |
| : method_(method), |
| a_(a), |
| @@ -526,11 +737,54 @@ class CompletionCallbackFactory { |
| void operator()(T* object, int32_t result) { |
| (object->*method_)(result, a_, b_, c_); |
| } |
| + void swap(Dispatcher3<Method, A, B, C>& other) { |
| + std::swap(method_, other.method_); |
| + std::swap(a_, other.a_); |
| + std::swap(b_, other.b_); |
| + std::swap(c_, other.c_); |
| + } |
| + private: |
| + Method method_; |
| + A a_; |
| + B b_; |
| + C c_; |
| + }; |
| + |
| + template <typename Output, typename Method, typename A, typename B, |
| + typename C> |
| + class DispatcherWithOutput3 { |
| + public: |
| + typedef Output OutputType; |
| + typedef internal::CallbackOutputTraits<Output> Traits; |
| + |
| + DispatcherWithOutput3() : method_(NULL) {} |
| + DispatcherWithOutput3(Method method, const A& a, const B& b, const C& c) |
| + : method_(method), |
| + a_(a), |
| + b_(b), |
| + c_(c) { |
| + } |
| + void operator()(T* object, int32_t result) { |
| + (object->*method_)(result, Traits::StorageToPluginArg(output_), |
| + a_, b_, c_); |
| + } |
| + typename Traits::StorageType* output() { |
| + return &output_; |
| + } |
| + void swap(DispatcherWithOutput3<Output, Method, A, B, C>& other) { |
| + std::swap(method_, other.method_); |
| + std::swap(output_, other.output_); |
| + std::swap(a_, other.a_); |
| + std::swap(b_, other.b_); |
| + std::swap(c_, other.c_); |
| + } |
| private: |
| Method method_; |
| A a_; |
| B b_; |
| C c_; |
| + |
| + typename Traits::StorageType output_; |
| }; |
| void InitBackPointer() { |
| @@ -544,13 +798,27 @@ class CompletionCallbackFactory { |
| } |
| template <typename Dispatcher> |
| - CompletionCallback NewCallbackHelper(const Dispatcher& dispatcher) { |
| + CompletionCallback NewCallbackHelper(Dispatcher& dispatcher) { |
| PP_DCHECK(object_); // Expects a non-null object! |
| return CompletionCallback( |
| &CallbackData<Dispatcher>::Thunk, |
| new CallbackData<Dispatcher>(back_pointer_, dispatcher)); |
| } |
| + template <typename Dispatcher> CompletionCallbackWithOutput< |
| + typename internal::TypeUnwrapper< |
| + typename Dispatcher::OutputType>::StorageType> |
| + NewCallbackWithOutputHelper(Dispatcher& dispatcher) { |
| + PP_DCHECK(object_); // Expects a non-null object! |
| + CallbackData<Dispatcher>* data = |
| + new CallbackData<Dispatcher>(back_pointer_, dispatcher); |
| + |
| + return CompletionCallbackWithOutput<typename Dispatcher::OutputType>( |
| + &CallbackData<Dispatcher>::Thunk, |
| + data, |
| + data->dispatcher().output()); |
| + } |
| + |
| // Disallowed: |
| CompletionCallbackFactory(const CompletionCallbackFactory&); |
| CompletionCallbackFactory& operator=(const CompletionCallbackFactory&); |