tuple: further generalize/simplify Tuple implementation

Instead of specially implementing Tuple for 0 to 8 arguments, use a
more traditional implementation by having Tuple<A, B, ...> inherit
from TupleLeaf<0, A>, TupleLeaf<1, B>, etc.  This allows Tuple to be
used with an arbitrary number of arguments.

To remain backwards compatible with code that accesses "t.a", "t.b",
etc., we specialize TupleLeaf for the first 8 elements to store their
values in appropriately named member variables.  These accessors work
even for Tuples with more than 8 elements, but the 9th element and
beyond are only supported with get<N>().

Review URL: https://codereview.chromium.org/792763002

Cr-Commit-Position: refs/heads/master@{#307681}
diff --git a/base/tuple.h b/base/tuple.h
index 16f5124..885413f7 100644
--- a/base/tuple.h
+++ b/base/tuple.h
@@ -2,20 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// A Tuple is a generic templatized container, similar in concept to std::pair.
-// There are classes Tuple0 to Tuple6, cooresponding to the number of elements
-// it contains.  The convenient MakeTuple() function takes 0 to 6 arguments,
-// and will construct and return the appropriate Tuple object.  The functions
-// DispatchToMethod and DispatchToFunction take a function pointer or instance
-// and method pointer, and unpack a tuple into arguments to the call.
+// A Tuple is a generic templatized container, similar in concept to std::pair
+// and std::tuple.  The convenient MakeTuple() function takes any number of
+// arguments and will construct and return the appropriate Tuple object.  The
+// functions DispatchToMethod and DispatchToFunction take a function pointer or
+// instance and method pointer, and unpack a tuple into arguments to the call.
 //
 // Tuple elements are copied by value, and stored in the tuple.  See the unit
 // tests for more details of how/when the values are copied.
 //
 // Example usage:
 //   // These two methods of creating a Tuple are identical.
-//   Tuple2<int, const char*> tuple_a(1, "wee");
-//   Tuple2<int, const char*> tuple_b = MakeTuple(1, "wee");
+//   Tuple<int, const char*> tuple_a(1, "wee");
+//   Tuple<int, const char*> tuple_b = MakeTuple(1, "wee");
 //
 //   void SomeFunc(int a, const char* b) { }
 //   DispatchToFunction(&SomeFunc, tuple_a);  // SomeFunc(1, "wee")
@@ -47,9 +46,8 @@
 };
 
 template <size_t N, size_t... Ns>
-struct MakeIndexSequenceImpl<N, Ns...> {
-  using Type = typename MakeIndexSequenceImpl<N - 1, N - 1, Ns...>::Type;
-};
+struct MakeIndexSequenceImpl<N, Ns...>
+    : MakeIndexSequenceImpl<N - 1, N - 1, Ns...> {};
 
 template <size_t N>
 using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type;
@@ -83,217 +81,77 @@
 // function objects that need to take an arbitrary number of parameters; see
 // RunnableMethod and IPC::MessageWithTuple.
 //
-// Tuple0 is supplied to act as a 'void' type.  It can be used, for example,
+// Tuple<> is supplied to act as a 'void' type.  It can be used, for example,
 // when dispatching to a function that accepts no arguments (see the
 // Dispatchers below).
-// Tuple1<A> is rarely useful.  One such use is when A is non-const ref that you
+// Tuple<A> is rarely useful.  One such use is when A is non-const ref that you
 // want filled by the dispatchee, and the tuple is merely a container for that
 // output (a "tier").  See MakeRefTuple and its usages.
 
+template <typename IxSeq, typename... Ts>
+struct TupleBaseImpl;
 template <typename... Ts>
-struct Tuple;
+using TupleBase = TupleBaseImpl<MakeIndexSequence<sizeof...(Ts)>, Ts...>;
+template <size_t N, typename T>
+struct TupleLeaf;
 
+template <typename... Ts>
+struct Tuple : TupleBase<Ts...> {
+  Tuple() : TupleBase<Ts...>() {}
+  explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
+      : TupleBase<Ts...>(args...) {}
+};
+
+// Avoids ambiguity between Tuple's two constructors.
 template <>
 struct Tuple<> {};
 
-template <typename A>
-struct Tuple<A> {
- public:
-  typedef A TypeA;
-
-  Tuple() {}
-  explicit Tuple(typename TupleTraits<A>::ParamType a) : a(a) {}
-
-  A a;
+template <size_t... Ns, typename... Ts>
+struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
+  TupleBaseImpl() : TupleLeaf<Ns, Ts>()... {}
+  explicit TupleBaseImpl(typename TupleTraits<Ts>::ParamType... args)
+      : TupleLeaf<Ns, Ts>(args)... {}
 };
 
-template <typename A, typename B>
-struct Tuple<A, B> {
- public:
-  typedef A TypeA;
-  typedef B TypeB;
+template <size_t N, typename T>
+struct TupleLeaf {
+  TupleLeaf() : x() {}
+  explicit TupleLeaf(typename TupleTraits<T>::ParamType x) : x(x) {}
 
-  Tuple() {}
-  Tuple(typename TupleTraits<A>::ParamType a,
-        typename TupleTraits<B>::ParamType b)
-      : a(a), b(b) {}
+  T& get() { return x; }
+  const T& get() const { return x; }
 
-  A a;
-  B b;
+  T x;
 };
 
-template <typename A, typename B, typename C>
-struct Tuple<A, B, C> {
- public:
-  typedef A TypeA;
-  typedef B TypeB;
-  typedef C TypeC;
+// For legacy compatibility, we name the first 8 tuple elements "a", "b", ...
+// TODO(mdempsky): Update users to use get<N>() (crbug.com/440675).
 
-  Tuple() {}
-  Tuple(typename TupleTraits<A>::ParamType a,
-        typename TupleTraits<B>::ParamType b,
-        typename TupleTraits<C>::ParamType c)
-      : a(a), b(b), c(c) {}
+#define DEFINE_TUPLE_LEAF(N, x)                                        \
+  template <typename T>                                                \
+  struct TupleLeaf<N, T> {                                             \
+    TupleLeaf() : x() {}                                               \
+    explicit TupleLeaf(typename TupleTraits<T>::ParamType x) : x(x) {} \
+                                                                       \
+    T& get() { return x; }                                             \
+    const T& get() const { return x; }                                 \
+                                                                       \
+    T x;                                                               \
+  }
 
-  A a;
-  B b;
-  C c;
-};
+DEFINE_TUPLE_LEAF(0, a);
+DEFINE_TUPLE_LEAF(1, b);
+DEFINE_TUPLE_LEAF(2, c);
+DEFINE_TUPLE_LEAF(3, d);
+DEFINE_TUPLE_LEAF(4, e);
+DEFINE_TUPLE_LEAF(5, f);
+DEFINE_TUPLE_LEAF(6, g);
+DEFINE_TUPLE_LEAF(7, h);
 
-template <typename A, typename B, typename C, typename D>
-struct Tuple<A, B, C, D> {
- public:
-  typedef A TypeA;
-  typedef B TypeB;
-  typedef C TypeC;
-  typedef D TypeD;
-
-  Tuple() {}
-  Tuple(typename TupleTraits<A>::ParamType a,
-        typename TupleTraits<B>::ParamType b,
-        typename TupleTraits<C>::ParamType c,
-        typename TupleTraits<D>::ParamType d)
-      : a(a), b(b), c(c), d(d) {}
-
-  A a;
-  B b;
-  C c;
-  D d;
-};
-
-template <typename A, typename B, typename C, typename D, typename E>
-struct Tuple<A, B, C, D, E> {
- public:
-  typedef A TypeA;
-  typedef B TypeB;
-  typedef C TypeC;
-  typedef D TypeD;
-  typedef E TypeE;
-
-  Tuple() {}
-  Tuple(typename TupleTraits<A>::ParamType a,
-        typename TupleTraits<B>::ParamType b,
-        typename TupleTraits<C>::ParamType c,
-        typename TupleTraits<D>::ParamType d,
-        typename TupleTraits<E>::ParamType e)
-      : a(a), b(b), c(c), d(d), e(e) {}
-
-  A a;
-  B b;
-  C c;
-  D d;
-  E e;
-};
-
-template <typename A,
-          typename B,
-          typename C,
-          typename D,
-          typename E,
-          typename F>
-struct Tuple<A, B, C, D, E, F> {
- public:
-  typedef A TypeA;
-  typedef B TypeB;
-  typedef C TypeC;
-  typedef D TypeD;
-  typedef E TypeE;
-  typedef F TypeF;
-
-  Tuple() {}
-  Tuple(typename TupleTraits<A>::ParamType a,
-        typename TupleTraits<B>::ParamType b,
-        typename TupleTraits<C>::ParamType c,
-        typename TupleTraits<D>::ParamType d,
-        typename TupleTraits<E>::ParamType e,
-        typename TupleTraits<F>::ParamType f)
-      : a(a), b(b), c(c), d(d), e(e), f(f) {}
-
-  A a;
-  B b;
-  C c;
-  D d;
-  E e;
-  F f;
-};
-
-template <typename A,
-          typename B,
-          typename C,
-          typename D,
-          typename E,
-          typename F,
-          typename G>
-struct Tuple<A, B, C, D, E, F, G> {
- public:
-  typedef A TypeA;
-  typedef B TypeB;
-  typedef C TypeC;
-  typedef D TypeD;
-  typedef E TypeE;
-  typedef F TypeF;
-  typedef G TypeG;
-
-  Tuple() {}
-  Tuple(typename TupleTraits<A>::ParamType a,
-        typename TupleTraits<B>::ParamType b,
-        typename TupleTraits<C>::ParamType c,
-        typename TupleTraits<D>::ParamType d,
-        typename TupleTraits<E>::ParamType e,
-        typename TupleTraits<F>::ParamType f,
-        typename TupleTraits<G>::ParamType g)
-      : a(a), b(b), c(c), d(d), e(e), f(f), g(g) {}
-
-  A a;
-  B b;
-  C c;
-  D d;
-  E e;
-  F f;
-  G g;
-};
-
-template <typename A,
-          typename B,
-          typename C,
-          typename D,
-          typename E,
-          typename F,
-          typename G,
-          typename H>
-struct Tuple<A, B, C, D, E, F, G, H> {
- public:
-  typedef A TypeA;
-  typedef B TypeB;
-  typedef C TypeC;
-  typedef D TypeD;
-  typedef E TypeE;
-  typedef F TypeF;
-  typedef G TypeG;
-  typedef H TypeH;
-
-  Tuple() {}
-  Tuple(typename TupleTraits<A>::ParamType a,
-        typename TupleTraits<B>::ParamType b,
-        typename TupleTraits<C>::ParamType c,
-        typename TupleTraits<D>::ParamType d,
-        typename TupleTraits<E>::ParamType e,
-        typename TupleTraits<F>::ParamType f,
-        typename TupleTraits<G>::ParamType g,
-        typename TupleTraits<H>::ParamType h)
-      : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {}
-
-  A a;
-  B b;
-  C c;
-  D d;
-  E e;
-  F f;
-  G g;
-  H h;
-};
+#undef DEFINE_TUPLE_LEAF
 
 // Deprecated compat aliases
+// TODO(mdempsky): Update users to just use Tuple instead (crbug.com/440675).
 
 using Tuple0 = Tuple<>;
 template <typename A>
@@ -331,91 +189,23 @@
           typename H>
 using Tuple8 = Tuple<A, B, C, D, E, F, G, H>;
 
-// Tuple element --------------------------------------------------------------
-
-template <size_t N, typename T>
-struct TupleElement;
-
-template <typename T, typename... Ts>
-struct TupleElement<0, Tuple<T, Ts...>> {
-  using Type = T;
-};
-
-template <size_t N, typename T, typename... Ts>
-struct TupleElement<N, Tuple<T, Ts...>> {
-  using Type = typename TupleElement<N - 1, Tuple<Ts...>>::Type;
-};
-
 // Tuple getters --------------------------------------------------------------
+//
+// Allows accessing an arbitrary tuple element by index.
+//
+// Example usage:
+//   Tuple<int, double> t2;
+//   get<0>(t2) = 42;
+//   get<1>(t2) = 3.14;
 
-template <size_t, typename T>
-struct TupleGetter;
-
-template <typename... Ts>
-struct TupleGetter<0, Tuple<Ts...>> {
-  using Elem = typename TupleElement<0, Tuple<Ts...>>::Type;
-  static Elem& Get(Tuple<Ts...>& t) { return t.a; }
-  static const Elem& Get(const Tuple<Ts...>& t) { return t.a; }
-};
-
-template <typename... Ts>
-struct TupleGetter<1, Tuple<Ts...>> {
-  using Elem = typename TupleElement<1, Tuple<Ts...>>::Type;
-  static Elem& Get(Tuple<Ts...>& t) { return t.b; }
-  static const Elem& Get(const Tuple<Ts...>& t) { return t.b; }
-};
-
-template <typename... Ts>
-struct TupleGetter<2, Tuple<Ts...>> {
-  using Elem = typename TupleElement<2, Tuple<Ts...>>::Type;
-  static Elem& Get(Tuple<Ts...>& t) { return t.c; }
-  static const Elem& Get(const Tuple<Ts...>& t) { return t.c; }
-};
-
-template <typename... Ts>
-struct TupleGetter<3, Tuple<Ts...>> {
-  using Elem = typename TupleElement<3, Tuple<Ts...>>::Type;
-  static Elem& Get(Tuple<Ts...>& t) { return t.d; }
-  static const Elem& Get(const Tuple<Ts...>& t) { return t.d; }
-};
-
-template <typename... Ts>
-struct TupleGetter<4, Tuple<Ts...>> {
-  using Elem = typename TupleElement<4, Tuple<Ts...>>::Type;
-  static Elem& Get(Tuple<Ts...>& t) { return t.e; }
-  static const Elem& Get(const Tuple<Ts...>& t) { return t.e; }
-};
-
-template <typename... Ts>
-struct TupleGetter<5, Tuple<Ts...>> {
-  using Elem = typename TupleElement<5, Tuple<Ts...>>::Type;
-  static Elem& Get(Tuple<Ts...>& t) { return t.f; }
-  static const Elem& Get(const Tuple<Ts...>& t) { return t.f; }
-};
-
-template <typename... Ts>
-struct TupleGetter<6, Tuple<Ts...>> {
-  using Elem = typename TupleElement<6, Tuple<Ts...>>::Type;
-  static Elem& Get(Tuple<Ts...>& t) { return t.g; }
-  static const Elem& Get(const Tuple<Ts...>& t) { return t.g; }
-};
-
-template <typename... Ts>
-struct TupleGetter<7, Tuple<Ts...>> {
-  using Elem = typename TupleElement<7, Tuple<Ts...>>::Type;
-  static Elem& Get(Tuple<Ts...>& t) { return t.h; }
-  static const Elem& Get(const Tuple<Ts...>& t) { return t.h; }
-};
-
-template <size_t I, typename... Ts>
-typename TupleElement<I, Tuple<Ts...>>::Type& get(Tuple<Ts...>& tuple) {
-  return TupleGetter<I, Tuple<Ts...>>::Get(tuple);
+template <size_t I, typename T>
+T& get(TupleLeaf<I, T>& leaf) {
+  return leaf.get();
 }
 
-template <size_t I, typename... Ts>
-const typename TupleElement<I, Tuple<Ts...>>::Type& get(
-    const Tuple<Ts...>& tuple) {
-  return TupleGetter<I, Tuple<Ts...>>::Get(tuple);
+template <size_t I, typename T>
+const T& get(const TupleLeaf<I, T>& leaf) {
+  return leaf.get();
 }
 
 // Tuple types ----------------------------------------------------------------