Bug 1185706 - support Tie() for mozilla::Pair. r=froydnj
authorLiang-Heng Chen <xeonchen@mozilla.com>
Fri, 24 Jul 2015 00:42:00 +0200
changeset 254652 7dee2347f114c1711a8debfa73d5c934b8b67e6b
parent 254651 bcc208c22c9ec08123ba024755d56b3e391416d2
child 254653 8f97241a0035b8183c9c2e96ed13c50356d728f9
push id29108
push userryanvm@gmail.com
push dateMon, 27 Jul 2015 14:12:01 +0000
treeherdermozilla-central@27ae736ef960 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1185706
milestone42.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 1185706 - support Tie() for mozilla::Pair. r=froydnj
mfbt/Tuple.h
mfbt/tests/TestTuple.cpp
--- a/mfbt/Tuple.h
+++ b/mfbt/Tuple.h
@@ -5,20 +5,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* A variadic tuple class. */
 
 #ifndef mozilla_Tuple_h
 #define mozilla_Tuple_h
 
 #include "mozilla/Move.h"
+#include "mozilla/Pair.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/TypeTraits.h"
 
 #include <stddef.h>
+#include <utility>
 
 namespace mozilla {
 
 namespace detail {
 
 /*
  * A helper class that allows passing around multiple variadic argument lists
  * by grouping them.
@@ -242,16 +244,101 @@ public:
   Tuple& operator=(Tuple&& aOther)
   {
     static_cast<Impl&>(*this) = Move(aOther);
     return *this;
   }
 };
 
 /**
+ * Specialization of Tuple for two elements.
+ * This is created to support construction and assignment from a Pair or std::pair.
+ */
+template <typename A, typename B>
+class Tuple<A, B> : public detail::TupleImpl<0, A, B>
+{
+  typedef detail::TupleImpl<0, A, B> Impl;
+
+public:
+  // The constructors and assignment operators here are simple wrappers
+  // around those in TupleImpl.
+
+  Tuple() : Impl() { }
+  explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) { }
+  template <typename AArg, typename BArg,
+            typename = typename EnableIf<
+                detail::CheckConvertibility<
+                    detail::Group<AArg, BArg>,
+                    detail::Group<A, B>>::value>::Type>
+  explicit Tuple(AArg&& aA, BArg&& aB)
+    : Impl(Forward<AArg>(aA), Forward<BArg>(aB)) { }
+  Tuple(const Tuple& aOther) : Impl(aOther) { }
+  Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
+  explicit Tuple(const Pair<A, B>& aOther)
+    : Impl(aOther.first(), aOther.second()) { }
+  explicit Tuple(Pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first()),
+                                    Forward<B>(aOther.second())) { }
+  explicit Tuple(const std::pair<A, B>& aOther)
+    : Impl(aOther.first, aOther.second) { }
+  explicit Tuple(std::pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first),
+                                    Forward<B>(aOther.second)) { }
+
+  template <typename AArg, typename BArg>
+  Tuple& operator=(const Tuple<AArg, BArg>& aOther)
+  {
+    static_cast<Impl&>(*this) = aOther;
+    return *this;
+  }
+  template <typename AArg, typename BArg>
+  Tuple& operator=(Tuple<AArg, BArg>&& aOther)
+  {
+    static_cast<Impl&>(*this) = Move(aOther);
+    return *this;
+  }
+  Tuple& operator=(const Tuple& aOther)
+  {
+    static_cast<Impl&>(*this) = aOther;
+    return *this;
+  }
+  Tuple& operator=(Tuple&& aOther)
+  {
+    static_cast<Impl&>(*this) = Move(aOther);
+    return *this;
+  }
+  template <typename AArg, typename BArg>
+  Tuple& operator=(const Pair<AArg, BArg>& aOther)
+  {
+    Impl::Head(*this) = aOther.first();
+    Impl::Tail(*this).Head(*this) = aOther.second();
+    return *this;
+  }
+  template <typename AArg, typename BArg>
+  Tuple& operator=(Pair<AArg, BArg>&& aOther)
+  {
+    Impl::Head(*this) = Forward<AArg>(aOther.first());
+    Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second());
+    return *this;
+  }
+  template <typename AArg, typename BArg>
+  Tuple& operator=(const std::pair<AArg, BArg>& aOther)
+  {
+    Impl::Head(*this) = aOther.first;
+    Impl::Tail(*this).Head(*this) = aOther.second;
+    return *this;
+  }
+  template <typename AArg, typename BArg>
+  Tuple& operator=(std::pair<AArg, BArg>&& aOther)
+  {
+    Impl::Head(*this) = Forward<AArg>(aOther.first);
+    Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second);
+    return *this;
+  }
+};
+
+/**
  * Specialization of Tuple for zero arguments.
  * This is necessary because if the primary template were instantiated with
  * an empty parameter pack, the 'Tuple(Elements...)' constructors would
  * become illegal overloads of the default constructor.
  */
 template <>
 class Tuple<> {};
 
--- a/mfbt/tests/TestTuple.cpp
+++ b/mfbt/tests/TestTuple.cpp
@@ -1,32 +1,36 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
    /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Move.h"
+#include "mozilla/Pair.h"
 #include "mozilla/Tuple.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/unused.h"
 
 #include <stddef.h>
+#include <utility>
 
 using mozilla::Get;
 using mozilla::IsSame;
 using mozilla::MakeTuple;
 using mozilla::MakeUnique;
 using mozilla::Move;
+using mozilla::Pair;
 using mozilla::Tie;
 using mozilla::Tuple;
 using mozilla::UniquePtr;
 using mozilla::unused;
+using std::pair;
 
 #define CHECK(c) \
   do { \
     bool cond = !!(c); \
     MOZ_RELEASE_ASSERT(cond, "Failed assertion: " #c); \
   } while (false)
 
 // The second argument is the expected type. It's variadic to allow the
@@ -74,16 +78,50 @@ TestConstruction()
   // Move construction
   Tuple<UniquePtr<int>> g{MakeUnique<int>(42)};
   Tuple<UniquePtr<int>> h{Move(g)};
   CHECK(Get<0>(g) == nullptr);
   CHECK(*Get<0>(h) == 42);
 }
 
 static void
+TestConstructionFromMozPair()
+{
+  // Construction from elements
+  int x = 1, y = 1;
+  Pair<int, int> a{x, y};
+  Pair<int&, const int&> b{x, y};
+  Tuple<int, int> c(a);
+  Tuple<int&, const int&> d(b);
+  x = 42;
+  y = 42;
+  CHECK(Get<0>(c) == 1);
+  CHECK(Get<1>(c) == 1);
+  CHECK(Get<0>(d) == 42);
+  CHECK(Get<1>(d) == 42);
+}
+
+static void
+TestConstructionFromStdPair()
+{
+  // Construction from elements
+  int x = 1, y = 1;
+  pair<int, int> a{x, y};
+  pair<int&, const int&> b{x, y};
+  Tuple<int, int> c(a);
+  Tuple<int&, const int&> d(b);
+  x = 42;
+  y = 42;
+  CHECK(Get<0>(c) == 1);
+  CHECK(Get<1>(c) == 1);
+  CHECK(Get<0>(d) == 42);
+  CHECK(Get<1>(d) == 42);
+}
+
+static void
 TestAssignment()
 {
   // Copy assignment
   Tuple<int> a{0};
   Tuple<int> b{42};
   a = b;
   CHECK(Get<0>(a) == 42);
 
@@ -99,16 +137,82 @@ TestAssignment()
   Tuple<UniquePtr<int>> e{MakeUnique<int>(0)};
   Tuple<UniquePtr<int>> f{MakeUnique<int>(42)};
   e = Move(f);
   CHECK(*Get<0>(e) == 42);
   CHECK(Get<0>(f) == nullptr);
 }
 
 static void
+TestAssignmentFromMozPair()
+{
+  // Copy assignment
+  Tuple<int, int> a{0, 0};
+  Pair<int, int> b{42, 42};
+  a = b;
+  CHECK(Get<0>(a) == 42);
+  CHECK(Get<1>(a) == 42);
+
+  // Assignment to reference member
+  int i = 0;
+  int j = 0;
+  int k = 42;
+  Tuple<int&, int&> c{i, j};
+  Pair<int&, int&> d{k, k};
+  c = d;
+  CHECK(i == 42);
+  CHECK(j == 42);
+
+  // Move assignment
+  Tuple<UniquePtr<int>, UniquePtr<int>> e{MakeUnique<int>(0),
+                                          MakeUnique<int>(0)};
+  Pair<UniquePtr<int>, UniquePtr<int>> f{MakeUnique<int>(42),
+                                         MakeUnique<int>(42)};
+  e = Move(f);
+  CHECK(*Get<0>(e) == 42);
+  CHECK(*Get<1>(e) == 42);
+  CHECK(f.first() == nullptr);
+  CHECK(f.second() == nullptr);
+}
+
+static void
+TestAssignmentFromStdPair()
+{
+  // Copy assignment
+  Tuple<int, int> a{0, 0};
+  pair<int, int> b{42, 42};
+  a = b;
+  CHECK(Get<0>(a) == 42);
+  CHECK(Get<1>(a) == 42);
+
+  // Assignment to reference member
+  int i = 0;
+  int j = 0;
+  int k = 42;
+  Tuple<int&, int&> c{i, j};
+  pair<int&, int&> d{k, k};
+  c = d;
+  CHECK(i == 42);
+  CHECK(j == 42);
+
+  // Move assignment.
+  Tuple<UniquePtr<int>, UniquePtr<int>> e{MakeUnique<int>(0), MakeUnique<int>(0)};
+  // XXX: On some platforms std::pair doesn't support move constructor.
+  pair<UniquePtr<int>, UniquePtr<int>> f;
+  f.first = MakeUnique<int>(42);
+  f.second = MakeUnique<int>(42);
+
+  e = Move(f);
+  CHECK(*Get<0>(e) == 42);
+  CHECK(*Get<1>(e) == 42);
+  CHECK(f.first == nullptr);
+  CHECK(f.second == nullptr);
+}
+
+static void
 TestGet()
 {
   int x = 1;
   int y = 2;
   int z = 3;
   Tuple<int, int&, const int&> tuple(x, y, z);
 
   // Using Get<>() to read elements
@@ -150,21 +254,37 @@ TestTie()
   CHECK(c == Get<2>(rhs1));
   // Test conversions
   Tuple<ConvertibleToInt, double, unsigned char> rhs2(ConvertibleToInt(),
       0.7f, 'd');
   Tie(i, f, c) = rhs2;
   CHECK(i == Get<0>(rhs2));
   CHECK(f == Get<1>(rhs2));
   CHECK(c == Get<2>(rhs2));
+
+  // Test Pair
+  Pair<int, float> rhs3(-1, 1.2f);
+  Tie(i, f) = rhs3;
+  CHECK(i == rhs3.first());
+  CHECK(f == rhs3.second());
+
+  pair<int, float> rhs4(42, 1.5f);
+  Tie(i, f) = rhs4;
+  CHECK(i == rhs4.first);
+  CHECK(f == rhs4.second);
+
   return true;
 }
 
 int
 main()
 {
   TestConstruction();
+  TestConstructionFromMozPair();
+  TestConstructionFromStdPair();
   TestAssignment();
+  TestAssignmentFromMozPair();
+  TestAssignmentFromStdPair();
   TestGet();
   TestMakeTuple();
   TestTie();
   return 0;
 }