Bug 1254565 - Allow passing matchers as rvalues to Variant::match. r=froydnj
authorNick Fitzgerald <fitzgen@gmail.com>
Thu, 10 Mar 2016 13:35:00 -0500
changeset 326083 4dccba6aa5a2dc57f24112edd57295bc880a9e33
parent 326082 3fd66d7ceea8718e57e897d1bdd010527c9ff6ce
child 326084 ecef715b50bfb373674f7fd477b2feac5c25c696
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1254565
milestone48.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 1254565 - Allow passing matchers as rvalues to Variant::match. r=froydnj
mfbt/Variant.h
mfbt/tests/TestVariant.cpp
--- a/mfbt/Variant.h
+++ b/mfbt/Variant.h
@@ -164,19 +164,20 @@ struct VariantImplementation<N, T> {
   }
 
   template<typename Variant>
   static bool
   equal(const Variant& aLhs, const Variant& aRhs) {
       return aLhs.template as<T>() == aRhs.template as<T>();
   }
 
-  template<typename Matcher, typename ConcreteVariant>
-  static typename Matcher::ReturnType
-  match(Matcher& aMatcher, ConcreteVariant& aV) {
+  template<typename Matcher, typename ConcreteVariant,
+           typename ReturnType = typename RemoveReference<Matcher>::Type::ReturnType>
+  static ReturnType
+  match(Matcher&& aMatcher, ConcreteVariant& aV) {
     return aMatcher.match(aV.template as<T>());
   }
 };
 
 // VariantImplementation for some variant type T.
 template<size_t N, typename T, typename... Ts>
 struct VariantImplementation<N, T, Ts...>
 {
@@ -220,19 +221,20 @@ struct VariantImplementation<N, T, Ts...
     if (aLhs.template is<T>()) {
       MOZ_ASSERT(aRhs.template is<T>());
       return aLhs.template as<T>() == aRhs.template as<T>();
     } else {
       return Next::equal(aLhs, aRhs);
     }
   }
 
-  template<typename Matcher, typename ConcreteVariant>
-  static typename Matcher::ReturnType
-  match(Matcher& aMatcher, ConcreteVariant& aV)
+  template<typename Matcher, typename ConcreteVariant,
+           typename ReturnType = typename RemoveReference<Matcher>::Type::ReturnType>
+  static ReturnType
+  match(Matcher&& aMatcher, ConcreteVariant& aV)
   {
     if (aV.template is<T>()) {
       return aMatcher.match(aV.template as<T>());
     } else {
       // If you're seeing compilation errors here like "no matching
       // function for call to 'match'" then that means that the
       // Matcher doesn't exhaust all variant types. There must exist a
       // Matcher::match(T&) for every variant type T.
@@ -547,29 +549,29 @@ public:
   template<typename T>
   T extract() {
     static_assert(detail::IsVariant<T, Ts...>::value,
                   "provided a type not found in this Variant's type list");
     MOZ_ASSERT(is<T>());
     return T(Move(as<T>()));
   }
 
-  // Exhaustive matching of all variant types no the contained value.
+  // Exhaustive matching of all variant types on the contained value.
 
   /** Match on an immutable const reference. */
   template<typename Matcher>
-  typename Matcher::ReturnType
-  match(Matcher& aMatcher) const {
+  typename RemoveReference<Matcher>::Type::ReturnType
+  match(Matcher&& aMatcher) const {
     return Impl::match(aMatcher, *this);
   }
 
-  /**  Match on a mutable non-const reference. */
+  /** Match on a mutable non-const reference. */
   template<typename Matcher>
-  typename Matcher::ReturnType
-  match(Matcher& aMatcher) {
+  typename RemoveReference<Matcher>::Type::ReturnType
+  match(Matcher&& aMatcher) {
     return Impl::match(aMatcher, *this);
   }
 };
 
 /*
  * AsVariant() is used to construct a Variant<T,...> value containing the
  * provided T value using type inference. It can be used to construct Variant
  * values in expressions or return them from functions without specifying the
--- a/mfbt/tests/TestVariant.cpp
+++ b/mfbt/tests/TestVariant.cpp
@@ -160,21 +160,31 @@ testMatching()
   const V& constRef2 = v2;
   const V& constRef3 = v3;
 
   MOZ_RELEASE_ASSERT(constRef1.match(desc) == Describer::little);
   MOZ_RELEASE_ASSERT(constRef2.match(desc) == Describer::medium);
   MOZ_RELEASE_ASSERT(constRef3.match(desc) == Describer::big);
 }
 
+static void
+testRvalueMatcher()
+{
+  printf("testRvalueMatcher\n");
+  using V = Variant<uint8_t, uint32_t, uint64_t>;
+  V v(uint8_t(1));
+  MOZ_RELEASE_ASSERT(v.match(Describer()) == Describer::little);
+}
+
 int
 main()
 {
   testSimple();
   testCopy();
   testMove();
   testDestructor();
   testEquality();
   testMatching();
+  testRvalueMatcher();
 
   printf("TestVariant OK!\n");
   return 0;
 }