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

Unified 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: With swapping 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 side-by-side diff with in-line comments
Download patch
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&);

Powered by Google App Engine
This is Rietveld 408576698