mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1276351 - remove unused mozilla::tuple. r=sergesanspaille
Differential Revision: https://phabricator.services.mozilla.com/D173299
This commit is contained in:
parent
a1b827b503
commit
90401e3fba
515
mfbt/Tuple.h
515
mfbt/Tuple.h
@ -1,515 +0,0 @@
|
||||
/* -*- 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 <stddef.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "mozilla/CompactPair.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
|
||||
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> : std::false_type {};
|
||||
|
||||
template <typename... SourceTypes, typename... TargetTypes>
|
||||
struct CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>,
|
||||
true>
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
tl::And<std::is_convertible_v<SourceTypes, TargetTypes>...>::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)> {};
|
||||
|
||||
/*
|
||||
* Helper type for Tie(args...) to allow ignoring specific elements
|
||||
* during Tie unpacking. Supports assignment from any type.
|
||||
*
|
||||
* Not for direct usage; instead, use mozilla::Ignore in calls to Tie.
|
||||
*/
|
||||
struct IgnoreImpl {
|
||||
template <typename T>
|
||||
constexpr const IgnoreImpl& operator=(const T&) const {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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; }
|
||||
|
||||
template <typename F>
|
||||
void ForEach(const F& aFunc) const {}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 = std::enable_if_t<CheckConvertibility<
|
||||
Group<OtherHeadT, OtherTailT...>, Group<HeadT, TailT...>>::value>>
|
||||
explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail)
|
||||
: Base(std::forward<OtherTailT>(aTail)...),
|
||||
mHead(std::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(std::move(Tail(aOther))),
|
||||
mHead(std::forward<HeadT>(Head(aOther))) {}
|
||||
|
||||
// Assign from a tuple whose elements are convertible to the elements
|
||||
// of this tuple.
|
||||
template <typename... OtherElements,
|
||||
typename = std::enable_if_t<sizeof...(OtherElements) ==
|
||||
sizeof...(TailT) + 1>>
|
||||
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 = std::enable_if_t<sizeof...(OtherElements) ==
|
||||
sizeof...(TailT) + 1>>
|
||||
TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther) {
|
||||
typedef TupleImpl<Index, OtherElements...> OtherT;
|
||||
Head(*this) = std::move(OtherT::Head(aOther));
|
||||
Tail(*this) = std::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) = std::move(Head(aOther));
|
||||
Tail(*this) = std::move(Tail(aOther));
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const TupleImpl& aOther) const {
|
||||
return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void ForEach(const F& aFunc) const& {
|
||||
aFunc(Head(*this));
|
||||
Tail(*this).ForEach(aFunc);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void ForEach(const F& aFunc) & {
|
||||
aFunc(Head(*this));
|
||||
Tail(*this).ForEach(aFunc);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void ForEach(const F& aFunc) && {
|
||||
aFunc(std::move(Head(*this)));
|
||||
std::move(Tail(*this)).ForEach(aFunc);
|
||||
}
|
||||
|
||||
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
|
||||
* std::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 = std::enable_if_t<detail::CheckConvertibility<
|
||||
detail::Group<OtherHead, OtherTail...>,
|
||||
detail::Group<Elements...>>::value>>
|
||||
explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail)
|
||||
: Impl(std::forward<OtherHead>(aHead),
|
||||
std::forward<OtherTail>(aTail)...) {}
|
||||
Tuple(const Tuple& aOther) : Impl(aOther) {}
|
||||
Tuple(Tuple&& aOther) : Impl(std::move(aOther)) {}
|
||||
|
||||
template <typename... OtherElements,
|
||||
typename = std::enable_if_t<sizeof...(OtherElements) ==
|
||||
sizeof...(Elements)>>
|
||||
Tuple& operator=(const Tuple<OtherElements...>& aOther) {
|
||||
static_cast<Impl&>(*this) = aOther;
|
||||
return *this;
|
||||
}
|
||||
template <typename... OtherElements,
|
||||
typename = std::enable_if_t<sizeof...(OtherElements) ==
|
||||
sizeof...(Elements)>>
|
||||
Tuple& operator=(Tuple<OtherElements...>&& aOther) {
|
||||
static_cast<Impl&>(*this) = std::move(aOther);
|
||||
return *this;
|
||||
}
|
||||
Tuple& operator=(const Tuple& aOther) {
|
||||
static_cast<Impl&>(*this) = aOther;
|
||||
return *this;
|
||||
}
|
||||
Tuple& operator=(Tuple&& aOther) {
|
||||
static_cast<Impl&>(*this) = std::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 CompactPair 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 = std::enable_if_t<detail::CheckConvertibility<
|
||||
detail::Group<AArg, BArg>, detail::Group<A, B>>::value>>
|
||||
explicit Tuple(AArg&& aA, BArg&& aB)
|
||||
: Impl(std::forward<AArg>(aA), std::forward<BArg>(aB)) {}
|
||||
Tuple(const Tuple& aOther) : Impl(aOther) {}
|
||||
Tuple(Tuple&& aOther) : Impl(std::move(aOther)) {}
|
||||
explicit Tuple(const CompactPair<A, B>& aOther)
|
||||
: Impl(aOther.first(), aOther.second()) {}
|
||||
explicit Tuple(CompactPair<A, B>&& aOther)
|
||||
: Impl(std::forward<A>(aOther.first()),
|
||||
std::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(std::forward<A>(aOther.first), std::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) = std::move(aOther);
|
||||
return *this;
|
||||
}
|
||||
Tuple& operator=(const Tuple& aOther) {
|
||||
static_cast<Impl&>(*this) = aOther;
|
||||
return *this;
|
||||
}
|
||||
Tuple& operator=(Tuple&& aOther) {
|
||||
static_cast<Impl&>(*this) = std::move(aOther);
|
||||
return *this;
|
||||
}
|
||||
template <typename AArg, typename BArg>
|
||||
Tuple& operator=(const CompactPair<AArg, BArg>& aOther) {
|
||||
Impl::Head(*this) = aOther.first();
|
||||
Impl::Tail(*this).Head(*this) = aOther.second();
|
||||
return *this;
|
||||
}
|
||||
template <typename AArg, typename BArg>
|
||||
Tuple& operator=(CompactPair<AArg, BArg>&& aOther) {
|
||||
Impl::Head(*this) = std::forward<AArg>(aOther.first());
|
||||
Impl::Tail(*this).Head(*this) = std::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) = std::forward<AArg>(aOther.first);
|
||||
Impl::Tail(*this).Head(*this) = std::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(std::move(mozilla::Get<Index>(aTuple))) {
|
||||
// We need a 'mozilla::' qualification here to avoid
|
||||
// name lookup only finding the current function.
|
||||
return std::move(mozilla::Get<Index>(aTuple));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers which call a function for each member of the tuple in turn. This will
|
||||
* typically be used with a lambda function with an `auto&` argument:
|
||||
*
|
||||
* Tuple<Foo*, Bar*, SmartPtr<Baz>> tuple{a, b, c};
|
||||
*
|
||||
* ForEach(tuple, [](auto& aElem) {
|
||||
* aElem = nullptr;
|
||||
* });
|
||||
*/
|
||||
|
||||
template <typename F>
|
||||
inline void ForEach(const Tuple<>& aTuple, const F& aFunc) {}
|
||||
|
||||
template <typename F>
|
||||
inline void ForEach(Tuple<>& aTuple, const F& aFunc) {}
|
||||
|
||||
template <typename F, typename... Elements>
|
||||
void ForEach(const Tuple<Elements...>& aTuple, const F& aFunc) {
|
||||
aTuple.ForEach(aFunc);
|
||||
}
|
||||
|
||||
template <typename F, typename... Elements>
|
||||
void ForEach(Tuple<Elements...>& aTuple, const F& aFunc) {
|
||||
aTuple.ForEach(aFunc);
|
||||
}
|
||||
|
||||
template <typename F, typename... Elements>
|
||||
void ForEach(Tuple<Elements...>&& aTuple, const F& aFunc) {
|
||||
std::forward<Tuple<Elements...>>(aTuple).ForEach(aFunc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<std::decay_t<Elements>...> MakeTuple(Elements&&... aElements) {
|
||||
return Tuple<std::decay_t<Elements>...>(std::forward<Elements>(aElements)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper placholder to allow ignoring specific elements during Tie unpacking.
|
||||
* Can be used with any type and any number of elements in a call to Tie.
|
||||
*
|
||||
* Usage of Ignore with Tie is equivalent to using std::ignore with
|
||||
* std::tie.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* int i;
|
||||
* float f;
|
||||
* char c;
|
||||
* Tie(i, Ignore, f, c, Ignore) = FunctionThatReturnsATuple();
|
||||
*/
|
||||
constexpr detail::IgnoreImpl Ignore;
|
||||
|
||||
/**
|
||||
* 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 */
|
@ -113,7 +113,6 @@ EXPORTS.mozilla = [
|
||||
"ThreadSafety.h",
|
||||
"ThreadSafeWeakPtr.h",
|
||||
"ToString.h",
|
||||
"Tuple.h",
|
||||
"TypedEnumBits.h",
|
||||
"Types.h",
|
||||
"TypeTraits.h",
|
||||
|
@ -1,362 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CompactPair.h"
|
||||
#include "mozilla/Tuple.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
using mozilla::CompactPair;
|
||||
using mozilla::Get;
|
||||
using mozilla::MakeTuple;
|
||||
using mozilla::MakeUnique;
|
||||
using mozilla::Tie;
|
||||
using mozilla::Tuple;
|
||||
using mozilla::UniquePtr;
|
||||
using mozilla::Unused;
|
||||
using std::pair;
|
||||
|
||||
#define CHECK(c) \
|
||||
do { \
|
||||
bool cond = !!(c); \
|
||||
MOZ_RELEASE_ASSERT(cond, "Failed assertion: " #c); \
|
||||
} while (false)
|
||||
|
||||
// The second argument is the expected type. It's variadic to allow the
|
||||
// type to contain commas.
|
||||
#define CHECK_TYPE(expression, ...) \
|
||||
static_assert(std::is_same_v<decltype(expression), __VA_ARGS__>, \
|
||||
"Type mismatch!")
|
||||
|
||||
struct ConvertibleToInt {
|
||||
operator int() const { return 42; }
|
||||
};
|
||||
|
||||
static void TestConstruction() {
|
||||
// Default construction
|
||||
Tuple<> a;
|
||||
Unused << a;
|
||||
Tuple<int> b;
|
||||
Unused << b;
|
||||
|
||||
// Construction from elements
|
||||
int x = 1, y = 1;
|
||||
Tuple<int, int> c{x, y};
|
||||
Tuple<int&, const int&> d{x, y};
|
||||
x = 42;
|
||||
y = 42;
|
||||
CHECK(Get<0>(c) == 1);
|
||||
CHECK(Get<1>(c) == 1);
|
||||
CHECK(Get<0>(d) == 42);
|
||||
CHECK(Get<1>(d) == 42);
|
||||
|
||||
// Construction from objects convertible to the element types
|
||||
Tuple<int, int> e{1.0, ConvertibleToInt{}};
|
||||
|
||||
// Copy construction
|
||||
Tuple<int> x1;
|
||||
Tuple<int> x2{x1};
|
||||
|
||||
Tuple<int, int> f(c);
|
||||
CHECK(Get<0>(f) == 1);
|
||||
CHECK(Get<0>(f) == 1);
|
||||
|
||||
// Move construction
|
||||
Tuple<UniquePtr<int>> g{MakeUnique<int>(42)};
|
||||
Tuple<UniquePtr<int>> h{std::move(g)};
|
||||
CHECK(Get<0>(g) == nullptr);
|
||||
CHECK(*Get<0>(h) == 42);
|
||||
}
|
||||
|
||||
static void TestConstructionFromMozPair() {
|
||||
// Construction from elements
|
||||
int x = 1, y = 1;
|
||||
CompactPair<int, int> a{x, y};
|
||||
CompactPair<int&, const int&> b{x, y};
|
||||
Tuple<int, int> c(a);
|
||||
Tuple<int&, const int&> d(b);
|
||||
x = 42;
|
||||
y = 42;
|
||||
CHECK(Get<0>(c) == 1);
|
||||
CHECK(Get<1>(c) == 1);
|
||||
CHECK(Get<0>(d) == 42);
|
||||
CHECK(Get<1>(d) == 42);
|
||||
}
|
||||
|
||||
static void TestConstructionFromStdPair() {
|
||||
// Construction from elements
|
||||
int x = 1, y = 1;
|
||||
pair<int, int> a{x, y};
|
||||
pair<int&, const int&> b{x, y};
|
||||
Tuple<int, int> c(a);
|
||||
Tuple<int&, const int&> d(b);
|
||||
x = 42;
|
||||
y = 42;
|
||||
CHECK(Get<0>(c) == 1);
|
||||
CHECK(Get<1>(c) == 1);
|
||||
CHECK(Get<0>(d) == 42);
|
||||
CHECK(Get<1>(d) == 42);
|
||||
}
|
||||
|
||||
static void TestAssignment() {
|
||||
// Copy assignment
|
||||
Tuple<int> a{0};
|
||||
Tuple<int> b{42};
|
||||
a = b;
|
||||
CHECK(Get<0>(a) == 42);
|
||||
|
||||
// Assignment to reference member
|
||||
int i = 0;
|
||||
int j = 42;
|
||||
Tuple<int&> c{i};
|
||||
Tuple<int&> d{j};
|
||||
c = d;
|
||||
CHECK(i == 42);
|
||||
|
||||
// Move assignment
|
||||
Tuple<UniquePtr<int>> e{MakeUnique<int>(0)};
|
||||
Tuple<UniquePtr<int>> f{MakeUnique<int>(42)};
|
||||
e = std::move(f);
|
||||
CHECK(*Get<0>(e) == 42);
|
||||
CHECK(Get<0>(f) == nullptr);
|
||||
}
|
||||
|
||||
static void TestAssignmentFromMozPair() {
|
||||
// Copy assignment
|
||||
Tuple<int, int> a{0, 0};
|
||||
CompactPair<int, int> b{42, 42};
|
||||
a = b;
|
||||
CHECK(Get<0>(a) == 42);
|
||||
CHECK(Get<1>(a) == 42);
|
||||
|
||||
// Assignment to reference member
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 42;
|
||||
Tuple<int&, int&> c{i, j};
|
||||
CompactPair<int&, int&> d{k, k};
|
||||
c = d;
|
||||
CHECK(i == 42);
|
||||
CHECK(j == 42);
|
||||
|
||||
// Move assignment
|
||||
Tuple<UniquePtr<int>, UniquePtr<int>> e{MakeUnique<int>(0),
|
||||
MakeUnique<int>(0)};
|
||||
CompactPair<UniquePtr<int>, UniquePtr<int>> f{MakeUnique<int>(42),
|
||||
MakeUnique<int>(42)};
|
||||
e = std::move(f);
|
||||
CHECK(*Get<0>(e) == 42);
|
||||
CHECK(*Get<1>(e) == 42);
|
||||
CHECK(f.first() == nullptr);
|
||||
CHECK(f.second() == nullptr);
|
||||
}
|
||||
|
||||
static void TestAssignmentFromStdPair() {
|
||||
// Copy assignment
|
||||
Tuple<int, int> a{0, 0};
|
||||
pair<int, int> b{42, 42};
|
||||
a = b;
|
||||
CHECK(Get<0>(a) == 42);
|
||||
CHECK(Get<1>(a) == 42);
|
||||
|
||||
// Assignment to reference member
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 42;
|
||||
Tuple<int&, int&> c{i, j};
|
||||
pair<int&, int&> d{k, k};
|
||||
c = d;
|
||||
CHECK(i == 42);
|
||||
CHECK(j == 42);
|
||||
|
||||
// Move assignment.
|
||||
Tuple<UniquePtr<int>, UniquePtr<int>> e{MakeUnique<int>(0),
|
||||
MakeUnique<int>(0)};
|
||||
// XXX: On some platforms std::pair doesn't support move constructor.
|
||||
pair<UniquePtr<int>, UniquePtr<int>> f;
|
||||
f.first = MakeUnique<int>(42);
|
||||
f.second = MakeUnique<int>(42);
|
||||
|
||||
e = std::move(f);
|
||||
CHECK(*Get<0>(e) == 42);
|
||||
CHECK(*Get<1>(e) == 42);
|
||||
CHECK(f.first == nullptr);
|
||||
CHECK(f.second == nullptr);
|
||||
}
|
||||
|
||||
static void TestGet() {
|
||||
int x = 1;
|
||||
int y = 2;
|
||||
int z = 3;
|
||||
Tuple<int, int&, const int&> tuple(x, y, z);
|
||||
|
||||
// Using Get<>() to read elements
|
||||
CHECK(Get<0>(tuple) == 1);
|
||||
CHECK(Get<1>(tuple) == 2);
|
||||
CHECK(Get<2>(tuple) == 3);
|
||||
|
||||
// Using Get<>() to write to elements
|
||||
Get<0>(tuple) = 41;
|
||||
CHECK(Get<0>(tuple) == 41);
|
||||
|
||||
// Writing through reference elements
|
||||
Get<1>(tuple) = 42;
|
||||
CHECK(Get<1>(tuple) == 42);
|
||||
CHECK(y == 42);
|
||||
}
|
||||
|
||||
static void TestMakeTuple() {
|
||||
auto tuple = MakeTuple(42, 0.5f, 'c');
|
||||
CHECK_TYPE(tuple, Tuple<int, float, char>);
|
||||
CHECK(Get<0>(tuple) == 42);
|
||||
CHECK(Get<1>(tuple) == 0.5f);
|
||||
CHECK(Get<2>(tuple) == 'c');
|
||||
|
||||
// Make sure we don't infer the type to be Tuple<int&>.
|
||||
int x = 1;
|
||||
auto tuple2 = MakeTuple(x);
|
||||
CHECK_TYPE(tuple2, Tuple<int>);
|
||||
x = 2;
|
||||
CHECK(Get<0>(tuple2) == 1);
|
||||
}
|
||||
|
||||
static bool TestTieMozPair() {
|
||||
int i;
|
||||
float f;
|
||||
char c;
|
||||
Tuple<int, float, char> rhs1(42, 0.5f, 'c');
|
||||
Tie(i, f, c) = rhs1;
|
||||
CHECK(i == Get<0>(rhs1));
|
||||
CHECK(f == Get<1>(rhs1));
|
||||
CHECK(c == Get<2>(rhs1));
|
||||
// Test conversions
|
||||
Tuple<ConvertibleToInt, double, unsigned char> rhs2(ConvertibleToInt(), 0.7f,
|
||||
'd');
|
||||
Tie(i, f, c) = rhs2;
|
||||
CHECK(i == Get<0>(rhs2));
|
||||
CHECK(f == Get<1>(rhs2));
|
||||
CHECK(c == Get<2>(rhs2));
|
||||
|
||||
// Test Pair
|
||||
CompactPair<int, float> rhs3(42, 1.5f);
|
||||
Tie(i, f) = rhs3;
|
||||
CHECK(i == rhs3.first());
|
||||
CHECK(f == rhs3.second());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestTie() {
|
||||
int i;
|
||||
float f;
|
||||
char c;
|
||||
Tuple<int, float, char> rhs1(42, 0.5f, 'c');
|
||||
Tie(i, f, c) = rhs1;
|
||||
CHECK(i == Get<0>(rhs1));
|
||||
CHECK(f == Get<1>(rhs1));
|
||||
CHECK(c == Get<2>(rhs1));
|
||||
// Test conversions
|
||||
Tuple<ConvertibleToInt, double, unsigned char> rhs2(ConvertibleToInt(), 0.7f,
|
||||
'd');
|
||||
Tie(i, f, c) = rhs2;
|
||||
CHECK(i == Get<0>(rhs2));
|
||||
CHECK(f == Get<1>(rhs2));
|
||||
CHECK(c == Get<2>(rhs2));
|
||||
|
||||
// Test Pair
|
||||
pair<int, float> rhs3(42, 1.5f);
|
||||
Tie(i, f) = rhs3;
|
||||
CHECK(i == rhs3.first);
|
||||
CHECK(f == rhs3.second);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestTieIgnore() {
|
||||
int i;
|
||||
char c;
|
||||
Tuple<int, float, char> rhs1(42, 0.5f, 'c');
|
||||
|
||||
Tie(i, mozilla::Ignore, c) = rhs1;
|
||||
|
||||
CHECK(i == Get<0>(rhs1));
|
||||
CHECK(c == Get<2>(rhs1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename... Elements, typename F>
|
||||
static void CheckForEachCall(const Tuple<Elements...>& aTuple,
|
||||
F&& CallForEach) {
|
||||
constexpr std::size_t tupleSize = sizeof...(Elements);
|
||||
|
||||
Tuple<Elements...> checkResult;
|
||||
std::size_t i = 0;
|
||||
auto createResult = [&](auto& aElem) {
|
||||
static_assert(tupleSize == 3,
|
||||
"Need to deal with more/less cases in the switch below");
|
||||
|
||||
CHECK(i < tupleSize);
|
||||
switch (i) {
|
||||
case 0:
|
||||
Get<0>(checkResult) = aElem;
|
||||
break;
|
||||
case 1:
|
||||
Get<1>(checkResult) = aElem;
|
||||
break;
|
||||
case 2:
|
||||
Get<2>(checkResult) = aElem;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
};
|
||||
|
||||
CallForEach(aTuple, createResult);
|
||||
|
||||
CHECK(checkResult == aTuple);
|
||||
}
|
||||
|
||||
static bool TestForEach() {
|
||||
Tuple<int, float, char> tuple = MakeTuple(42, 0.5f, 'c');
|
||||
|
||||
CheckForEachCall(
|
||||
tuple, [](auto& aTuple, auto&& aLambda) { aTuple.ForEach(aLambda); });
|
||||
|
||||
CheckForEachCall(
|
||||
tuple, [](auto& aTuple, auto&& aLambda) { ForEach(aTuple, aLambda); });
|
||||
|
||||
CheckForEachCall(tuple, [](auto& aTuple, auto&& aLambda) {
|
||||
const decltype(aTuple)& constTuple = aTuple;
|
||||
constTuple.ForEach(aLambda);
|
||||
});
|
||||
|
||||
CheckForEachCall(tuple, [](auto& aTuple, auto&& aLambda) {
|
||||
const decltype(aTuple)& constTuple = aTuple;
|
||||
ForEach(constTuple, aLambda);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
TestConstruction();
|
||||
TestConstructionFromMozPair();
|
||||
TestConstructionFromStdPair();
|
||||
TestAssignment();
|
||||
TestAssignmentFromMozPair();
|
||||
TestAssignmentFromStdPair();
|
||||
TestGet();
|
||||
TestMakeTuple();
|
||||
TestTie();
|
||||
TestTieIgnore();
|
||||
TestTieMozPair();
|
||||
TestForEach();
|
||||
return 0;
|
||||
}
|
@ -62,7 +62,6 @@ CppUnitTests(
|
||||
"TestSplayTree",
|
||||
"TestTemplateLib",
|
||||
"TestTextUtils",
|
||||
"TestTuple",
|
||||
"TestTypedEnum",
|
||||
"TestTypeTraits",
|
||||
"TestUniquePtr",
|
||||
|
@ -118,7 +118,7 @@ template <typename OrigFuncT, typename... Args,
|
||||
typename ArgTuple = std::tuple<Args...>, size_t... Indices>
|
||||
decltype(auto) Apply(OrigFuncT& aFunc, ArgTuple&& aArgs,
|
||||
std::index_sequence<Indices...>) {
|
||||
return aFunc(std::get<Indices>(std::forward<ArgTuple>(aArgs))...);
|
||||
return std::apply(aFunc, aArgs);
|
||||
}
|
||||
|
||||
#define DEFINE_TEST_FUNCTION(calling_convention) \
|
||||
|
@ -1,31 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef TupleCycleCollection_h
|
||||
#define TupleCycleCollection_h
|
||||
|
||||
#include "mozilla/Tuple.h"
|
||||
#include "nsCycleCollectionNoteChild.h"
|
||||
|
||||
class nsCycleCollectionTraversalCallback;
|
||||
|
||||
template <typename... Elements>
|
||||
inline void ImplCycleCollectionUnlink(mozilla::Tuple<Elements...>& aField) {
|
||||
ForEach(aField, [](auto& aElem) { ImplCycleCollectionUnlink(aElem); });
|
||||
}
|
||||
|
||||
template <typename... Elements>
|
||||
inline void ImplCycleCollectionTraverse(
|
||||
nsCycleCollectionTraversalCallback& aCallback,
|
||||
mozilla::Tuple<Elements...>& aField, const char* aName,
|
||||
uint32_t aFlags = 0) {
|
||||
aFlags |= CycleCollectionEdgeNameArrayFlag;
|
||||
ForEach(aField, [&](auto& aElem) {
|
||||
ImplCycleCollectionTraverse(aCallback, aElem, aName, aFlags);
|
||||
});
|
||||
}
|
||||
|
||||
#endif // TupleCycleCollection_h
|
@ -133,7 +133,6 @@ EXPORTS.mozilla += [
|
||||
"StaticMonitor.h",
|
||||
"StaticMutex.h",
|
||||
"StaticPtr.h",
|
||||
"TupleCycleCollection.h",
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
@ -1157,17 +1157,13 @@ struct RunnableMethodArguments final {
|
||||
template <typename... As>
|
||||
explicit RunnableMethodArguments(As&&... aArguments)
|
||||
: mArguments(std::forward<As>(aArguments)...) {}
|
||||
template <typename C, typename M, typename... Args, size_t... Indices>
|
||||
static auto applyImpl(C* o, M m, std::tuple<Args...>& args,
|
||||
std::index_sequence<Indices...>)
|
||||
-> decltype(((*o).*m)(std::get<Indices>(args).PassAsParameter()...)) {
|
||||
return ((*o).*m)(std::get<Indices>(args).PassAsParameter()...);
|
||||
}
|
||||
template <class C, typename M>
|
||||
auto apply(C* o, M m)
|
||||
-> decltype(applyImpl(o, m, mArguments,
|
||||
std::index_sequence_for<Ts...>{})) {
|
||||
return applyImpl(o, m, mArguments, std::index_sequence_for<Ts...>{});
|
||||
decltype(auto) apply(C* o, M m) {
|
||||
return std::apply(
|
||||
[&o, m](auto&&... args) {
|
||||
return ((*o).*m)(args.PassAsParameter()...);
|
||||
},
|
||||
mArguments);
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user