From 872cd2741222b09f714cfdb909745fa68d5116a3 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Thu, 21 May 2015 22:33:49 -0400 Subject: [PATCH] Bug 1163328 - Add a Tuple class to MFBT. r=froydnj --HG-- extra : source : f12a4369d58e8ed5acb244b10ce749849d61f60c --- mfbt/Tuple.h | 301 +++++++++++++++++++++++++++++++++++++++++++++++++ mfbt/moz.build | 1 + 2 files changed, 302 insertions(+) create mode 100644 mfbt/Tuple.h diff --git a/mfbt/Tuple.h b/mfbt/Tuple.h new file mode 100644 index 000000000000..98872796a962 --- /dev/null +++ b/mfbt/Tuple.h @@ -0,0 +1,301 @@ +/* -*- 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/TemplateLib.h" +#include "mozilla/TypeTraits.h" + +#include + +namespace mozilla { + +namespace detail { + +/* + * A helper class that allows passing around multiple variadic argument lists + * by grouping them. + */ +template +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> + * 'Group' is used to separate types in the two packs (otherwise if we just + * wrote 'CheckConvertibility +struct CheckConvertibilityImpl; + +template +struct CheckConvertibilityImpl + : FalseType {}; + +template +struct CheckConvertibilityImpl, Group, true> + : IntegralConstant::value...>::value> { }; + +template +struct CheckConvertibility; + +template +struct CheckConvertibility, Group> + : CheckConvertibilityImpl, Group, + 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 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', + * where 'I' is specified explicitly and 'E...' is deduced (this is what the + * non-member 'Get(t)' function does). + * + * This implementation strategy is borrowed from libstdc++'s std::tuple + * implementation. + */ +template +struct TupleImpl; + +/* + * The base case of the inheritance recursion (and also the implementation + * of an empty tuple). + */ +template +struct TupleImpl {}; + +/* + * 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 +struct TupleImpl + : public TupleImpl +{ + typedef TupleImpl 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 , + Group>::value>::Type> + explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail) + : Base(Forward(aTail)...), mHead(Forward(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(Move(Head(aOther))) {} + + // 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(tuple)'. + */ +template +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 , + detail::Group>::value>::Type> + explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail) + : Impl(Forward(aHead), Forward(aTail)...) { } + Tuple(const Tuple& aOther) : Impl(aOther) { } + Tuple(Tuple&& aOther) : Impl(Move(aOther)) { } + + Tuple& operator=(const Tuple& aOther) + { + static_cast(*this) = aOther; + return *this; + } + Tuple& operator=(Tuple&& aOther) + { + static_cast(*this) = Move(aOther); + 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(tuple). + * These functions take a TupleImpl, 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 +auto TupleGetHelper(TupleImpl& aTuple) + -> decltype(TupleImpl::Head(aTuple)) +{ + return TupleImpl::Head(aTuple); +} + +// Non-const reference version. +template +auto TupleGetHelper(const TupleImpl& aTuple) + -> decltype(TupleImpl::Head(aTuple)) +{ + return TupleImpl::Head(aTuple); +} + +} // namespace detail + +/** + * Index-based access to an element of a tuple. + * The syntax is Get(tuple). The index is zero-based. + * + * Example: + * + * Tuple t; + * ... + * float f = Get<1>(t); + */ + +// Non-const reference version. +template +auto Get(Tuple& aTuple) + -> decltype(detail::TupleGetHelper(aTuple)) +{ + return detail::TupleGetHelper(aTuple); +} + +// Const reference version. +template +auto Get(const Tuple& aTuple) + -> decltype(detail::TupleGetHelper(aTuple)) +{ + return detail::TupleGetHelper(aTuple); +} + +// Rvalue reference version. +template +auto Get(Tuple&& aTuple) + -> decltype(Move(mozilla::Get(aTuple))) +{ + // We need a 'mozilla::' qualification here to avoid + // name lookup only finding the current function. + return Move(mozilla::Get(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 + */ +template +Tuple MakeTuple(Elements&&... aElements) +{ + return Tuple(Forward(aElements)...); +} + +} // namespace mozilla + +#endif /* mozilla_Tuple_h */ diff --git a/mfbt/moz.build b/mfbt/moz.build index eef7852dbcac..e1c2c35fc382 100644 --- a/mfbt/moz.build +++ b/mfbt/moz.build @@ -73,6 +73,7 @@ EXPORTS.mozilla = [ 'TemplateLib.h', 'ThreadLocal.h', 'ToString.h', + 'Tuple.h', 'TypedEnumBits.h', 'Types.h', 'TypeTraits.h',