Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // A Tuple is a generic templatized container, similar in concept to std::pair
      6 // and std::tuple.  The convenient MakeTuple() function takes any number of
      7 // arguments and will construct and return the appropriate Tuple object.  The
      8 // functions DispatchToMethod and DispatchToFunction take a function pointer or
      9 // instance and method pointer, and unpack a tuple into arguments to the call.
     10 //
     11 // Tuple elements are copied by value, and stored in the tuple.  See the unit
     12 // tests for more details of how/when the values are copied.
     13 //
     14 // Example usage:
     15 //   // These two methods of creating a Tuple are identical.
     16 //   Tuple<int, const char*> tuple_a(1, "wee");
     17 //   Tuple<int, const char*> tuple_b = MakeTuple(1, "wee");
     18 //
     19 //   void SomeFunc(int a, const char* b) { }
     20 //   DispatchToFunction(&SomeFunc, tuple_a);  // SomeFunc(1, "wee")
     21 //   DispatchToFunction(
     22 //       &SomeFunc, MakeTuple(10, "foo"));    // SomeFunc(10, "foo")
     23 //
     24 //   struct { void SomeMeth(int a, int b, int c) { } } foo;
     25 //   DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3));
     26 //   // foo->SomeMeth(1, 2, 3);
     27 
     28 #ifndef BASE_TUPLE_H_
     29 #define BASE_TUPLE_H_
     30 
     31 #include <stddef.h>
     32 
     33 #include "base/bind_helpers.h"
     34 #include "build/build_config.h"
     35 
     36 namespace base {
     37 
     38 // Index sequences
     39 //
     40 // Minimal clone of the similarly-named C++14 functionality.
     41 
     42 template <size_t...>
     43 struct IndexSequence {};
     44 
     45 template <size_t... Ns>
     46 struct MakeIndexSequenceImpl;
     47 
     48 #if defined(_PREFAST_) && defined(OS_WIN)
     49 
     50 // Work around VC++ 2013 /analyze internal compiler error:
     51 // https://connect.microsoft.com/VisualStudio/feedback/details/1053626
     52 
     53 template <> struct MakeIndexSequenceImpl<0> {
     54   using Type = IndexSequence<>;
     55 };
     56 template <> struct MakeIndexSequenceImpl<1> {
     57   using Type = IndexSequence<0>;
     58 };
     59 template <> struct MakeIndexSequenceImpl<2> {
     60   using Type = IndexSequence<0,1>;
     61 };
     62 template <> struct MakeIndexSequenceImpl<3> {
     63   using Type = IndexSequence<0,1,2>;
     64 };
     65 template <> struct MakeIndexSequenceImpl<4> {
     66   using Type = IndexSequence<0,1,2,3>;
     67 };
     68 template <> struct MakeIndexSequenceImpl<5> {
     69   using Type = IndexSequence<0,1,2,3,4>;
     70 };
     71 template <> struct MakeIndexSequenceImpl<6> {
     72   using Type = IndexSequence<0,1,2,3,4,5>;
     73 };
     74 template <> struct MakeIndexSequenceImpl<7> {
     75   using Type = IndexSequence<0,1,2,3,4,5,6>;
     76 };
     77 template <> struct MakeIndexSequenceImpl<8> {
     78   using Type = IndexSequence<0,1,2,3,4,5,6,7>;
     79 };
     80 template <> struct MakeIndexSequenceImpl<9> {
     81   using Type = IndexSequence<0,1,2,3,4,5,6,7,8>;
     82 };
     83 template <> struct MakeIndexSequenceImpl<10> {
     84   using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9>;
     85 };
     86 template <> struct MakeIndexSequenceImpl<11> {
     87   using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10>;
     88 };
     89 template <> struct MakeIndexSequenceImpl<12> {
     90   using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11>;
     91 };
     92 template <> struct MakeIndexSequenceImpl<13> {
     93   using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11,12>;
     94 };
     95 
     96 #else  // defined(WIN) && defined(_PREFAST_)
     97 
     98 template <size_t... Ns>
     99 struct MakeIndexSequenceImpl<0, Ns...> {
    100   using Type = IndexSequence<Ns...>;
    101 };
    102 
    103 template <size_t N, size_t... Ns>
    104 struct MakeIndexSequenceImpl<N, Ns...>
    105     : MakeIndexSequenceImpl<N - 1, N - 1, Ns...> {};
    106 
    107 #endif  // defined(WIN) && defined(_PREFAST_)
    108 
    109 template <size_t N>
    110 using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type;
    111 
    112 // Traits ----------------------------------------------------------------------
    113 //
    114 // A simple traits class for tuple arguments.
    115 //
    116 // ValueType: the bare, nonref version of a type (same as the type for nonrefs).
    117 // RefType: the ref version of a type (same as the type for refs).
    118 // ParamType: what type to pass to functions (refs should not be constified).
    119 
    120 template <class P>
    121 struct TupleTraits {
    122   typedef P ValueType;
    123   typedef P& RefType;
    124   typedef const P& ParamType;
    125 };
    126 
    127 template <class P>
    128 struct TupleTraits<P&> {
    129   typedef P ValueType;
    130   typedef P& RefType;
    131   typedef P& ParamType;
    132 };
    133 
    134 // Tuple -----------------------------------------------------------------------
    135 //
    136 // This set of classes is useful for bundling 0 or more heterogeneous data types
    137 // into a single variable.  The advantage of this is that it greatly simplifies
    138 // function objects that need to take an arbitrary number of parameters; see
    139 // RunnableMethod and IPC::MessageWithTuple.
    140 //
    141 // Tuple<> is supplied to act as a 'void' type.  It can be used, for example,
    142 // when dispatching to a function that accepts no arguments (see the
    143 // Dispatchers below).
    144 // Tuple<A> is rarely useful.  One such use is when A is non-const ref that you
    145 // want filled by the dispatchee, and the tuple is merely a container for that
    146 // output (a "tier").  See MakeRefTuple and its usages.
    147 
    148 template <typename IxSeq, typename... Ts>
    149 struct TupleBaseImpl;
    150 template <typename... Ts>
    151 using TupleBase = TupleBaseImpl<MakeIndexSequence<sizeof...(Ts)>, Ts...>;
    152 template <size_t N, typename T>
    153 struct TupleLeaf;
    154 
    155 template <typename... Ts>
    156 struct Tuple final : TupleBase<Ts...> {
    157   Tuple() : TupleBase<Ts...>() {}
    158   explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
    159       : TupleBase<Ts...>(args...) {}
    160 };
    161 
    162 // Avoids ambiguity between Tuple's two constructors.
    163 template <>
    164 struct Tuple<> final {};
    165 
    166 template <size_t... Ns, typename... Ts>
    167 struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
    168   TupleBaseImpl() : TupleLeaf<Ns, Ts>()... {}
    169   explicit TupleBaseImpl(typename TupleTraits<Ts>::ParamType... args)
    170       : TupleLeaf<Ns, Ts>(args)... {}
    171 };
    172 
    173 template <size_t N, typename T>
    174 struct TupleLeaf {
    175   TupleLeaf() {}
    176   explicit TupleLeaf(typename TupleTraits<T>::ParamType x) : x(x) {}
    177 
    178   T& get() { return x; }
    179   const T& get() const { return x; }
    180 
    181   T x;
    182 };
    183 
    184 // Tuple getters --------------------------------------------------------------
    185 //
    186 // Allows accessing an arbitrary tuple element by index.
    187 //
    188 // Example usage:
    189 //   base::Tuple<int, double> t2;
    190 //   base::get<0>(t2) = 42;
    191 //   base::get<1>(t2) = 3.14;
    192 
    193 template <size_t I, typename T>
    194 T& get(TupleLeaf<I, T>& leaf) {
    195   return leaf.get();
    196 }
    197 
    198 template <size_t I, typename T>
    199 const T& get(const TupleLeaf<I, T>& leaf) {
    200   return leaf.get();
    201 }
    202 
    203 // Tuple types ----------------------------------------------------------------
    204 //
    205 // Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
    206 // definitions of class types the tuple takes as parameters.
    207 
    208 template <typename T>
    209 struct TupleTypes;
    210 
    211 template <typename... Ts>
    212 struct TupleTypes<Tuple<Ts...>> {
    213   using ValueTuple = Tuple<typename TupleTraits<Ts>::ValueType...>;
    214   using RefTuple = Tuple<typename TupleTraits<Ts>::RefType...>;
    215   using ParamTuple = Tuple<typename TupleTraits<Ts>::ParamType...>;
    216 };
    217 
    218 // Tuple creators -------------------------------------------------------------
    219 //
    220 // Helper functions for constructing tuples while inferring the template
    221 // argument types.
    222 
    223 template <typename... Ts>
    224 inline Tuple<Ts...> MakeTuple(const Ts&... arg) {
    225   return Tuple<Ts...>(arg...);
    226 }
    227 
    228 // The following set of helpers make what Boost refers to as "Tiers" - a tuple
    229 // of references.
    230 
    231 template <typename... Ts>
    232 inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) {
    233   return Tuple<Ts&...>(arg...);
    234 }
    235 
    236 // Dispatchers ----------------------------------------------------------------
    237 //
    238 // Helper functions that call the given method on an object, with the unpacked
    239 // tuple arguments.  Notice that they all have the same number of arguments,
    240 // so you need only write:
    241 //   DispatchToMethod(object, &Object::method, args);
    242 // This is very useful for templated dispatchers, since they don't need to know
    243 // what type |args| is.
    244 
    245 // Non-Static Dispatchers with no out params.
    246 
    247 template <typename ObjT, typename Method, typename... Ts, size_t... Ns>
    248 inline void DispatchToMethodImpl(ObjT* obj,
    249                                  Method method,
    250                                  const Tuple<Ts...>& arg,
    251                                  IndexSequence<Ns...>) {
    252   (obj->*method)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
    253 }
    254 
    255 template <typename ObjT, typename Method, typename... Ts>
    256 inline void DispatchToMethod(ObjT* obj,
    257                              Method method,
    258                              const Tuple<Ts...>& arg) {
    259   DispatchToMethodImpl(obj, method, arg, MakeIndexSequence<sizeof...(Ts)>());
    260 }
    261 
    262 // Static Dispatchers with no out params.
    263 
    264 template <typename Function, typename... Ts, size_t... Ns>
    265 inline void DispatchToFunctionImpl(Function function,
    266                                    const Tuple<Ts...>& arg,
    267                                    IndexSequence<Ns...>) {
    268   (*function)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
    269 }
    270 
    271 template <typename Function, typename... Ts>
    272 inline void DispatchToFunction(Function function, const Tuple<Ts...>& arg) {
    273   DispatchToFunctionImpl(function, arg, MakeIndexSequence<sizeof...(Ts)>());
    274 }
    275 
    276 // Dispatchers with out parameters.
    277 
    278 template <typename ObjT,
    279           typename Method,
    280           typename... InTs,
    281           typename... OutTs,
    282           size_t... InNs,
    283           size_t... OutNs>
    284 inline void DispatchToMethodImpl(ObjT* obj,
    285                                  Method method,
    286                                  const Tuple<InTs...>& in,
    287                                  Tuple<OutTs...>* out,
    288                                  IndexSequence<InNs...>,
    289                                  IndexSequence<OutNs...>) {
    290   (obj->*method)(base::internal::UnwrapTraits<InTs>::Unwrap(get<InNs>(in))...,
    291                  &get<OutNs>(*out)...);
    292 }
    293 
    294 template <typename ObjT, typename Method, typename... InTs, typename... OutTs>
    295 inline void DispatchToMethod(ObjT* obj,
    296                              Method method,
    297                              const Tuple<InTs...>& in,
    298                              Tuple<OutTs...>* out) {
    299   DispatchToMethodImpl(obj, method, in, out,
    300                        MakeIndexSequence<sizeof...(InTs)>(),
    301                        MakeIndexSequence<sizeof...(OutTs)>());
    302 }
    303 
    304 }  // namespace base
    305 
    306 #endif  // BASE_TUPLE_H_
    307