| Index: ppapi/cpp/completion_callback.h
|
| ===================================================================
|
| --- ppapi/cpp/completion_callback.h (revision 116283)
|
| +++ ppapi/cpp/completion_callback.h (working copy)
|
| @@ -8,7 +8,7 @@
|
| #include "ppapi/c/pp_completion_callback.h"
|
| #include "ppapi/c/pp_errors.h"
|
| #include "ppapi/cpp/logging.h"
|
| -#include "ppapi/cpp/module.h"
|
| +#include "ppapi/cpp/non_thread_safe_ref_count.h"
|
|
|
| /// @file
|
| /// This file defines the API to create and run a callback.
|
| @@ -156,6 +156,555 @@
|
| /// @return A <code>CompletionCallback</code> corresponding to a NULL callback.
|
| CompletionCallback BlockUntilComplete();
|
|
|
| +/// 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 you can make it more thread-friendly by passing a
|
| +/// thread-safe refcounting 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 MyHandler {
|
| +/// 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) {
|
| +/// }
|
| +///
|
| +/// void ProcessFile(const FileRef& file) {
|
| +/// CompletionCallback cc = factory_.NewRequiredCallback(
|
| +/// &MyHandler::DidOpen);
|
| +/// int32_t rv = fio_.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').
|
| +/// }
|
| +/// }
|
| +///
|
| +/// 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);
|
| +/// }
|
| +///
|
| +/// void ProcessBytes(const char* bytes, int32_t length) {
|
| +/// // Do work ...
|
| +/// }
|
| +///
|
| +/// pp::CompletionCallbackFactory<MyHandler> factory_;
|
| +/// pp::FileIO fio_;
|
| +/// char buf_[4096];
|
| +/// int64_t offset_;
|
| +/// };
|
| +///
|
| +/// @endcode
|
| +///
|
| +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
|
| + /// 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) {
|
| + InitBackPointer();
|
| + }
|
| +
|
| + /// Destructor.
|
| + ~CompletionCallbackFactory() {
|
| + ResetBackPointer();
|
| + }
|
| +
|
| + /// CancelAll() cancels all <code>CompletionCallbacks</code> allocated from
|
| + /// this factory.
|
| + void CancelAll() {
|
| + 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().
|
| + ///
|
| + /// @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.
|
| + /// NewCallback() is equivalent to NewRequiredCallback() below.
|
| + ///
|
| + /// @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) {
|
| + 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;
|
| + }
|
| +
|
| + /// 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;
|
| + }
|
| +
|
| + /// 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.
|
| + ///
|
| + /// @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) {
|
| + PP_DCHECK(object_);
|
| + return NewCallbackHelper(Dispatcher1<Method, A>(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
|
| + /// 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 NewRequiredCallback(Method method, const A& a) {
|
| + CompletionCallback cc = NewCallback(method, a);
|
| + cc.set_flags(cc.flags() & ~PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
|
| + return cc;
|
| + }
|
| +
|
| + /// 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;
|
| + }
|
| +
|
| + /// 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.
|
| + ///
|
| + /// @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) {
|
| + PP_DCHECK(object_);
|
| + return NewCallbackHelper(Dispatcher2<Method, A, B>(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
|
| + /// 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 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;
|
| + }
|
| +
|
| + /// 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;
|
| + }
|
| +
|
| + /// 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.
|
| + ///
|
| + /// @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) {
|
| + PP_DCHECK(object_);
|
| + return NewCallbackHelper(Dispatcher3<Method, A, B, C>(method, a, b, c));
|
| + }
|
| +
|
| + /// 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 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 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;
|
| + }
|
| +
|
| + /// 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;
|
| + }
|
| +
|
| + private:
|
| + class BackPointer {
|
| + public:
|
| + typedef CompletionCallbackFactory<T, RefCount> FactoryType;
|
| +
|
| + 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:
|
| + RefCount ref_;
|
| + FactoryType* factory_;
|
| + };
|
| +
|
| + template <typename Dispatcher>
|
| + class CallbackData {
|
| + public:
|
| + CallbackData(BackPointer* back_pointer, const Dispatcher& dispatcher)
|
| + : back_pointer_(back_pointer),
|
| + dispatcher_(dispatcher) {
|
| + back_pointer_->AddRef();
|
| + }
|
| +
|
| + ~CallbackData() {
|
| + back_pointer_->Release();
|
| + }
|
| +
|
| + static void Thunk(void* user_data, int32_t result) {
|
| + Self* self = static_cast<Self*>(user_data);
|
| + T* object = self->back_pointer_->GetObject();
|
| + if (object)
|
| + self->dispatcher_(object, result);
|
| + delete self;
|
| + }
|
| +
|
| + private:
|
| + typedef CallbackData<Dispatcher> Self;
|
| + BackPointer* back_pointer_;
|
| + Dispatcher dispatcher_;
|
| + };
|
| +
|
| + template <typename Method>
|
| + class Dispatcher0 {
|
| + public:
|
| + Dispatcher0(Method method) : method_(method) {
|
| + }
|
| + void operator()(T* object, int32_t result) {
|
| + (object->*method_)(result);
|
| + }
|
| + private:
|
| + Method method_;
|
| + };
|
| +
|
| + template <typename Method, typename A>
|
| + class Dispatcher1 {
|
| + public:
|
| + Dispatcher1(Method method, const A& a)
|
| + : method_(method),
|
| + a_(a) {
|
| + }
|
| + void operator()(T* object, int32_t result) {
|
| + (object->*method_)(result, a_);
|
| + }
|
| + private:
|
| + Method method_;
|
| + A a_;
|
| + };
|
| +
|
| + template <typename Method, typename A, typename B>
|
| + class Dispatcher2 {
|
| + public:
|
| + Dispatcher2(Method method, const A& a, const B& b)
|
| + : method_(method),
|
| + a_(a),
|
| + b_(b) {
|
| + }
|
| + void operator()(T* object, int32_t result) {
|
| + (object->*method_)(result, a_, b_);
|
| + }
|
| + private:
|
| + Method method_;
|
| + A a_;
|
| + B b_;
|
| + };
|
| +
|
| + template <typename Method, typename A, typename B, typename C>
|
| + class Dispatcher3 {
|
| + public:
|
| + 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) {
|
| + (object->*method_)(result, a_, b_, c_);
|
| + }
|
| + private:
|
| + Method method_;
|
| + A a_;
|
| + B b_;
|
| + C c_;
|
| + };
|
| +
|
| + void InitBackPointer() {
|
| + back_pointer_ = new BackPointer(this);
|
| + back_pointer_->AddRef();
|
| + }
|
| +
|
| + void ResetBackPointer() {
|
| + back_pointer_->DropFactory();
|
| + back_pointer_->Release();
|
| + }
|
| +
|
| + template <typename Dispatcher>
|
| + CompletionCallback NewCallbackHelper(const Dispatcher& dispatcher) {
|
| + PP_DCHECK(object_); // Expects a non-null object!
|
| + return CompletionCallback(
|
| + &CallbackData<Dispatcher>::Thunk,
|
| + new CallbackData<Dispatcher>(back_pointer_, dispatcher));
|
| + }
|
| +
|
| + // Disallowed:
|
| + CompletionCallbackFactory(const CompletionCallbackFactory&);
|
| + CompletionCallbackFactory& operator=(const CompletionCallbackFactory&);
|
| +
|
| + T* object_;
|
| + BackPointer* back_pointer_;
|
| +};
|
| +
|
| } // namespace pp
|
|
|
| #endif // PPAPI_CPP_COMPLETION_CALLBACK_H_
|
|
|
|
|