C++程序  |  894行  |  31.11 KB

// 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 "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_