diff options
author | Abseil Team <absl-team@google.com> | 2018-10-22 11:21:18 -0400 |
---|---|---|
committer | Gennadiy Civil <misterg@google.com> | 2018-10-22 11:29:14 -0400 |
commit | 82987067d8cc6ee034abd18a78bd444cb41fd2c5 (patch) | |
tree | abece5b448269503a91a98eba0446412d39d0562 | |
parent | 32dbcac06e1fa94e596fe1fc1d0d7c312c46c642 (diff) | |
download | googletest-82987067d8cc6ee034abd18a78bd444cb41fd2c5.tar.gz googletest-82987067d8cc6ee034abd18a78bd444cb41fd2c5.tar.bz2 googletest-82987067d8cc6ee034abd18a78bd444cb41fd2c5.zip |
Googletest export
Change ValuesArray to require much less template instantiation depth.
PiperOrigin-RevId: 218170842
-rw-r--r-- | googletest/include/gtest/internal/gtest-internal.h | 106 | ||||
-rw-r--r-- | googletest/include/gtest/internal/gtest-param-util.h | 46 | ||||
-rw-r--r-- | googletest/test/gtest_unittest.cc | 78 |
3 files changed, 193 insertions, 37 deletions
diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 0fe05e23..9d1d8634 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -1176,6 +1176,112 @@ class NativeArray { GTEST_DISALLOW_ASSIGN_(NativeArray); }; +// Backport of std::index_sequence. +template <size_t... Is> +struct IndexSequence { + using type = IndexSequence; +}; + +// Double the IndexSequence, and one if plus_one is true. +template <bool plus_one, typename T, size_t sizeofT> +struct DoubleSequence; +template <size_t... I, size_t sizeofT> +struct DoubleSequence<true, IndexSequence<I...>, sizeofT> { + using type = IndexSequence<I..., (sizeofT + I)..., 2 * sizeofT>; +}; +template <size_t... I, size_t sizeofT> +struct DoubleSequence<false, IndexSequence<I...>, sizeofT> { + using type = IndexSequence<I..., (sizeofT + I)...>; +}; + +// Backport of std::make_index_sequence. +// It uses O(ln(N)) instantiation depth. +template <size_t N> +struct MakeIndexSequence + : DoubleSequence<N % 2 == 1, typename MakeIndexSequence<N / 2>::type, + N / 2>::type {}; + +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; +}; + +// Get the Nth element from T... +// It uses O(1) instantiation depth. +template <size_t N, typename I, typename... T> +struct ElemFromList; + +template <size_t N, size_t... I, typename... T> +struct ElemFromList<N, IndexSequence<I...>, T...> + : ElemFromListImpl<T, N, I>... {}; + +template <typename... T> +class FlatTuple; + +template <typename Derived, size_t I> +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; + FlatTupleElemBase() = default; + explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} + value_type value; +}; + +template <typename Derived, typename Idx> +struct FlatTupleBase; + +template <size_t... Idx, typename... T> +struct FlatTupleBase<FlatTuple<T...>, IndexSequence<Idx...>> + : FlatTupleElemBase<FlatTuple<T...>, Idx>... { + using Indices = IndexSequence<Idx...>; + FlatTupleBase() = default; + explicit FlatTupleBase(T... t) + : FlatTupleElemBase<FlatTuple<T...>, Idx>(std::move(t))... {} +}; + +// Analog to std::tuple but with different tradeoffs. +// This class minimizes the template instantiation depth, thus allowing more +// elements that std::tuple would. std::tuple has been seen to require an +// instantiation depth of more than 10x the number of elements in some +// implementations. +// FlatTuple and ElemFromList are not recursive and have a fixed depth +// regardless of T... +// MakeIndexSequence, on the other hand, it is recursive but with an +// instantiation depth of O(ln(N)). +template <typename... T> +class FlatTuple + : private FlatTupleBase<FlatTuple<T...>, + typename MakeIndexSequence<sizeof...(T)>::type> { + using Indices = typename FlatTuple::FlatTupleBase::Indices; + + public: + FlatTuple() = default; + explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} + + template <size_t I> + const typename ElemFromList<I, Indices, T...>::type& Get() const { + return static_cast<const FlatTupleElemBase<FlatTuple, I>*>(this)->value; + } + + template <size_t I> + typename ElemFromList<I, Indices, T...>::type& Get() { + return static_cast<FlatTupleElemBase<FlatTuple, I>*>(this)->value; + } +}; + } // namespace internal } // namespace testing diff --git a/googletest/include/gtest/internal/gtest-param-util.h b/googletest/include/gtest/internal/gtest-param-util.h index 2dea63cc..d5d4da95 100644 --- a/googletest/include/gtest/internal/gtest-param-util.h +++ b/googletest/include/gtest/internal/gtest-param-util.h @@ -74,27 +74,6 @@ namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // Utility Functions -// Block of code creating for_each_in_tuple -template <int... Is> -struct sequence {}; - -template <int N, int... Is> -struct generate_sequence : generate_sequence<N - 1, N - 1, Is...> {}; - -template <int... Is> -struct generate_sequence<0, Is...> : sequence<Is...> {}; - -template <typename T, typename F, int... Is> -void ForEachInTupleImpl(T&& t, F f_gtest, sequence<Is...>) { - int l[] = {(f_gtest(std::get<Is>(t)), 0)...}; - (void)l; // silence "unused variable warning" -} -template <typename... T, typename F> -void ForEachInTuple(const std::tuple<T...>& t, F f_gtest) { - internal::ForEachInTupleImpl(t, f_gtest, - internal::generate_sequence<sizeof...(T)>()); -} - // Outputs a message explaining invalid registration of different // fixture class for the same test case. This may happen when // TEST_P macro is used to define two tests with the same name @@ -747,30 +726,23 @@ internal::ParamGenerator<typename Container::value_type> ValuesIn( namespace internal { // Used in the Values() function to provide polymorphic capabilities. -template <typename T> -struct PushBack { - template <typename U> - void operator()(const U& u) { - v_.push_back(static_cast<T>(u)); - } - std::vector<T>& v_; -}; - template <typename... Ts> class ValueArray { public: ValueArray(Ts... v) : v_{std::move(v)...} {} - template <typename Tn> - operator ParamGenerator<Tn>() const { - std::vector<Tn> vc_accumulate; - PushBack<Tn> fnc{vc_accumulate}; - ForEachInTuple(v_, fnc); - return ValuesIn(std::move(vc_accumulate)); + template <typename T> + operator ParamGenerator<T>() const { // NOLINT + return ValuesIn(MakeVector<T>(MakeIndexSequence<sizeof...(Ts)>())); } private: - std::tuple<Ts...> v_; + template <typename T, size_t... I> + std::vector<T> MakeVector(IndexSequence<I...>) const { + return std::vector<T>{static_cast<T>(v_.template Get<I>())...}; + } + + FlatTuple<Ts...> v_; }; } // namespace internal diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index c6280ca2..9aff4f04 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -7450,6 +7450,84 @@ TEST(NativeArrayTest, WorksForTwoDimensionalArray) { EXPECT_EQ(a, na.begin()); } +// IndexSequence +TEST(IndexSequence, MakeIndexSequence) { + using testing::internal::IndexSequence; + using testing::internal::MakeIndexSequence; + EXPECT_TRUE( + (std::is_same<IndexSequence<>, MakeIndexSequence<0>::type>::value)); + EXPECT_TRUE( + (std::is_same<IndexSequence<0>, MakeIndexSequence<1>::type>::value)); + EXPECT_TRUE( + (std::is_same<IndexSequence<0, 1>, MakeIndexSequence<2>::type>::value)); + EXPECT_TRUE(( + std::is_same<IndexSequence<0, 1, 2>, MakeIndexSequence<3>::type>::value)); + EXPECT_TRUE( + (std::is_base_of<IndexSequence<0, 1, 2>, MakeIndexSequence<3>>::value)); +} + +// ElemFromList +TEST(ElemFromList, Basic) { + using testing::internal::ElemFromList; + using Idx = testing::internal::MakeIndexSequence<3>::type; + 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)); +} + +// FlatTuple +TEST(FlatTuple, Basic) { + using testing::internal::FlatTuple; + + FlatTuple<int, double, const char*> tuple = {}; + EXPECT_EQ(0, tuple.Get<0>()); + EXPECT_EQ(0.0, tuple.Get<1>()); + EXPECT_EQ(nullptr, tuple.Get<2>()); + + tuple = FlatTuple<int, double, const char*>(7, 3.2, "Foo"); + EXPECT_EQ(7, tuple.Get<0>()); + EXPECT_EQ(3.2, tuple.Get<1>()); + EXPECT_EQ(std::string("Foo"), tuple.Get<2>()); + + tuple.Get<1>() = 5.1; + EXPECT_EQ(5.1, tuple.Get<1>()); +} + +TEST(FlatTuple, ManyTypes) { + using testing::internal::FlatTuple; + + // Instantiate FlatTuple with 257 ints. + // Tests show that we can do it with thousands of elements, but very long + // compile times makes it unusuitable for this test. +#define GTEST_FLAT_TUPLE_INT8 int, int, int, int, int, int, int, int, +#define GTEST_FLAT_TUPLE_INT16 GTEST_FLAT_TUPLE_INT8 GTEST_FLAT_TUPLE_INT8 +#define GTEST_FLAT_TUPLE_INT32 GTEST_FLAT_TUPLE_INT16 GTEST_FLAT_TUPLE_INT16 +#define GTEST_FLAT_TUPLE_INT64 GTEST_FLAT_TUPLE_INT32 GTEST_FLAT_TUPLE_INT32 +#define GTEST_FLAT_TUPLE_INT128 GTEST_FLAT_TUPLE_INT64 GTEST_FLAT_TUPLE_INT64 +#define GTEST_FLAT_TUPLE_INT256 GTEST_FLAT_TUPLE_INT128 GTEST_FLAT_TUPLE_INT128 + + // Let's make sure that we can have a very long list of types without blowing + // up the template instantiation depth. + FlatTuple<GTEST_FLAT_TUPLE_INT256 int> tuple; + + tuple.Get<0>() = 7; + tuple.Get<99>() = 17; + tuple.Get<256>() = 1000; + EXPECT_EQ(7, tuple.Get<0>()); + EXPECT_EQ(17, tuple.Get<99>()); + EXPECT_EQ(1000, tuple.Get<256>()); +} + // Tests SkipPrefix(). TEST(SkipPrefixTest, SkipsWhenPrefixMatches) { |