LCOV - code coverage report
Current view: top level - mfbt - Tuple.h (source / functions) Hit Total Coverage
Test: output.info Lines: 42 66 63.6 %
Date: 2017-07-14 16:53:18 Functions: 363 3412 10.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* A variadic tuple class. */
       8             : 
       9             : #ifndef mozilla_Tuple_h
      10             : #define mozilla_Tuple_h
      11             : 
      12             : #include "mozilla/Move.h"
      13             : #include "mozilla/Pair.h"
      14             : #include "mozilla/TemplateLib.h"
      15             : #include "mozilla/TypeTraits.h"
      16             : 
      17             : #include <stddef.h>
      18             : #include <utility>
      19             : 
      20             : namespace mozilla {
      21             : 
      22             : namespace detail {
      23             : 
      24             : /*
      25             :  * A helper class that allows passing around multiple variadic argument lists
      26             :  * by grouping them.
      27             :  */
      28             : template<typename... Ts>
      29             : struct Group;
      30             : 
      31             : /*
      32             :  * CheckConvertibility checks whether each type in a source pack of types
      33             :  * is convertible to the corresponding type in a target pack of types.
      34             :  *
      35             :  * It is intended to be invoked like this:
      36             :  *   CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>>
      37             :  * 'Group' is used to separate types in the two packs (otherwise if we just
      38             :  * wrote 'CheckConvertibility<SourceTypes..., TargetTypes...', it couldn't
      39             :  * know where the first pack ends and the second begins).
      40             :  *
      41             :  * Note that we need to check explicitly that the two packs are of the same
      42             :  * size, because attempting to simultaneously expand two parameter packs
      43             :  * is an error (and it would be a hard error, because it wouldn't be in the
      44             :  * immediate context of the caller).
      45             :  */
      46             : 
      47             : template<typename Source, typename Target, bool SameSize>
      48             : struct CheckConvertibilityImpl;
      49             : 
      50             : template<typename Source, typename Target>
      51             : struct CheckConvertibilityImpl<Source, Target, false>
      52             :   : FalseType {};
      53             : 
      54             : template<typename... SourceTypes, typename... TargetTypes>
      55             : struct CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>, true>
      56             :   : IntegralConstant<bool, tl::And<IsConvertible<SourceTypes, TargetTypes>::value...>::value> { };
      57             : 
      58             : template<typename Source, typename Target>
      59             : struct CheckConvertibility;
      60             : 
      61             : template<typename... SourceTypes, typename... TargetTypes>
      62             : struct CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>>
      63             :   : CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>,
      64             :         sizeof...(SourceTypes) == sizeof...(TargetTypes)> { };
      65             : 
      66             : /*
      67             :  * TupleImpl is a helper class used to implement mozilla::Tuple.
      68             :  * It represents one node in a recursive inheritance hierarchy.
      69             :  * 'Index' is the 0-based index of the tuple element stored in this node;
      70             :  * 'Elements...' are the types of the elements stored in this node and its
      71             :  * base classes.
      72             :  *
      73             :  * Example:
      74             :  *   Tuple<int, float, char> inherits from
      75             :  *   TupleImpl<0, int, float, char>, which stores the 'int' and inherits from
      76             :  *   TupleImpl<1, float, char>, which stores the 'float' and inherits from
      77             :  *   TupleImpl<2, char>, which stores the 'char' and inherits from
      78             :  *   TupleImpl<3>, which stores nothing and terminates the recursion.
      79             :  *
      80             :  * The purpose of the 'Index' parameter is to allow efficient index-based
      81             :  * access to a tuple element: given a tuple, and an index 'I' that we wish to
      82             :  * access, we can cast the tuple to the base which stores the I'th element
      83             :  * by performing template argument deduction against 'TupleImpl<I, E...>',
      84             :  * where 'I' is specified explicitly and 'E...' is deduced (this is what the
      85             :  * non-member 'Get<N>(t)' function does).
      86             :  *
      87             :  * This implementation strategy is borrowed from libstdc++'s std::tuple
      88             :  * implementation.
      89             :  */
      90             : template<std::size_t Index, typename... Elements>
      91             : struct TupleImpl;
      92             : 
      93             : /*
      94             :  * The base case of the inheritance recursion (and also the implementation
      95             :  * of an empty tuple).
      96             :  */
      97             : template<std::size_t Index>
      98             : struct TupleImpl<Index> {
      99           0 :   bool operator==(const TupleImpl<Index>& aOther) const
     100             :   {
     101           0 :     return true;
     102             :   }
     103             : };
     104             : 
     105             : /*
     106             :  * One node of the recursive inheritance hierarchy. It stores the element at
     107             :  * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes
     108             :  * that store the remaining elements, of types 'TailT...'.
     109             :  */
     110             : template<std::size_t Index, typename HeadT, typename... TailT>
     111          74 : struct TupleImpl<Index, HeadT, TailT...>
     112             :   : public TupleImpl<Index + 1, TailT...>
     113             : {
     114             :   typedef TupleImpl<Index + 1, TailT...> Base;
     115             : 
     116             :   // Accessors for the head and the tail.
     117             :   // These are static, because the intended usage is for the caller to,
     118             :   // given a tuple, obtain the type B of the base class which stores the
     119             :   // element of interest, and then call B::Head(tuple) to access it.
     120             :   // (Tail() is mostly for internal use, but is exposed for consistency.)
     121        3174 :   static HeadT& Head(TupleImpl& aTuple) { return aTuple.mHead; }
     122           0 :   static const HeadT& Head(const TupleImpl& aTuple) { return aTuple.mHead; }
     123        1905 :   static Base& Tail(TupleImpl& aTuple) { return aTuple; }
     124           0 :   static const Base& Tail(const TupleImpl& aTuple) { return aTuple; }
     125             : 
     126             :   TupleImpl() : Base(), mHead() { }
     127             : 
     128             :   // Construct from const references to the elements.
     129         985 :   explicit TupleImpl(const HeadT& aHead, const TailT&... aTail)
     130         985 :     : Base(aTail...), mHead(aHead) { }
     131             : 
     132             :   // Construct from objects that are convertible to the elements.
     133             :   // This constructor is enabled only when the argument types are actually
     134             :   // convertible to the element types, otherwise it could become a better
     135             :   // match for certain invocations than the copy constructor.
     136             :   template <typename OtherHeadT, typename... OtherTailT,
     137             :             typename = typename EnableIf<
     138             :                 CheckConvertibility<
     139             :                     Group<OtherHeadT, OtherTailT...>,
     140             :                     Group<HeadT, TailT...>>::value>::Type>
     141        2186 :   explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail)
     142        2186 :     : Base(Forward<OtherTailT>(aTail)...), mHead(Forward<OtherHeadT>(aHead)) { }
     143             : 
     144             :   // Copy and move constructors.
     145             :   // We'd like to use '= default' to implement these, but MSVC 2013's support
     146             :   // for '= default' is incomplete and this doesn't work.
     147           0 :   TupleImpl(const TupleImpl& aOther)
     148           0 :     : Base(Tail(aOther))
     149           0 :     , mHead(Head(aOther)) {}
     150           7 :   TupleImpl(TupleImpl&& aOther)
     151           7 :     : Base(Move(Tail(aOther)))
     152           7 :     , mHead(Forward<HeadT>(Head(aOther))) {}
     153             : 
     154             :   // Assign from a tuple whose elements are convertible to the elements
     155             :   // of this tuple.
     156             :   template <typename... OtherElements,
     157             :             typename = typename EnableIf<
     158             :                 sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type>
     159             :   TupleImpl& operator=(const TupleImpl<Index, OtherElements...>& aOther)
     160             :   {
     161             :     typedef TupleImpl<Index, OtherElements...> OtherT;
     162             :     Head(*this) = OtherT::Head(aOther);
     163             :     Tail(*this) = OtherT::Tail(aOther);
     164             :     return *this;
     165             :   }
     166             :   template <typename... OtherElements,
     167             :             typename = typename EnableIf<
     168             :                 sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type>
     169         937 :   TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther)
     170             :   {
     171             :     typedef TupleImpl<Index, OtherElements...> OtherT;
     172         937 :     Head(*this) = Move(OtherT::Head(aOther));
     173         937 :     Tail(*this) = Move(OtherT::Tail(aOther));
     174         937 :     return *this;
     175             :   }
     176             : 
     177             :   // Copy and move assignment operators.
     178           0 :   TupleImpl& operator=(const TupleImpl& aOther)
     179             :   {
     180           0 :     Head(*this) = Head(aOther);
     181           0 :     Tail(*this) = Tail(aOther);
     182           0 :     return *this;
     183             :   }
     184             :   TupleImpl& operator=(TupleImpl&& aOther)
     185             :   {
     186             :     Head(*this) = Move(Head(aOther));
     187             :     Tail(*this) = Move(Tail(aOther));
     188             :     return *this;
     189             :   }
     190           0 :   bool operator==(const TupleImpl& aOther) const
     191             :   {
     192           0 :     return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther);
     193             :   }
     194             : private:
     195             :   HeadT mHead;  // The element stored at this index in the tuple.
     196             : };
     197             : 
     198             : } // namespace detail
     199             : 
     200             : /**
     201             :  * Tuple is a class that stores zero or more objects, whose types are specified
     202             :  * as template parameters. It can be thought of as a generalization of Pair,
     203             :  * (which can be thought of as a 2-tuple).
     204             :  *
     205             :  * Tuple allows index-based access to its elements (with the index having to be
     206             :  * known at compile time) via the non-member function 'Get<N>(tuple)'.
     207             :  */
     208             : template<typename... Elements>
     209          34 : class Tuple : public detail::TupleImpl<0, Elements...>
     210             : {
     211             :   typedef detail::TupleImpl<0, Elements...> Impl;
     212             : public:
     213             :   // The constructors and assignment operators here are simple wrappers
     214             :   // around those in TupleImpl.
     215             : 
     216             :   Tuple() : Impl() { }
     217         182 :   explicit Tuple(const Elements&... aElements) : Impl(aElements...) { }
     218             :   // Here, we can't just use 'typename... OtherElements' because MSVC will give
     219             :   // a warning "C4520: multiple default constructors specified" (even if no one
     220             :   // actually instantiates the constructor with an empty parameter pack -
     221             :   // that's probably a bug) and we compile with warnings-as-errors.
     222             :   template <typename OtherHead, typename... OtherTail,
     223             :             typename = typename EnableIf<
     224             :                 detail::CheckConvertibility<
     225             :                     detail::Group<OtherHead, OtherTail...>,
     226             :                     detail::Group<Elements...>>::value>::Type>
     227        1371 :   explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail)
     228        1371 :     : Impl(Forward<OtherHead>(aHead), Forward<OtherTail>(aTail)...) { }
     229           0 :   Tuple(const Tuple& aOther) : Impl(aOther) { }
     230           3 :   Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
     231             : 
     232             :   template <typename... OtherElements,
     233             :             typename = typename EnableIf<
     234             :                 sizeof...(OtherElements) == sizeof...(Elements)>::Type>
     235             :   Tuple& operator=(const Tuple<OtherElements...>& aOther)
     236             :   {
     237             :     static_cast<Impl&>(*this) = aOther;
     238             :     return *this;
     239             :   }
     240             :   template <typename... OtherElements,
     241             :             typename = typename EnableIf<
     242             :                 sizeof...(OtherElements) == sizeof...(Elements)>::Type>
     243         182 :   Tuple& operator=(Tuple<OtherElements...>&& aOther)
     244             :   {
     245         182 :     static_cast<Impl&>(*this) = Move(aOther);
     246         182 :     return *this;
     247             :   }
     248           0 :   Tuple& operator=(const Tuple& aOther)
     249             :   {
     250           0 :     static_cast<Impl&>(*this) = aOther;
     251           0 :     return *this;
     252             :   }
     253             :   Tuple& operator=(Tuple&& aOther)
     254             :   {
     255             :     static_cast<Impl&>(*this) = Move(aOther);
     256             :     return *this;
     257             :   }
     258           0 :   bool operator==(const Tuple& aOther) const
     259             :   {
     260           0 :     return static_cast<const Impl&>(*this) == static_cast<const Impl&>(aOther);
     261             :   }
     262             : };
     263             : 
     264             : /**
     265             :  * Specialization of Tuple for two elements.
     266             :  * This is created to support construction and assignment from a Pair or std::pair.
     267             :  */
     268             : template <typename A, typename B>
     269           8 : class Tuple<A, B> : public detail::TupleImpl<0, A, B>
     270             : {
     271             :   typedef detail::TupleImpl<0, A, B> Impl;
     272             : 
     273             : public:
     274             :   // The constructors and assignment operators here are simple wrappers
     275             :   // around those in TupleImpl.
     276             : 
     277             :   Tuple() : Impl() { }
     278         141 :   explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) { }
     279             :   template <typename AArg, typename BArg,
     280             :             typename = typename EnableIf<
     281             :                 detail::CheckConvertibility<
     282             :                     detail::Group<AArg, BArg>,
     283             :                     detail::Group<A, B>>::value>::Type>
     284         134 :   explicit Tuple(AArg&& aA, BArg&& aB)
     285         134 :     : Impl(Forward<AArg>(aA), Forward<BArg>(aB)) { }
     286           0 :   Tuple(const Tuple& aOther) : Impl(aOther) { }
     287           2 :   Tuple(Tuple&& aOther) : Impl(Move(aOther)) { }
     288             :   explicit Tuple(const Pair<A, B>& aOther)
     289             :     : Impl(aOther.first(), aOther.second()) { }
     290             :   explicit Tuple(Pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first()),
     291             :                                     Forward<B>(aOther.second())) { }
     292             :   explicit Tuple(const std::pair<A, B>& aOther)
     293             :     : Impl(aOther.first, aOther.second) { }
     294             :   explicit Tuple(std::pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first),
     295             :                                     Forward<B>(aOther.second)) { }
     296             : 
     297             :   template <typename AArg, typename BArg>
     298             :   Tuple& operator=(const Tuple<AArg, BArg>& aOther)
     299             :   {
     300             :     static_cast<Impl&>(*this) = aOther;
     301             :     return *this;
     302             :   }
     303             :   template <typename AArg, typename BArg>
     304         117 :   Tuple& operator=(Tuple<AArg, BArg>&& aOther)
     305             :   {
     306         117 :     static_cast<Impl&>(*this) = Move(aOther);
     307         117 :     return *this;
     308             :   }
     309             :   Tuple& operator=(const Tuple& aOther)
     310             :   {
     311             :     static_cast<Impl&>(*this) = aOther;
     312             :     return *this;
     313             :   }
     314             :   Tuple& operator=(Tuple&& aOther)
     315             :   {
     316             :     static_cast<Impl&>(*this) = Move(aOther);
     317             :     return *this;
     318             :   }
     319             :   template <typename AArg, typename BArg>
     320             :   Tuple& operator=(const Pair<AArg, BArg>& aOther)
     321             :   {
     322             :     Impl::Head(*this) = aOther.first();
     323             :     Impl::Tail(*this).Head(*this) = aOther.second();
     324             :     return *this;
     325             :   }
     326             :   template <typename AArg, typename BArg>
     327          24 :   Tuple& operator=(Pair<AArg, BArg>&& aOther)
     328             :   {
     329          24 :     Impl::Head(*this) = Forward<AArg>(aOther.first());
     330          24 :     Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second());
     331          24 :     return *this;
     332             :   }
     333             :   template <typename AArg, typename BArg>
     334             :   Tuple& operator=(const std::pair<AArg, BArg>& aOther)
     335             :   {
     336             :     Impl::Head(*this) = aOther.first;
     337             :     Impl::Tail(*this).Head(*this) = aOther.second;
     338             :     return *this;
     339             :   }
     340             :   template <typename AArg, typename BArg>
     341             :   Tuple& operator=(std::pair<AArg, BArg>&& aOther)
     342             :   {
     343             :     Impl::Head(*this) = Forward<AArg>(aOther.first);
     344             :     Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second);
     345             :     return *this;
     346             :   }
     347             : };
     348             : 
     349             : /**
     350             :  * Specialization of Tuple for zero arguments.
     351             :  * This is necessary because if the primary template were instantiated with
     352             :  * an empty parameter pack, the 'Tuple(Elements...)' constructors would
     353             :  * become illegal overloads of the default constructor.
     354             :  */
     355             : template <>
     356             : class Tuple<> {};
     357             : 
     358             : namespace detail {
     359             : 
     360             : /*
     361             :  * Helper functions for implementing Get<N>(tuple).
     362             :  * These functions take a TupleImpl<Index, Elements...>, with Index being
     363             :  * explicitly specified, and Elements being deduced. By passing a Tuple
     364             :  * object as argument, template argument deduction will do its magic and
     365             :  * cast the tuple to the base class which stores the element at Index.
     366             :  */
     367             : 
     368             : // Const reference version.
     369             : template<std::size_t Index, typename... Elements>
     370        1245 : auto TupleGetHelper(TupleImpl<Index, Elements...>& aTuple)
     371             :     -> decltype(TupleImpl<Index, Elements...>::Head(aTuple))
     372             : {
     373        1245 :   return TupleImpl<Index, Elements...>::Head(aTuple);
     374             : }
     375             : 
     376             : // Non-const reference version.
     377             : template<std::size_t Index, typename... Elements>
     378           0 : auto TupleGetHelper(const TupleImpl<Index, Elements...>& aTuple)
     379             :     -> decltype(TupleImpl<Index, Elements...>::Head(aTuple))
     380             : {
     381           0 :   return TupleImpl<Index, Elements...>::Head(aTuple);
     382             : }
     383             : 
     384             : } // namespace detail
     385             : 
     386             : /**
     387             :  * Index-based access to an element of a tuple.
     388             :  * The syntax is Get<Index>(tuple). The index is zero-based.
     389             :  *
     390             :  * Example:
     391             :  *
     392             :  * Tuple<int, float, char> t;
     393             :  * ...
     394             :  * float f = Get<1>(t);
     395             :  */
     396             : 
     397             : // Non-const reference version.
     398             : template<std::size_t Index, typename... Elements>
     399        1246 : auto Get(Tuple<Elements...>& aTuple)
     400             :     -> decltype(detail::TupleGetHelper<Index>(aTuple))
     401             : {
     402        1246 :   return detail::TupleGetHelper<Index>(aTuple);
     403             : }
     404             : 
     405             : // Const reference version.
     406             : template<std::size_t Index, typename... Elements>
     407           0 : auto Get(const Tuple<Elements...>& aTuple)
     408             :     -> decltype(detail::TupleGetHelper<Index>(aTuple))
     409             : {
     410           0 :   return detail::TupleGetHelper<Index>(aTuple);
     411             : }
     412             : 
     413             : // Rvalue reference version.
     414             : template<std::size_t Index, typename... Elements>
     415             : auto Get(Tuple<Elements...>&& aTuple)
     416             :     -> decltype(Move(mozilla::Get<Index>(aTuple)))
     417             : {
     418             :   // We need a 'mozilla::' qualification here to avoid
     419             :   // name lookup only finding the current function.
     420             :   return Move(mozilla::Get<Index>(aTuple));
     421             : }
     422             : 
     423             : /**
     424             :  * A convenience function for constructing a tuple out of a sequence of
     425             :  * values without specifying the type of the tuple.
     426             :  * The type of the tuple is deduced from the types of its elements.
     427             :  *
     428             :  * Example:
     429             :  *
     430             :  * auto tuple = MakeTuple(42, 0.5f, 'c');  // has type Tuple<int, float, char>
     431             :  */
     432             : template<typename... Elements>
     433             : inline Tuple<typename Decay<Elements>::Type...>
     434         305 : MakeTuple(Elements&&... aElements)
     435             : {
     436         305 :   return Tuple<typename Decay<Elements>::Type...>(Forward<Elements>(aElements)...);
     437             : }
     438             : 
     439             : /**
     440             :  * A convenience function for constructing a tuple of references to a
     441             :  * sequence of variables. Since assignments to the elements of the tuple
     442             :  * "go through" to the referenced variables, this can be used to "unpack"
     443             :  * a tuple into individual variables.
     444             :  *
     445             :  * Example:
     446             :  *
     447             :  * int i;
     448             :  * float f;
     449             :  * char c;
     450             :  * Tie(i, f, c) = FunctionThatReturnsATuple();
     451             :  */
     452             : template<typename... Elements>
     453             : inline Tuple<Elements&...>
     454         323 : Tie(Elements&... aVariables)
     455             : {
     456         323 :   return Tuple<Elements&...>(aVariables...);
     457             : }
     458             : 
     459             : } // namespace mozilla
     460             : 
     461             : #endif /* mozilla_Tuple_h */

Generated by: LCOV version 1.13