123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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> {
- bool operator==(const TupleImpl<Index>& aOther) const
- {
- return true;
- }
- };
- /*
- * 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;
- }
- bool operator==(const TupleImpl& aOther) const
- {
- return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther);
- }
- 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;
- }
- bool operator==(const Tuple& aOther) const
- {
- return static_cast<const Impl&>(*this) == static_cast<const Impl&>(aOther);
- }
- };
- /**
- * 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 */
|