blob: 973aae1e3548e2e47cc8cca273ff1c34d8e5b1e1 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
#define PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
#include <stdint.h>
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/utility/completion_callback_factory_thread_traits.h"
/// @file
/// This file defines the API to create CompletionCallback objects that are
/// bound to member functions.
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.
///
/// If a factory is destroyed, then any pending callbacks will be cancelled
/// preventing any bound member functions from being called. The CancelAll()
/// method allows pending callbacks to be cancelled without destroying the
/// factory.
///
/// <strong>Note: </strong><code>CompletionCallbackFactory<T></code> isn't
/// thread safe, but it is somewhat thread-friendly when used with a
/// thread-safe traits class as the second template element. However, it
/// only guarantees safety for creating a callback from another thread, the
/// callback itself needs to execute on the same thread as the thread that
/// creates/destroys the factory. With this restriction, it is safe to create
/// the <code>CompletionCallbackFactory</code> on the main thread, create
/// callbacks from any thread and pass them to CallOnMainThread().
///
/// <strong>Example: </strong>
///
/// @code
/// class MyClass {
/// public:
/// // If an compiler warns on following using |this| in the initializer
/// // list, use PP_ALLOW_THIS_IN_INITIALIZER_LIST macro.
/// MyClass() : factory_(this) {
/// }
///
/// 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:
/// void DidOpen(int32_t result) {
/// if (result == PP_OK) {
/// // The file is open, and we can begin reading.
/// // ...
/// } else {
/// // Failed to open the file with error given by 'result'.
/// }
/// }
///
/// pp::CompletionCallbackFactory<MyClass> factory_;
/// };
/// @endcode
///
/// <strong>Passing additional parameters to your callback</strong>
///
/// 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.
///
/// 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 ThreadTraits = ThreadSafeThreadTraits>
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
/// Initialize() to initialize the object.
///
/// param[in] object Optional parameter. An object whose member functions
/// are to be bound to CompletionCallbacks created by this
/// <code>CompletionCallbackFactory</code>. The default value of this
/// parameter is <code>NULL</code>.
explicit CompletionCallbackFactory(T* object = NULL)
: object_(object) {
// Assume that we don't need to lock since construction should be complete
// before the pointer is used on another thread.
InitBackPointer();
}
/// Destructor.
~CompletionCallbackFactory() {
// Assume that we don't need to lock since this object should not be used
// from multiple threads during destruction.
ResetBackPointer();
}
/// CancelAll() cancels all <code>CompletionCallbacks</code> allocated from
/// this factory.
void CancelAll() {
typename ThreadTraits::AutoLock lock(lock_);
ResetBackPointer();
InitBackPointer();
}
/// Initialize() binds the <code>CallbackFactory</code> to a particular
/// object. Use this when the object is not available at
/// <code>CallbackFactory</code> creation, and the <code>NULL</code> default
/// is passed to the constructor. The object may only be initialized once,
/// either by the constructor, or by a call to Initialize().
///
/// This class may not be used on any thread until initialization is complete.
///
/// @param[in] object The object whose member functions are to be bound to
/// the <code>CompletionCallback</code> created by this
/// <code>CompletionCallbackFactory</code>.
void Initialize(T* object) {
PP_DCHECK(object);
PP_DCHECK(!object_); // May only initialize once!
object_ = object;
}
/// GetObject() returns the object that was passed at initialization to
/// Intialize().
///
/// @return the object passed to the constructor or Intialize().
T* GetObject() {
return object_;
}
/// 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
/// operation.
///
/// @return A <code>CompletionCallback</code>.
template <typename Method>
CompletionCallback NewCallback(Method method) {
return NewCallbackHelper(new Dispatcher0<Method>(method));
}
/// 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
/// PP_OK_COMPLETIONPENDING, then you should manually call the
/// CompletionCallback's Run method, or memory will be leaked.
///
/// @param[in] method The method to be invoked upon completion of the
/// operation.
///
/// @return A <code>CompletionCallback</code>.
template <typename Method>
CompletionCallback NewOptionalCallback(Method method) {
CompletionCallback cc = NewCallback(method);
cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
return cc;
}
/// NewCallbackWithOutput() allocates a new, single-use
/// <code>CompletionCallback</code> where the browser will pass an additional
/// parameter containing 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[in] method The method to be invoked upon completion of the
/// operation.
///
/// @return A <code>CompletionCallback</code>.
template <typename Output>
CompletionCallbackWithOutput<
typename internal::TypeUnwrapper<Output>::StorageType>
NewCallbackWithOutput(void (T::*method)(int32_t, Output)) {
return NewCallbackWithOutputHelper(new DispatcherWithOutput0<
typename internal::TypeUnwrapper<Output>::StorageType,
void (T::*)(int32_t, Output)>(method));
}
/// 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
/// 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.
///
/// @return A <code>CompletionCallback</code>.
template <typename Method, typename A>
CompletionCallback NewCallback(Method method, const A& a) {
return NewCallbackHelper(new Dispatcher1<Method, A>(method, a));
}
/// 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
/// PP_OK_COMPLETIONPENDING, then you should manually call the
/// CompletionCallback's Run method, or memory will be leaked.
///
/// @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.
///
/// @return A <code>CompletionCallback</code>.
template <typename Method, typename A>
CompletionCallback NewOptionalCallback(Method method, const A& a) {
CompletionCallback cc = NewCallback(method, a);
cc.set_flags(cc.flags() | PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
return cc;
}
/// NewCallbackWithOutput() allocates a new, single-use
/// <code>CompletionCallback</code> where the browser will pass an additional
/// parameter containing 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[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.
///
/// @return A <code>CompletionCallback</code>.
template <typename Output, typename A>
CompletionCallbackWithOutput<
typename internal::TypeUnwrapper<Output>::StorageType>
NewCallbackWithOutput(void (T::*method)(int32_t, Output, A),
const A& a) {
return NewCallbackWithOutputHelper(new DispatcherWithOutput1<
typename internal::TypeUnwrapper<Output>::StorageType,
void (T::*)(int32_t, Output, A),
typename internal::TypeUnwrapper<A>::StorageType>(method, a));
}
/// 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:
/// <code>void (T::*)(int32_t result, const A& a, const B& b)</code>
///
/// @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) {
return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b));
}
/// 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
/// PP_OK_COMPLETIONPENDING, then you should manually call the
/// CompletionCallback's Run method, or memory will be leaked.
///
/// @param[in] 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] 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 NewOptionalCallback(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;
}
/// NewCallbackWithOutput() allocates a new, single-use
/// <code>CompletionCallback</code> where the browser will pass an additional
/// parameter containing 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[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 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(new 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));
}
/// 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:
/// <code>
/// void (T::*)(int32_t result, const A& a, const B& b, const C& c)
/// </code>
///
/// @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 Method, typename A, typename B, typename C>
CompletionCallback NewCallback(Method method, const A& a, const B& b,
const C& c) {
return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c));
}
/// 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
/// PP_OK_COMPLETIONPENDING, then you should manually call the
/// CompletionCallback's Run method, or memory will be leaked.
///
/// @param[in] 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] 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 Method, typename A, typename B, typename C>
CompletionCallback NewOptionalCallback(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;
}
/// NewCallbackWithOutput() allocates a new, single-use
/// <code>CompletionCallback</code> where the browser will pass an additional
/// parameter containing 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(new 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:
typedef CompletionCallbackFactory<T, ThreadTraits> FactoryType;
explicit BackPointer(FactoryType* factory)
: factory_(factory) {
}
void AddRef() {
ref_.AddRef();
}
void Release() {
if (ref_.Release() == 0)
delete this;
}
void DropFactory() {
factory_ = NULL;
}
T* GetObject() {
return factory_ ? factory_->GetObject() : NULL;
}
private:
typename ThreadTraits::RefCount ref_;
FactoryType* factory_;
};
template <typename Dispatcher>
class CallbackData {
public:
// Takes ownership of the given dispatcher pointer.
CallbackData(BackPointer* back_pointer, Dispatcher* dispatcher)
: back_pointer_(back_pointer),
dispatcher_(dispatcher) {
back_pointer_->AddRef();
}
~CallbackData() {
back_pointer_->Release();
delete dispatcher_;
}
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();
// Please note that |object| may be NULL at this point. But we still need
// to call into Dispatcher::operator() in that case, so that it can do
// necessary cleanup.
(*self->dispatcher_)(object, result);
delete self;
}
private:
typedef CallbackData<Dispatcher> Self;
BackPointer* back_pointer_; // We own a ref to this refcounted object.
Dispatcher* dispatcher_; // We own this pointer.
// Disallow copying & assignment.
CallbackData(const CallbackData<Dispatcher>&);
CallbackData<Dispatcher>& operator=(const CallbackData<Dispatcher>&);
};
template <typename Method>
class Dispatcher0 {
public:
Dispatcher0() : method_(NULL) {}
explicit Dispatcher0(Method method) : method_(method) {
}
void operator()(T* object, int32_t result) {
if (object)
(object->*method_)(result);
}
private:
Method method_;
};
template <typename Output, typename Method>
class DispatcherWithOutput0 {
public:
typedef Output OutputType;
typedef internal::CallbackOutputTraits<Output> Traits;
DispatcherWithOutput0()
: method_(NULL),
output_() {
Traits::Initialize(&output_);
}
DispatcherWithOutput0(Method method)
: method_(method),
output_() {
Traits::Initialize(&output_);
}
void operator()(T* object, int32_t result) {
// We must call Traits::StorageToPluginArg() even if we don't need to call
// the callback anymore, otherwise we may leak resource or var references.
if (object)
(object->*method_)(result, Traits::StorageToPluginArg(output_));
else
Traits::StorageToPluginArg(output_);
}
typename Traits::StorageType* output() {
return &output_;
}
private:
Method method_;
typename Traits::StorageType output_;
};
template <typename Method, typename A>
class Dispatcher1 {
public:
Dispatcher1()
: method_(NULL),
a_() {
}
Dispatcher1(Method method, const A& a)
: method_(method),
a_(a) {
}
void operator()(T* object, int32_t result) {
if (object)
(object->*method_)(result, 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),
a_(),
output_() {
Traits::Initialize(&output_);
}
DispatcherWithOutput1(Method method, const A& a)
: method_(method),
a_(a),
output_() {
Traits::Initialize(&output_);
}
void operator()(T* object, int32_t result) {
// We must call Traits::StorageToPluginArg() even if we don't need to call
// the callback anymore, otherwise we may leak resource or var references.
if (object)
(object->*method_)(result, Traits::StorageToPluginArg(output_), a_);
else
Traits::StorageToPluginArg(output_);
}
typename Traits::StorageType* output() {
return &output_;
}
private:
Method method_;
A a_;
typename Traits::StorageType output_;
};
template <typename Method, typename A, typename B>
class Dispatcher2 {
public:
Dispatcher2()
: method_(NULL),
a_(),
b_() {
}
Dispatcher2(Method method, const A& a, const B& b)
: method_(method),
a_(a),
b_(b) {
}
void operator()(T* object, int32_t result) {
if (object)
(object->*method_)(result, a_, 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),
a_(),
b_(),
output_() {
Traits::Initialize(&output_);
}
DispatcherWithOutput2(Method method, const A& a, const B& b)
: method_(method),
a_(a),
b_(b),
output_() {
Traits::Initialize(&output_);
}
void operator()(T* object, int32_t result) {
// We must call Traits::StorageToPluginArg() even if we don't need to call
// the callback anymore, otherwise we may leak resource or var references.
if (object)
(object->*method_)(result, Traits::StorageToPluginArg(output_), a_, b_);
else
Traits::StorageToPluginArg(output_);
}
typename Traits::StorageType* output() {
return &output_;
}
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),
a_(),
b_(),
c_() {
}
Dispatcher3(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) {
if (object)
(object->*method_)(result, a_, b_, 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),
a_(),
b_(),
c_(),
output_() {
Traits::Initialize(&output_);
}
DispatcherWithOutput3(Method method, const A& a, const B& b, const C& c)
: method_(method),
a_(a),
b_(b),
c_(c),
output_() {
Traits::Initialize(&output_);
}
void operator()(T* object, int32_t result) {
// We must call Traits::StorageToPluginArg() even if we don't need to call
// the callback anymore, otherwise we may leak resource or var references.
if (object) {
(object->*method_)(result, Traits::StorageToPluginArg(output_),
a_, b_, c_);
} else {
Traits::StorageToPluginArg(output_);
}
}
typename Traits::StorageType* output() {
return &output_;
}
private:
Method method_;
A a_;
B b_;
C c_;
typename Traits::StorageType output_;
};
// Creates the back pointer object and takes a reference to it. This assumes
// either that the lock is held or that it is not needed.
void InitBackPointer() {
back_pointer_ = new BackPointer(this);
back_pointer_->AddRef();
}
// Releases our reference to the back pointer object and clears the pointer.
// This assumes either that the lock is held or that it is not needed.
void ResetBackPointer() {
back_pointer_->DropFactory();
back_pointer_->Release();
back_pointer_ = NULL;
}
// Takes ownership of the dispatcher pointer, which should be heap allocated.
template <typename Dispatcher>
CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) {
typename ThreadTraits::AutoLock lock(lock_);
PP_DCHECK(object_); // Expects a non-null object!
return CompletionCallback(
&CallbackData<Dispatcher>::Thunk,
new CallbackData<Dispatcher>(back_pointer_, dispatcher));
}
// Takes ownership of the dispatcher pointer, which should be heap allocated.
template <typename Dispatcher> CompletionCallbackWithOutput<
typename internal::TypeUnwrapper<
typename Dispatcher::OutputType>::StorageType>
NewCallbackWithOutputHelper(Dispatcher* dispatcher) {
typename ThreadTraits::AutoLock lock(lock_);
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&);
// Never changed once initialized so does not need protection by the lock.
T* object_;
// Protects the back pointer.
typename ThreadTraits::Lock lock_;
// Protected by the lock. This will get reset when you do CancelAll, for
// example.
BackPointer* back_pointer_;
};
} // namespace pp
#endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_