From ed78e54f38ab10c775e39e5c4d500c6134a60d64 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 10 Oct 2019 13:12:54 -0400 Subject: 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 --- .../include/gmock/internal/gmock-internal-utils.h | 3 +- googletest/include/gtest/internal/gtest-internal.h | 44 +++++++++++----------- googletest/test/gtest_unittest.cc | 17 +++------ 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/googlemock/include/gmock/internal/gmock-internal-utils.h b/googlemock/include/gmock/internal/gmock-internal-utils.h index d012e71..584afa9 100644 --- a/googlemock/include/gmock/internal/gmock-internal-utils.h +++ b/googlemock/include/gmock/internal/gmock-internal-utils.h @@ -490,8 +490,7 @@ struct Function { using Result = R; static constexpr size_t ArgumentCount = sizeof...(Args); template - using Arg = ElemFromList::type, - Args...>; + using Arg = ElemFromList; using ArgumentTuple = std::tuple; using ArgumentMatcherTuple = std::tuple...>; using MakeResultVoid = void(Args...); diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 76ce13a..ebfe3c9 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -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 -struct ElemFromListImpl {}; - -template -struct ElemFromListImpl { - using type = T; +template +struct Ignore { + Ignore(...); // NOLINT }; -// Get the Nth element from T... -// It uses O(1) instantiation depth. -template -struct ElemFromList; +template +struct ElemFromListImpl; +template +struct ElemFromListImpl> { + // 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 + static R Apply(Ignore<0 * I>..., R (*)(), ...); +}; -template -struct ElemFromList, T...> - : ElemFromListImpl... {}; +template +struct ElemFromList { + using type = + decltype(ElemFromListImpl::type>::Apply( + static_cast(nullptr)...)); +}; template class FlatTuple; @@ -1152,9 +1156,7 @@ struct FlatTupleElemBase; template struct FlatTupleElemBase, I> { - using value_type = - typename ElemFromList::type, - T...>::type; + using value_type = typename ElemFromList::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 - const typename ElemFromList::type& Get() const { + const typename ElemFromList::type& Get() const { return static_cast*>(this)->value; } template - typename ElemFromList::type& Get() { + typename ElemFromList::type& Get() { return static_cast*>(this)->value; } }; diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index 05ee1c7..8312bd1 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -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::type>::value)); EXPECT_TRUE( - (std::is_same::type>::value)); + (std::is_same::type>::value)); EXPECT_TRUE( - (std::is_same::type>::value)); + (std::is_same::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::type>::value)); + EXPECT_TRUE(( + std::is_same::type>::value)); } // FlatTuple -- cgit v0.12