Bug 1194112. Part 1 - extract event dispatch code from ListenerImpl to its own class. r=kinetik.
authorJW Wang <jwwang@mozilla.com>
Mon, 24 Aug 2015 10:38:16 +0800
changeset 259018 2afb1fcf608b57ef00583b419d79677b6a8587fa
parent 259017 16327a5d2961773729aca9f1928d6e7d0334e77f
child 259019 e55b03747ebd99186aeb3d9ac5eeeb2e9e0af138
push id29268
push userryanvm@gmail.com
push dateTue, 25 Aug 2015 00:37:23 +0000
treeherdermozilla-central@08015770c9d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1194112
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1194112. Part 1 - extract event dispatch code from ListenerImpl to its own class. r=kinetik.
dom/media/MediaEventSource.h
--- a/dom/media/MediaEventSource.h
+++ b/dom/media/MediaEventSource.h
@@ -113,16 +113,85 @@ template <typename T>
 class RawPtr {
 public:
   explicit RawPtr(T* aPtr) : mPtr(aPtr) {}
   T* get() const { return mPtr; }
 private:
   T* const mPtr;
 };
 
+/**
+ * A helper class to pass event data to the listeners. Optimized to save
+ * copy when Move is possible or |Function| takes no arguments.
+ */
+template<typename Target, typename Function>
+class ListenerHelper {
+  // Define our custom runnable to minimize copy of the event data.
+  // NS_NewRunnableFunction will result in 2 copies of the event data.
+  // One is captured by the lambda and the other is the copy of the lambda.
+  template <typename T>
+  class R : public nsRunnable {
+    typedef typename RemoveCV<typename RemoveReference<T>::Type>::Type ArgType;
+  public:
+    template <typename U>
+    R(RevocableToken* aToken, const Function& aFunction, U&& aEvent)
+      : mToken(aToken), mFunction(aFunction), mEvent(Forward<U>(aEvent)) {}
+
+    NS_IMETHOD Run() override {
+      // Don't call the listener if it is disconnected.
+      if (!mToken->IsRevoked()) {
+        // Enable move whenever possible since mEvent won't be used anymore.
+        mFunction(Move(mEvent));
+      }
+      return NS_OK;
+    }
+
+  private:
+    nsRefPtr<RevocableToken> mToken;
+    Function mFunction;
+    ArgType mEvent;
+  };
+
+public:
+  ListenerHelper(RevocableToken* aToken, Target* aTarget, const Function& aFunc)
+    : mToken(aToken), mTarget(aTarget), mFunction(aFunc) {}
+
+  // |F| takes one argument.
+  template <typename F, typename T>
+  typename EnableIf<TakeArgs<F>::Type::value, void>::Type
+  Dispatch(const F& aFunc, T&& aEvent) {
+    nsCOMPtr<nsIRunnable> r = new R<T>(mToken, aFunc, Forward<T>(aEvent));
+    EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
+  }
+
+  // |F| takes no arguments. Don't bother passing aEvent.
+  template <typename F, typename T>
+  typename EnableIf<!TakeArgs<F>::Type::value, void>::Type
+  Dispatch(const F& aFunc, T&&) {
+    const nsRefPtr<RevocableToken>& token = mToken;
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
+      // Don't call the listener if it is disconnected.
+      if (!token->IsRevoked()) {
+        aFunc();
+      }
+    });
+    EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
+  }
+
+  template <typename T>
+  void Dispatch(T&& aEvent) {
+    Dispatch(mFunction, Forward<T>(aEvent));
+  }
+
+private:
+  nsRefPtr<RevocableToken> mToken;
+  const nsRefPtr<Target> mTarget;
+  Function mFunction;
+};
+
 } // namespace detail
 
 template <typename T, ListenerMode> class MediaEventSource;
 
 /**
  * Not thread-safe since this is not meant to be shared and therefore only
  * move constructor is provided. Used to hold the result of
  * MediaEventSource<T>::Connect() and call Disconnect() to disconnect the
@@ -192,68 +261,22 @@ class MediaEventSource {
   /**
    * Store the registered target thread and function so it knows where and to
    * whom to send the event data.
    */
   template<typename Target, typename Function>
   class ListenerImpl : public Listener {
   public:
     explicit ListenerImpl(Target* aTarget, const Function& aFunction)
-      : mTarget(aTarget), mFunction(aFunction) {}
-
-    // |Function| takes one argument.
-    void Dispatch(const ArgType& aEvent, TrueType) {
-      // Define our custom runnable to minimize copy of the event data.
-      // NS_NewRunnableFunction will result in 2 copies of the event data.
-      // One is captured by the lambda and the other is the copy of the lambda.
-      class R : public nsRunnable {
-      public:
-        R(RevocableToken* aToken,
-          const Function& aFunction, const ArgType& aEvent)
-          : mToken(aToken), mFunction(aFunction), mEvent(aEvent) {}
-
-        NS_IMETHOD Run() override {
-          // Don't call the listener if it is disconnected.
-          if (!mToken->IsRevoked()) {
-            // Enable move whenever possible since mEvent won't be used anymore.
-            mFunction(Move(mEvent));
-          }
-          return NS_OK;
-        }
-
-      private:
-        nsRefPtr<RevocableToken> mToken;
-        Function mFunction;
-        ArgType mEvent;
-      };
-
-      nsCOMPtr<nsIRunnable> r = new R(this->Token(), mFunction, aEvent);
-      detail::EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
+      : mHelper(Listener::Token(), aTarget, aFunction) {}
+    void Dispatch(const ArgType& aEvent) override {
+      mHelper.Dispatch(aEvent);
     }
-
-    // |Function| takes no arguments. Don't bother passing aEvent.
-    void Dispatch(const ArgType& aEvent, FalseType) {
-      nsRefPtr<RevocableToken> token = this->Token();
-      const Function& function = mFunction;
-      nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-        // Don't call the listener if it is disconnected.
-        if (!token->IsRevoked()) {
-          function();
-        }
-      });
-      detail::EventTarget<Target>::Dispatch(mTarget.get(), r.forget());
-    }
-
-    void Dispatch(const ArgType& aEvent) override {
-      Dispatch(aEvent, typename detail::TakeArgs<Function>::Type());
-    }
-
   private:
-    const nsRefPtr<Target> mTarget;
-    Function mFunction;
+    detail::ListenerHelper<Target, Function> mHelper;
   };
 
   template<typename Target, typename Function>
   MediaEventListener
   ConnectInternal(Target* aTarget, const Function& aFunction) {
     MutexAutoLock lock(mMutex);
     MOZ_ASSERT(Mode == ListenerMode::NonExclusive || mListeners.IsEmpty());
     auto l = mListeners.AppendElement();