Googletest export

Fix the O(n^2) number of instantiations in ElemFromList.
It is now O(n). It still has O(1) instantiation depth.

PiperOrigin-RevId: 273980821
This commit is contained in:
Abseil Team 2019-10-10 13:12:54 -04:00 committed by Gennadiy Civil
parent 58c7197761
commit ed78e54f38
3 changed files with 32 additions and 36 deletions

View File

@ -490,8 +490,7 @@ struct Function<R(Args...)> {
using Result = R;
static constexpr size_t ArgumentCount = sizeof...(Args);
template <size_t I>
using Arg = ElemFromList<I, typename MakeIndexSequence<sizeof...(Args)>::type,
Args...>;
using Arg = ElemFromList<I, Args...>;
using ArgumentTuple = std::tuple<Args...>;
using ArgumentMatcherTuple = std::tuple<Matcher<Args>...>;
using MakeResultVoid = void(Args...);

View File

@ -1124,25 +1124,29 @@ struct MakeIndexSequence
template <>
struct MakeIndexSequence<0> : IndexSequence<> {};
// FIXME: This implementation of ElemFromList is O(1) in instantiation depth,
// but it is O(N^2) in total instantiations. Not sure if this is the best
// tradeoff, as it will make it somewhat slow to compile.
template <typename T, size_t, size_t>
struct ElemFromListImpl {};
template <typename T, size_t I>
struct ElemFromListImpl<T, I, I> {
using type = T;
template <size_t>
struct Ignore {
Ignore(...); // NOLINT
};
// Get the Nth element from T...
// It uses O(1) instantiation depth.
template <size_t N, typename I, typename... T>
struct ElemFromList;
template <typename>
struct ElemFromListImpl;
template <size_t... I>
struct ElemFromListImpl<IndexSequence<I...>> {
// We make Ignore a template to solve a problem with MSVC.
// A non-template Ignore would work fine with `decltype(Ignore(I))...`, but
// MSVC doesn't understand how to deal with that pack expansion.
// Use `0 * I` to have a single instantiation of Ignore.
template <typename R>
static R Apply(Ignore<0 * I>..., R (*)(), ...);
};
template <size_t N, size_t... I, typename... T>
struct ElemFromList<N, IndexSequence<I...>, T...>
: ElemFromListImpl<T, N, I>... {};
template <size_t N, typename... T>
struct ElemFromList {
using type =
decltype(ElemFromListImpl<typename MakeIndexSequence<N>::type>::Apply(
static_cast<T (*)()>(nullptr)...));
};
template <typename... T>
class FlatTuple;
@ -1152,9 +1156,7 @@ struct FlatTupleElemBase;
template <typename... T, size_t I>
struct FlatTupleElemBase<FlatTuple<T...>, I> {
using value_type =
typename ElemFromList<I, typename MakeIndexSequence<sizeof...(T)>::type,
T...>::type;
using value_type = typename ElemFromList<I, T...>::type;
FlatTupleElemBase() = default;
explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {}
value_type value;
@ -1192,12 +1194,12 @@ class FlatTuple
explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {}
template <size_t I>
const typename ElemFromList<I, Indices, T...>::type& Get() const {
const typename ElemFromList<I, T...>::type& Get() const {
return static_cast<const FlatTupleElemBase<FlatTuple, I>*>(this)->value;
}
template <size_t I>
typename ElemFromList<I, Indices, T...>::type& Get() {
typename ElemFromList<I, T...>::type& Get() {
return static_cast<FlatTupleElemBase<FlatTuple, I>*>(this)->value;
}
};

View File

@ -7353,20 +7353,15 @@ TEST(IndexSequence, MakeIndexSequence) {
// ElemFromList
TEST(ElemFromList, Basic) {
using testing::internal::ElemFromList;
using Idx = testing::internal::MakeIndexSequence<3>::type;
EXPECT_TRUE(
(std::is_same<int, ElemFromList<0, int, double, char>::type>::value));
EXPECT_TRUE(
(std::is_same<double, ElemFromList<1, int, double, char>::type>::value));
EXPECT_TRUE(
(std::is_same<char, ElemFromList<2, int, double, char>::type>::value));
EXPECT_TRUE((
std::is_same<int, ElemFromList<0, Idx, int, double, char>::type>::value));
EXPECT_TRUE(
(std::is_same<double,
ElemFromList<1, Idx, int, double, char>::type>::value));
EXPECT_TRUE(
(std::is_same<char,
ElemFromList<2, Idx, int, double, char>::type>::value));
EXPECT_TRUE(
(std::is_same<
char, ElemFromList<7, testing::internal::MakeIndexSequence<12>::type,
int, int, int, int, int, int, int, char, int, int,
int, int>::type>::value));
std::is_same<char, ElemFromList<7, int, int, int, int, int, int, int,
char, int, int, int, int>::type>::value));
}
// FlatTuple