Bug 1163320 - Variadic implementation of nsRunnableMethodArguments. r=froydnj draft
authorBotond Ballo <botond@mozilla.com>
Mon, 11 May 2015 17:24:21 -0400
changeset 347124 89a0ad0877ed3290a41288523fe9b13d9c5bac7d
parent 346552 538d248fa252a4100082fd9bc3fdc08d322cda22
child 517554 04406063ccf1387d6ecb5a346fb8370ddb9be090
push id14499
push userbballo@mozilla.com
push dateSat, 02 Apr 2016 00:36:10 +0000
reviewersfroydnj
bugs1163320
milestone48.0a1
Bug 1163320 - Variadic implementation of nsRunnableMethodArguments. r=froydnj MozReview-Commit-ID: 13YyOyiionD
xpcom/glue/nsThreadUtils.h
--- a/xpcom/glue/nsThreadUtils.h
+++ b/xpcom/glue/nsThreadUtils.h
@@ -13,17 +13,19 @@
 #include "nsIThreadManager.h"
 #include "nsIThread.h"
 #include "nsIRunnable.h"
 #include "nsICancelableRunnable.h"
 #include "nsStringGlue.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Atomics.h"
+#include "mozilla/IndexSequence.h"
 #include "mozilla/Likely.h"
+#include "mozilla/Tuple.h"
 #include "mozilla/TypeTraits.h"
 
 //-----------------------------------------------------------------------------
 // These methods are alternatives to the methods on nsIThreadManager, provided
 // for convenience.
 
 /**
  * Set name of the target thread.  This operation is asynchronous.
@@ -364,157 +366,157 @@ struct IsParameterStorageClass : public 
 
 template<typename T>
 struct StoreCopyPassByValue
 {
   typedef T stored_type;
   typedef T passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreCopyPassByValue(A&& a) : m(mozilla::Forward<A>(a)) {}
+  MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(mozilla::Forward<A>(a)) {}
   passed_type PassAsParameter() { return m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreCopyPassByValue<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StoreCopyPassByConstLRef
 {
   typedef T stored_type;
   typedef const T& passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreCopyPassByConstLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
+  MOZ_IMPLICIT StoreCopyPassByConstLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
   passed_type PassAsParameter() { return m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StoreCopyPassByLRef
 {
   typedef T stored_type;
   typedef T& passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreCopyPassByLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
+  MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
   passed_type PassAsParameter() { return m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreCopyPassByLRef<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StoreCopyPassByRRef
 {
   typedef T stored_type;
   typedef T&& passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreCopyPassByRRef(A&& a) : m(mozilla::Forward<A>(a)) {}
+  MOZ_IMPLICIT StoreCopyPassByRRef(A&& a) : m(mozilla::Forward<A>(a)) {}
   passed_type PassAsParameter() { return mozilla::Move(m); }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreCopyPassByRRef<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StoreRefPassByLRef
 {
   typedef T& stored_type;
   typedef T& passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreRefPassByLRef(A& a) : m(a) {}
+  MOZ_IMPLICIT StoreRefPassByLRef(A& a) : m(a) {}
   passed_type PassAsParameter() { return m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreRefPassByLRef<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StoreConstRefPassByConstLRef
 {
   typedef const T& stored_type;
   typedef const T& passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreConstRefPassByConstLRef(const A& a) : m(a) {}
+  MOZ_IMPLICIT StoreConstRefPassByConstLRef(const A& a) : m(a) {}
   passed_type PassAsParameter() { return m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreConstRefPassByConstLRef<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StorensRefPtrPassByPtr
 {
   typedef RefPtr<T> stored_type;
   typedef T* passed_type;
   stored_type m;
   template <typename A>
-  explicit StorensRefPtrPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
+  MOZ_IMPLICIT StorensRefPtrPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
   passed_type PassAsParameter() { return m.get(); }
 };
 template<typename S>
 struct IsParameterStorageClass<StorensRefPtrPassByPtr<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StorePtrPassByPtr
 {
   typedef T* stored_type;
   typedef T* passed_type;
   stored_type m;
   template <typename A>
-  explicit StorePtrPassByPtr(A a) : m(a) {}
+  MOZ_IMPLICIT StorePtrPassByPtr(A a) : m(a) {}
   passed_type PassAsParameter() { return m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StorePtrPassByPtr<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StoreConstPtrPassByConstPtr
 {
   typedef const T* stored_type;
   typedef const T* passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreConstPtrPassByConstPtr(A a) : m(a) {}
+  MOZ_IMPLICIT StoreConstPtrPassByConstPtr(A a) : m(a) {}
   passed_type PassAsParameter() { return m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StoreCopyPassByConstPtr
 {
   typedef T stored_type;
   typedef const T* passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreCopyPassByConstPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
+  MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
   passed_type PassAsParameter() { return &m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreCopyPassByConstPtr<S>>
   : public mozilla::TrueType {};
 
 template<typename T>
 struct StoreCopyPassByPtr
 {
   typedef T stored_type;
   typedef T* passed_type;
   stored_type m;
   template <typename A>
-  explicit StoreCopyPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
+  MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
   passed_type PassAsParameter() { return &m; }
 };
 template<typename S>
 struct IsParameterStorageClass<StoreCopyPassByPtr<S>>
   : public mozilla::TrueType {};
 
 namespace detail {
 
@@ -646,206 +648,38 @@ struct ParameterStorage
   : mozilla::Conditional<IsParameterStorageClass<T>::value,
                          T,
                          typename NonParameterStorageClass<T>::Type>
 {};
 
 } /* namespace detail */
 
 // struct used to store arguments and later apply them to a method.
-template <typename... Ts> struct nsRunnableMethodArguments;
-
-// Specializations for 0-8 arguments, add more as required.
-// TODO Use tuple instead; And/or use lambdas (see bug 1152753)
-template <>
-struct nsRunnableMethodArguments<>
-{
-  template<class C, typename M> void apply(C* o, M m)
-  {
-    ((*o).*m)();
-  }
-};
-template <typename T0>
-struct nsRunnableMethodArguments<T0>
-{
-  typename ::detail::ParameterStorage<T0>::Type m0;
-  template<typename A0>
-  explicit nsRunnableMethodArguments(A0&& a0)
-    : m0(mozilla::Forward<A0>(a0))
-  {}
-  template<class C, typename M> void apply(C* o, M m)
-  {
-    ((*o).*m)(m0.PassAsParameter());
-  }
-};
-template <typename T0, typename T1>
-struct nsRunnableMethodArguments<T0, T1>
-{
-  typename ::detail::ParameterStorage<T0>::Type m0;
-  typename ::detail::ParameterStorage<T1>::Type m1;
-  template<typename A0, typename A1>
-  nsRunnableMethodArguments(A0&& a0, A1&& a1)
-    : m0(mozilla::Forward<A0>(a0))
-    , m1(mozilla::Forward<A1>(a1))
-  {}
-  template<class C, typename M> void apply(C* o, M m)
-  {
-    ((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter());
-  }
-};
-template <typename T0, typename T1, typename T2>
-struct nsRunnableMethodArguments<T0, T1, T2>
+template <typename... Ts>
+struct nsRunnableMethodArguments
 {
-  typename ::detail::ParameterStorage<T0>::Type m0;
-  typename ::detail::ParameterStorage<T1>::Type m1;
-  typename ::detail::ParameterStorage<T2>::Type m2;
-  template<typename A0, typename A1, typename A2>
-  nsRunnableMethodArguments(A0&& a0, A1&& a1, A2&& a2)
-    : m0(mozilla::Forward<A0>(a0))
-    , m1(mozilla::Forward<A1>(a1))
-    , m2(mozilla::Forward<A2>(a2))
+  mozilla::Tuple<typename ::detail::ParameterStorage<Ts>::Type...> mArguments;
+  template <typename... As>
+  explicit nsRunnableMethodArguments(As&&... aArguments)
+    : mArguments(mozilla::Forward<As>(aArguments)...)
   {}
-  template<class C, typename M> void apply(C* o, M m)
-  {
-    ((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter(), m2.PassAsParameter());
-  }
-};
-template <typename T0, typename T1, typename T2, typename T3>
-struct nsRunnableMethodArguments<T0, T1, T2, T3>
-{
-  typename ::detail::ParameterStorage<T0>::Type m0;
-  typename ::detail::ParameterStorage<T1>::Type m1;
-  typename ::detail::ParameterStorage<T2>::Type m2;
-  typename ::detail::ParameterStorage<T3>::Type m3;
-  template<typename A0, typename A1, typename A2, typename A3>
-  nsRunnableMethodArguments(A0&& a0, A1&& a1, A2&& a2, A3&& a3)
-    : m0(mozilla::Forward<A0>(a0))
-    , m1(mozilla::Forward<A1>(a1))
-    , m2(mozilla::Forward<A2>(a2))
-    , m3(mozilla::Forward<A3>(a3))
-  {}
-  template<class C, typename M> void apply(C* o, M m)
-  {
-    ((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter(),
-              m2.PassAsParameter(), m3.PassAsParameter());
-  }
-};
-template <typename T0, typename T1, typename T2, typename T3, typename T4>
-struct nsRunnableMethodArguments<T0, T1, T2, T3, T4>
-{
-  typename ::detail::ParameterStorage<T0>::Type m0;
-  typename ::detail::ParameterStorage<T1>::Type m1;
-  typename ::detail::ParameterStorage<T2>::Type m2;
-  typename ::detail::ParameterStorage<T3>::Type m3;
-  typename ::detail::ParameterStorage<T4>::Type m4;
-  template<typename A0, typename A1, typename A2, typename A3, typename A4>
-  nsRunnableMethodArguments(A0&& a0, A1&& a1, A2&& a2, A3&& a3, A4&& a4)
-    : m0(mozilla::Forward<A0>(a0))
-    , m1(mozilla::Forward<A1>(a1))
-    , m2(mozilla::Forward<A2>(a2))
-    , m3(mozilla::Forward<A3>(a3))
-    , m4(mozilla::Forward<A4>(a4))
-  {}
-  template<class C, typename M> void apply(C* o, M m)
+  template<typename C, typename M, typename... Args, size_t... Indices>
+  static auto
+  applyImpl(C* o, M m, mozilla::Tuple<Args...>& args,
+            mozilla::IndexSequence<Indices...>)
+      -> decltype(((*o).*m)(mozilla::Get<Indices>(args).PassAsParameter()...))
   {
-    ((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter(),
-              m2.PassAsParameter(), m3.PassAsParameter(),
-              m4.PassAsParameter());
-  }
-};
-template <typename T0, typename T1, typename T2, typename T3, typename T4,
-          typename T5>
-struct nsRunnableMethodArguments<T0, T1, T2, T3, T4, T5>
-{
-  typename ::detail::ParameterStorage<T0>::Type m0;
-  typename ::detail::ParameterStorage<T1>::Type m1;
-  typename ::detail::ParameterStorage<T2>::Type m2;
-  typename ::detail::ParameterStorage<T3>::Type m3;
-  typename ::detail::ParameterStorage<T4>::Type m4;
-  typename ::detail::ParameterStorage<T5>::Type m5;
-  template<typename A0, typename A1, typename A2, typename A3, typename A4,
-           typename A5>
-  nsRunnableMethodArguments(A0&& a0, A1&& a1, A2&& a2, A3&& a3, A4&& a4,
-        A5&& a5)
-    : m0(mozilla::Forward<A0>(a0))
-    , m1(mozilla::Forward<A1>(a1))
-    , m2(mozilla::Forward<A2>(a2))
-    , m3(mozilla::Forward<A3>(a3))
-    , m4(mozilla::Forward<A4>(a4))
-    , m5(mozilla::Forward<A5>(a5))
-  {}
-  template<class C, typename M> void apply(C* o, M m)
-  {
-    ((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter(),
-              m2.PassAsParameter(), m3.PassAsParameter(),
-              m4.PassAsParameter(), m5.PassAsParameter());
+    return ((*o).*m)(mozilla::Get<Indices>(args).PassAsParameter()...);
   }
-};
-template <typename T0, typename T1, typename T2, typename T3, typename T4,
-          typename T5, typename T6>
-struct nsRunnableMethodArguments<T0, T1, T2, T3, T4, T5, T6>
-{
-  typename ::detail::ParameterStorage<T0>::Type m0;
-  typename ::detail::ParameterStorage<T1>::Type m1;
-  typename ::detail::ParameterStorage<T2>::Type m2;
-  typename ::detail::ParameterStorage<T3>::Type m3;
-  typename ::detail::ParameterStorage<T4>::Type m4;
-  typename ::detail::ParameterStorage<T5>::Type m5;
-  typename ::detail::ParameterStorage<T6>::Type m6;
-  template<typename A0, typename A1, typename A2, typename A3, typename A4,
-           typename A5, typename A6>
-  nsRunnableMethodArguments(A0&& a0, A1&& a1, A2&& a2, A3&& a3, A4&& a4,
-        A5&& a5, A6&& a6)
-    : m0(mozilla::Forward<A0>(a0))
-    , m1(mozilla::Forward<A1>(a1))
-    , m2(mozilla::Forward<A2>(a2))
-    , m3(mozilla::Forward<A3>(a3))
-    , m4(mozilla::Forward<A4>(a4))
-    , m5(mozilla::Forward<A5>(a5))
-    , m6(mozilla::Forward<A6>(a6))
-  {}
-  template<class C, typename M> void apply(C* o, M m)
+  template<class C, typename M> auto apply(C* o, M m)
+      -> decltype(applyImpl(o, m, mArguments,
+                  typename mozilla::IndexSequenceFor<Ts...>::Type()))
   {
-    ((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter(),
-              m2.PassAsParameter(), m3.PassAsParameter(),
-              m4.PassAsParameter(), m5.PassAsParameter(),
-              m6.PassAsParameter());
-  }
-};
-template <typename T0, typename T1, typename T2, typename T3, typename T4,
-          typename T5, typename T6, typename T7>
-struct nsRunnableMethodArguments<T0, T1, T2, T3, T4, T5, T6, T7>
-{
-  typename ::detail::ParameterStorage<T0>::Type m0;
-  typename ::detail::ParameterStorage<T1>::Type m1;
-  typename ::detail::ParameterStorage<T2>::Type m2;
-  typename ::detail::ParameterStorage<T3>::Type m3;
-  typename ::detail::ParameterStorage<T4>::Type m4;
-  typename ::detail::ParameterStorage<T5>::Type m5;
-  typename ::detail::ParameterStorage<T6>::Type m6;
-  typename ::detail::ParameterStorage<T7>::Type m7;
-  template<typename A0, typename A1, typename A2, typename A3, typename A4,
-           typename A5, typename A6, typename A7>
-  nsRunnableMethodArguments(A0&& a0, A1&& a1, A2&& a2, A3&& a3, A4&& a4,
-        A5&& a5, A6&& a6, A7&& a7)
-    : m0(mozilla::Forward<A0>(a0))
-    , m1(mozilla::Forward<A1>(a1))
-    , m2(mozilla::Forward<A2>(a2))
-    , m3(mozilla::Forward<A3>(a3))
-    , m4(mozilla::Forward<A4>(a4))
-    , m5(mozilla::Forward<A5>(a5))
-    , m6(mozilla::Forward<A6>(a6))
-    , m7(mozilla::Forward<A7>(a7))
-  {}
-  template<class C, typename M> void apply(C* o, M m)
-  {
-    ((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter(),
-              m2.PassAsParameter(), m3.PassAsParameter(),
-              m4.PassAsParameter(), m5.PassAsParameter(),
-              m6.PassAsParameter(), m7.PassAsParameter());
+    return applyImpl(o, m, mArguments,
+        typename mozilla::IndexSequenceFor<Ts...>::Type());
   }
 };
 
 template<typename Method, bool Owning, typename... Storages>
 class nsRunnableMethodImpl
   : public nsRunnableMethodTraits<Method, Owning>::base_type
 {
   typedef typename nsRunnableMethodTraits<Method, Owning>::class_type