| /* -*- 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/. */ |
| |
| /* 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. |
| */ |
| template<typename... Ts> |
| struct Group; |
| |
| /* |
| * CheckConvertibility checks whether each type in a source pack of types |
| * is convertible to the corresponding type in a target pack of types. |
| * |
| * It is intended to be invoked like this: |
| * CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>> |
| * 'Group' is used to separate types in the two packs (otherwise if we just |
| * wrote 'CheckConvertibility<SourceTypes..., TargetTypes...', it couldn't |
| * know where the first pack ends and the second begins). |
| * |
| * Note that we need to check explicitly that the two packs are of the same |
| * size, because attempting to simultaneously expand two parameter packs |
| * is an error (and it would be a hard error, because it wouldn't be in the |
| * immediate context of the caller). |
| */ |
| |
| template<typename Source, typename Target, bool SameSize> |
| struct CheckConvertibilityImpl; |
| |
| template<typename Source, typename Target> |
| struct CheckConvertibilityImpl<Source, Target, false> |
| : FalseType {}; |
| |
| template<typename... SourceTypes, typename... TargetTypes> |
| struct CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>, true> |
| : IntegralConstant<bool, tl::And<IsConvertible<SourceTypes, TargetTypes>::value...>::value> { }; |
| |
| template<typename Source, typename Target> |
| struct CheckConvertibility; |
| |
| template<typename... SourceTypes, typename... TargetTypes> |
| struct CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>> |
| : CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>, |
| sizeof...(SourceTypes) == sizeof...(TargetTypes)> { }; |
| |
| /* |
| * TupleImpl is a helper class used to implement mozilla::Tuple. |
| * It represents one node in a recursive inheritance hierarchy. |
| * 'Index' is the 0-based index of the tuple element stored in this node; |
| * 'Elements...' are the types of the elements stored in this node and its |
| * base classes. |
| * |
| * Example: |
| * Tuple<int, float, char> inherits from |
| * TupleImpl<0, int, float, char>, which stores the 'int' and inherits from |
| * TupleImpl<1, float, char>, which stores the 'float' and inherits from |
| * TupleImpl<2, char>, which stores the 'char' and inherits from |
| * TupleImpl<3>, which stores nothing and terminates the recursion. |
| * |
| * The purpose of the 'Index' parameter is to allow efficient index-based |
| * access to a tuple element: given a tuple, and an index 'I' that we wish to |
| * access, we can cast the tuple to the base which stores the I'th element |
| * by performing template argument deduction against 'TupleImpl<I, E...>', |
| * where 'I' is specified explicitly and 'E...' is deduced (this is what the |
| * non-member 'Get<N>(t)' function does). |
| * |
| * This implementation strategy is borrowed from libstdc++'s std::tuple |
| * implementation. |
| */ |
| template<std::size_t Index, typename... Elements> |
| struct TupleImpl; |
| |
| /* |
| * The base case of the inheritance recursion (and also the implementation |
| * of an empty tuple). |
| */ |
| template<std::size_t Index> |
| struct TupleImpl<Index> {}; |
| |
| /* |
| * One node of the recursive inheritance hierarchy. It stores the element at |
| * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes |
| * that store the remaining elements, of types 'TailT...'. |
| */ |
| template<std::size_t Index, typename HeadT, typename... TailT> |
| struct TupleImpl<Index, HeadT, TailT...> |
| : public TupleImpl<Index + 1, TailT...> |
| { |
| typedef TupleImpl<Index + 1, TailT...> Base; |
| |
| // Accessors for the head and the tail. |
| // These are static, because the intended usage is for the caller to, |
| // given a tuple, obtain the type B of the base class which stores the |
| // element of interest, and then call B::Head(tuple) to access it. |
| // (Tail() is mostly for internal use, but is exposed for consistency.) |
| static HeadT& Head(TupleImpl& aTuple) { return aTuple.mHead; } |
| static const HeadT& Head(const TupleImpl& aTuple) { return aTuple.mHead; } |
| static Base& Tail(TupleImpl& aTuple) { return aTuple; } |
| static const Base& Tail(const TupleImpl& aTuple) { return aTuple; } |
| |
| TupleImpl() : Base(), mHead() { } |
| |
| // Construct from const references to the elements. |
| explicit TupleImpl(const HeadT& aHead, const TailT&... aTail) |
| : Base(aTail...), mHead(aHead) { } |
| |
| // Construct from objects that are convertible to the elements. |
| // This constructor is enabled only when the argument types are actually |
| // convertible to the element types, otherwise it could become a better |
| // match for certain invocations than the copy constructor. |
| template <typename OtherHeadT, typename... OtherTailT, |
| typename = typename EnableIf< |
| CheckConvertibility< |
| Group<OtherHeadT, OtherTailT...>, |
| Group<HeadT, TailT...>>::value>::Type> |
| explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail) |
| : Base(Forward<OtherTailT>(aTail)...), mHead(Forward<OtherHeadT>(aHead)) { } |
| |
| // Copy and move constructors. |
| // We'd like to use '= default' to implement these, but MSVC 2013's support |
| // for '= default' is incomplete and this doesn't work. |
| TupleImpl(const TupleImpl& aOther) |
| : Base(Tail(aOther)) |
| , mHead(Head(aOther)) {} |
| TupleImpl(TupleImpl&& aOther) |
| : Base(Move(Tail(aOther))) |
| , mHead(Forward<HeadT>(Head(aOther))) {} |
| |
| // Assign from a tuple whose elements are convertible to the elements |
| // of this tuple. |
| template <typename... OtherElements, |
| typename = typename EnableIf< |
| sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type> |
| TupleImpl& operator=(const TupleImpl<Index, OtherElements...>& aOther) |
| { |
| typedef TupleImpl<Index, OtherElements...> OtherT; |
| Head(*this) = OtherT::Head(aOther); |
| Tail(*this) = OtherT::Tail(aOther); |
| return *this; |
| } |
| template <typename... OtherElements, |
| typename = typename EnableIf< |
| sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type> |
| TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther) |
| { |
| typedef TupleImpl<Index, OtherElements...> OtherT; |
| Head(*this) = Move(OtherT::Head(aOther)); |
| Tail(*this) = Move(OtherT::Tail(aOther)); |
| return *this; |
| } |
| |
| // Copy and move assignment operators. |
| TupleImpl& operator=(const TupleImpl& aOther) |
| { |
| Head(*this) = Head(aOther); |
| Tail(*this) = Tail(aOther); |
| return *this; |
| } |
| TupleImpl& operator=(TupleImpl&& aOther) |
| { |
| Head(*this) = Move(Head(aOther)); |
| Tail(*this) = Move(Tail(aOther)); |
| return *this; |
| } |
| private: |
| HeadT mHead; // The element stored at this index in the tuple. |
| }; |
| |
| } // namespace detail |
| |
| /** |
| * Tuple is a class that stores zero or more objects, whose types are specified |
| * as template parameters. It can be thought of as a generalization of Pair, |
| * (which can be thought of as a 2-tuple). |
| * |
| * Tuple allows index-based access to its elements (with the index having to be |
| * known at compile time) via the non-member function 'Get<N>(tuple)'. |
| */ |
| template<typename... Elements> |
| class Tuple : public detail::TupleImpl<0, Elements...> |
| { |
| typedef detail::TupleImpl<0, Elements...> Impl; |
| public: |
| // The constructors and assignment operators here are simple wrappers |
| // around those in TupleImpl. |
| |
| Tuple() : Impl() { } |
| explicit Tuple(const Elements&... aElements) : Impl(aElements...) { } |
| // Here, we can't just use 'typename... OtherElements' because MSVC will give |
| // a warning "C4520: multiple default constructors specified" (even if no one |
| // actually instantiates the constructor with an empty parameter pack - |
| // that's probably a bug) and we compile with warnings-as-errors. |
| template <typename OtherHead, typename... OtherTail, |
| typename = typename EnableIf< |
| detail::CheckConvertibility< |
| detail::Group<OtherHead, OtherTail...>, |
| detail::Group<Elements...>>::value>::Type> |
| explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail) |
| : Impl(Forward<OtherHead>(aHead), Forward<OtherTail>(aTail)...) { } |
| Tuple(const Tuple& aOther) : Impl(aOther) { } |
| Tuple(Tuple&& aOther) : Impl(Move(aOther)) { } |
| |
| template <typename... OtherElements, |
| typename = typename EnableIf< |
| sizeof...(OtherElements) == sizeof...(Elements)>::Type> |
| Tuple& operator=(const Tuple<OtherElements...>& aOther) |
| { |
| static_cast<Impl&>(*this) = aOther; |
| return *this; |
| } |
| template <typename... OtherElements, |
| typename = typename EnableIf< |
| sizeof...(OtherElements) == sizeof...(Elements)>::Type> |
| Tuple& operator=(Tuple<OtherElements...>&& 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; |
| } |
| }; |
| |
| /** |
| * 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<> {}; |
| |
| namespace detail { |
| |
| /* |
| * Helper functions for implementing Get<N>(tuple). |
| * These functions take a TupleImpl<Index, Elements...>, with Index being |
| * explicitly specified, and Elements being deduced. By passing a Tuple |
| * object as argument, template argument deduction will do its magic and |
| * cast the tuple to the base class which stores the element at Index. |
| */ |
| |
| // Const reference version. |
| template<std::size_t Index, typename... Elements> |
| auto TupleGetHelper(TupleImpl<Index, Elements...>& aTuple) |
| -> decltype(TupleImpl<Index, Elements...>::Head(aTuple)) |
| { |
| return TupleImpl<Index, Elements...>::Head(aTuple); |
| } |
| |
| // Non-const reference version. |
| template<std::size_t Index, typename... Elements> |
| auto TupleGetHelper(const TupleImpl<Index, Elements...>& aTuple) |
| -> decltype(TupleImpl<Index, Elements...>::Head(aTuple)) |
| { |
| return TupleImpl<Index, Elements...>::Head(aTuple); |
| } |
| |
| } // namespace detail |
| |
| /** |
| * Index-based access to an element of a tuple. |
| * The syntax is Get<Index>(tuple). The index is zero-based. |
| * |
| * Example: |
| * |
| * Tuple<int, float, char> t; |
| * ... |
| * float f = Get<1>(t); |
| */ |
| |
| // Non-const reference version. |
| template<std::size_t Index, typename... Elements> |
| auto Get(Tuple<Elements...>& aTuple) |
| -> decltype(detail::TupleGetHelper<Index>(aTuple)) |
| { |
| return detail::TupleGetHelper<Index>(aTuple); |
| } |
| |
| // Const reference version. |
| template<std::size_t Index, typename... Elements> |
| auto Get(const Tuple<Elements...>& aTuple) |
| -> decltype(detail::TupleGetHelper<Index>(aTuple)) |
| { |
| return detail::TupleGetHelper<Index>(aTuple); |
| } |
| |
| // Rvalue reference version. |
| template<std::size_t Index, typename... Elements> |
| auto Get(Tuple<Elements...>&& aTuple) |
| -> decltype(Move(mozilla::Get<Index>(aTuple))) |
| { |
| // We need a 'mozilla::' qualification here to avoid |
| // name lookup only finding the current function. |
| return Move(mozilla::Get<Index>(aTuple)); |
| } |
| |
| /** |
| * A convenience function for constructing a tuple out of a sequence of |
| * values without specifying the type of the tuple. |
| * The type of the tuple is deduced from the types of its elements. |
| * |
| * Example: |
| * |
| * auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple<int, float, char> |
| */ |
| template<typename... Elements> |
| inline Tuple<typename Decay<Elements>::Type...> |
| MakeTuple(Elements&&... aElements) |
| { |
| return Tuple<typename Decay<Elements>::Type...>(Forward<Elements>(aElements)...); |
| } |
| |
| /** |
| * A convenience function for constructing a tuple of references to a |
| * sequence of variables. Since assignments to the elements of the tuple |
| * "go through" to the referenced variables, this can be used to "unpack" |
| * a tuple into individual variables. |
| * |
| * Example: |
| * |
| * int i; |
| * float f; |
| * char c; |
| * Tie(i, f, c) = FunctionThatReturnsATuple(); |
| */ |
| template<typename... Elements> |
| inline Tuple<Elements&...> |
| Tie(Elements&... aVariables) |
| { |
| return Tuple<Elements&...>(aVariables...); |
| } |
| |
| } // namespace mozilla |
| |
| #endif /* mozilla_Tuple_h */ |