Bug 1368382. P2 - let ThenCommand reference the sub-type of ThenValueBase. r=gerald
authorJW Wang <jwwang@mozilla.com>
Wed, 31 May 2017 15:23:43 +0800
changeset 361728 a6df0f5e3000f7992c9cf4e0161887a8f465a906
parent 361727 f143a22591fa3f095c2b01c63937417f46826eff
child 361729 aa971939802838b324623e709034c09346006c21
push id31939
push usercbook@mozilla.com
push dateThu, 01 Jun 2017 11:49:28 +0000
treeherdermozilla-central@d96110d76619 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1368382
milestone55.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 1368382. P2 - let ThenCommand reference the sub-type of ThenValueBase. r=gerald Since we will store mCompletionPromise in the sub-class of ThenValueBase, ThenCommand needs to reference the sub-type in order to access mCompletionPromise. MozReview-Commit-ID: BUi7jElOhP7
xpcom/threads/MozPromise.h
--- a/xpcom/threads/MozPromise.h
+++ b/xpcom/threads/MozPromise.h
@@ -538,25 +538,34 @@ protected:
                            !TakesArgument<MethodType>::value,
                            already_AddRefed<MozPromise>>::Type
   InvokeCallbackMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue)
   {
     ((*aThisVal).*aMethod)();
     return nullptr;
   }
 
+  template<typename>
+  class ThenCommand;
+
   template<typename...>
   class ThenValue;
 
   template<typename ThisType,
            typename ResolveMethodType,
            typename RejectMethodType>
   class ThenValue<ThisType*, ResolveMethodType, RejectMethodType>
     : public ThenValueBase
   {
+    friend class ThenCommand<ThenValue>;
+    using SupportChaining = IntegralConstant<
+      bool,
+      ReturnTypeIs<ResolveMethodType, RefPtr<MozPromise>>::value &&
+        ReturnTypeIs<RejectMethodType, RefPtr<MozPromise>>::value>;
+
   public:
     ThenValue(AbstractThread* aResponseTarget,
               ThisType* aThisVal,
               ResolveMethodType aResolveMethod,
               RejectMethodType aRejectMethod,
               const char* aCallSite)
       : ThenValueBase(aResponseTarget, aCallSite)
       , mThisVal(aThisVal)
@@ -600,16 +609,20 @@ protected:
     RefPtr<ThisType> mThisVal; // Only accessed and refcounted on dispatch thread.
     ResolveMethodType mResolveMethod;
     RejectMethodType mRejectMethod;
   };
 
   template<typename ThisType, typename ResolveRejectMethodType>
   class ThenValue<ThisType*, ResolveRejectMethodType> : public ThenValueBase
   {
+    friend class ThenCommand<ThenValue>;
+    using SupportChaining =
+      ReturnTypeIs<ResolveRejectMethodType, RefPtr<MozPromise>>;
+
   public:
     ThenValue(AbstractThread* aResponseTarget,
               ThisType* aThisVal,
               ResolveRejectMethodType aResolveRejectMethod,
               const char* aCallSite)
       : ThenValueBase(aResponseTarget, aCallSite)
       , mThisVal(aThisVal)
       , mResolveRejectMethod(aResolveRejectMethod)
@@ -644,16 +657,22 @@ protected:
     RefPtr<ThisType> mThisVal; // Only accessed and refcounted on dispatch thread.
     ResolveRejectMethodType mResolveRejectMethod;
   };
 
   // NB: We could use std::function here instead of a template if it were supported. :-(
   template<typename ResolveFunction, typename RejectFunction>
   class ThenValue<ResolveFunction, RejectFunction> : public ThenValueBase
   {
+    friend class ThenCommand<ThenValue>;
+    using SupportChaining = IntegralConstant<
+      bool,
+      ReturnTypeIs<ResolveFunction, RefPtr<MozPromise>>::value &&
+        ReturnTypeIs<RejectFunction, RefPtr<MozPromise>>::value>;
+
   public:
     ThenValue(AbstractThread* aResponseTarget,
               ResolveFunction&& aResolveFunction,
               RejectFunction&& aRejectFunction,
               const char* aCallSite)
       : ThenValueBase(aResponseTarget, aCallSite)
     {
       mResolveFunction.emplace(Move(aResolveFunction));
@@ -702,16 +721,20 @@ protected:
   private:
     Maybe<ResolveFunction> mResolveFunction; // Only accessed and deleted on dispatch thread.
     Maybe<RejectFunction> mRejectFunction; // Only accessed and deleted on dispatch thread.
   };
 
   template<typename ResolveRejectFunction>
   class ThenValue<ResolveRejectFunction> : public ThenValueBase
   {
+    friend class ThenCommand<ThenValue>;
+    using SupportChaining =
+      ReturnTypeIs<ResolveRejectFunction, RefPtr<MozPromise>>;
+
   public:
     ThenValue(AbstractThread* aResponseTarget,
               ResolveRejectFunction&& aResolveRejectFunction,
               const char* aCallSite)
       : ThenValueBase(aResponseTarget, aCallSite)
     {
       mResolveRejectFunction.emplace(Move(aResolveRejectFunction));
     }
@@ -766,34 +789,34 @@ public:
                 aCallSite, this, aThenValue, (int) IsPending());
     if (!IsPending()) {
       aThenValue->Dispatch(this);
     } else {
       mThenValues.AppendElement(aThenValue);
     }
   }
 
-private:
+protected:
   /*
    * A command object to store all information needed to make a request to
    * the promise. This allows us to delay the request until further use is
    * known (whether it is ->Then() again for more promise chaining or ->Track()
    * to terminate chaining and issue the request).
    *
    * This allows a unified syntax for promise chaining and disconnection
    * and feels more like its JS counterpart.
    */
-  template <bool SupportChaining>
+  template<typename ThenValueType>
   class ThenCommand
   {
     friend class MozPromise;
 
     ThenCommand(AbstractThread* aResponseThread,
                 const char* aCallSite,
-                already_AddRefed<ThenValueBase> aThenValue,
+                already_AddRefed<ThenValueType> aThenValue,
                 MozPromise* aReceiver)
       : mResponseThread(aResponseThread)
       , mCallSite(aCallSite)
       , mThenValue(aThenValue)
       , mReceiver(aReceiver)
     {
       MOZ_ASSERT(aResponseThread);
     }
@@ -810,21 +833,22 @@ private:
     }
 
     // Allow RefPtr<MozPromise> p = somePromise->Then();
     //       p->Then(thread1, ...);
     //       p->Then(thread2, ...);
     template <typename...>
     operator RefPtr<MozPromise>()
     {
-      static_assert(SupportChaining,
+      static_assert(
+        ThenValueType::SupportChaining::value,
         "The resolve/reject callback needs to return a RefPtr<MozPromise> "
         "in order to do promise chaining.");
 
-      RefPtr<ThenValueBase> thenValue = mThenValue.forget();
+      RefPtr<ThenValueType> thenValue = mThenValue.forget();
       // mCompletionPromise must be created before ThenInternal() to avoid race.
       RefPtr<MozPromise::Private> p = new MozPromise::Private(
         "<completion promise>", true /* aIsCompletionPromise */);
       thenValue->mCompletionPromise = p;
       // Note ThenInternal() might nullify mCompletionPromise before return.
       // So we need to return p instead of mCompletionPromise.
       mReceiver->ThenInternal(mResponseThread, thenValue, mCallSite);
       return p;
@@ -834,120 +858,94 @@ private:
     auto Then(Ts&&... aArgs)
       -> decltype(DeclVal<MozPromise>().Then(Forward<Ts>(aArgs)...))
     {
       return static_cast<RefPtr<MozPromise>>(*this)->Then(Forward<Ts>(aArgs)...);
     }
 
     void Track(MozPromiseRequestHolder<MozPromise>& aRequestHolder)
     {
-      RefPtr<ThenValueBase> thenValue = mThenValue.forget();
+      RefPtr<ThenValueType> thenValue = mThenValue.forget();
       mReceiver->ThenInternal(mResponseThread, thenValue, mCallSite);
       aRequestHolder.Track(thenValue.forget());
     }
 
     // Allow calling ->Then() again for more promise chaining or ->Track() to
     // end chaining and track the request for future disconnection.
     ThenCommand* operator->()
     {
       return this;
     }
 
   private:
     AbstractThread* mResponseThread;
     const char* mCallSite;
-    RefPtr<ThenValueBase> mThenValue;
+    RefPtr<ThenValueType> mThenValue;
     MozPromise* mReceiver;
   };
 
-  template<typename Method>
-  using MethodReturnPromise =
-    ReturnTypeIs<Method, RefPtr<MozPromise>>;
-
-  template<typename Function>
-  using FunctionReturnPromise =
-    MethodReturnPromise<decltype(&Function::operator())>;
-
-  template <typename M1, typename... Ms>
-  struct MethodThenCommand
-  {
-    static const bool value =
-      MethodThenCommand<M1>::value && MethodThenCommand<Ms...>::value;
-    using type = ThenCommand<value>;
-  };
-
-  template <typename M1>
-  struct MethodThenCommand<M1>
-  {
-    static const bool value = MethodReturnPromise<M1>::value;
-    using type = ThenCommand<value>;
-  };
-
-  template <typename F1, typename... Fs>
-  struct FunctionThenCommand
-  {
-    static const bool value =
-      FunctionThenCommand<F1>::value && FunctionThenCommand<Fs...>::value;
-    using type = ThenCommand<value>;
-  };
-
-  template <typename F1>
-  struct FunctionThenCommand<F1>
-  {
-    static const bool value = FunctionReturnPromise<F1>::value;
-    using type = ThenCommand<value>;
-  };
-
 public:
-  template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
-  typename MethodThenCommand<ResolveMethodType, RejectMethodType>::type
-  Then(AbstractThread* aResponseThread, const char* aCallSite,
-    ThisType* aThisVal, ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
+  template<typename ThisType,
+           typename ResolveMethodType,
+           typename RejectMethodType,
+           typename ThenValueType =
+             ThenValue<ThisType*, ResolveMethodType, RejectMethodType>,
+           typename ReturnType = ThenCommand<ThenValueType>>
+  ReturnType Then(AbstractThread* aResponseThread,
+                  const char* aCallSite,
+                  ThisType* aThisVal,
+                  ResolveMethodType aResolveMethod,
+                  RejectMethodType aRejectMethod)
   {
-    using ThenType = ThenValue<ThisType*, ResolveMethodType, RejectMethodType>;
-    RefPtr<ThenValueBase> thenValue = new ThenType(aResponseThread,
-       aThisVal, aResolveMethod, aRejectMethod, aCallSite);
-    return typename MethodThenCommand<ResolveMethodType, RejectMethodType>::type(
-      aResponseThread, aCallSite, thenValue.forget(), this);
+    RefPtr<ThenValueType> thenValue = new ThenValueType(
+      aResponseThread, aThisVal, aResolveMethod, aRejectMethod, aCallSite);
+    return ReturnType(aResponseThread, aCallSite, thenValue.forget(), this);
   }
 
-  template<typename ThisType, typename ResolveRejectMethodType>
-  typename MethodThenCommand<ResolveRejectMethodType>::type
-  Then(AbstractThread* aResponseThread, const char* aCallSite,
-    ThisType* aThisVal, ResolveRejectMethodType aResolveRejectMethod)
+  template<
+    typename ThisType,
+    typename ResolveRejectMethodType,
+    typename ThenValueType = ThenValue<ThisType*, ResolveRejectMethodType>,
+    typename ReturnType = ThenCommand<ThenValueType>>
+  ReturnType Then(AbstractThread* aResponseThread,
+                  const char* aCallSite,
+                  ThisType* aThisVal,
+                  ResolveRejectMethodType aResolveRejectMethod)
   {
-    using ThenType = ThenValue<ThisType*, ResolveRejectMethodType>;
-    RefPtr<ThenValueBase> thenValue = new ThenType(aResponseThread,
-       aThisVal, aResolveRejectMethod, aCallSite);
-    return typename MethodThenCommand<ResolveRejectMethodType>::type(
-      aResponseThread, aCallSite, thenValue.forget(), this);
+    RefPtr<ThenValueType> thenValue = new ThenValueType(
+      aResponseThread, aThisVal, aResolveRejectMethod, aCallSite);
+    return ReturnType(aResponseThread, aCallSite, thenValue.forget(), this);
   }
 
-  template<typename ResolveFunction, typename RejectFunction>
-  typename FunctionThenCommand<ResolveFunction, RejectFunction>::type
-  Then(AbstractThread* aResponseThread, const char* aCallSite,
-    ResolveFunction&& aResolveFunction, RejectFunction&& aRejectFunction)
+  template<typename ResolveFunction,
+           typename RejectFunction,
+           typename ThenValueType = ThenValue<ResolveFunction, RejectFunction>,
+           typename ReturnType = ThenCommand<ThenValueType>>
+  ReturnType Then(AbstractThread* aResponseThread,
+                  const char* aCallSite,
+                  ResolveFunction&& aResolveFunction,
+                  RejectFunction&& aRejectFunction)
   {
-    using ThenType = ThenValue<ResolveFunction, RejectFunction>;
-    RefPtr<ThenValueBase> thenValue = new ThenType(aResponseThread,
-      Move(aResolveFunction), Move(aRejectFunction), aCallSite);
-    return typename FunctionThenCommand<ResolveFunction, RejectFunction>::type(
-      aResponseThread, aCallSite, thenValue.forget(), this);
+    RefPtr<ThenValueType> thenValue = new ThenValueType(aResponseThread,
+                                                        Move(aResolveFunction),
+                                                        Move(aRejectFunction),
+                                                        aCallSite);
+    return ReturnType(aResponseThread, aCallSite, thenValue.forget(), this);
   }
 
-  template<typename ResolveRejectFunction>
-  typename FunctionThenCommand<ResolveRejectFunction>::type
-  Then(AbstractThread* aResponseThread, const char* aCallSite,
-                   ResolveRejectFunction&& aResolveRejectFunction)
+  template<typename ResolveRejectFunction,
+           typename ThenValueType = ThenValue<ResolveRejectFunction>,
+           typename ReturnType = ThenCommand<ThenValueType>>
+  ReturnType Then(AbstractThread* aResponseThread,
+                  const char* aCallSite,
+                  ResolveRejectFunction&& aResolveRejectFunction)
   {
-    using ThenType = ThenValue<ResolveRejectFunction>;
-    RefPtr<ThenValueBase> thenValue = new ThenType(aResponseThread,
-      Move(aResolveRejectFunction), aCallSite);
-    return typename FunctionThenCommand<ResolveRejectFunction>::type(
-      aResponseThread, aCallSite, thenValue.forget(), this);
+    RefPtr<ThenValueType> thenValue = new ThenValueType(
+      aResponseThread, Move(aResolveRejectFunction), aCallSite);
+    return ReturnType(aResponseThread, aCallSite, thenValue.forget(), this);
   }
 
   void ChainTo(already_AddRefed<Private> aChainedPromise, const char* aCallSite)
   {
     MutexAutoLock lock(mMutex);
     MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveRequest);
     mHaveRequest = true;
     RefPtr<Private> chainedPromise = aChainedPromise;