aboutsummaryrefslogtreecommitdiffstats
path: root/googletest
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2018-10-22 11:21:18 -0400
committerGennadiy Civil <misterg@google.com>2018-10-22 11:29:14 -0400
commit82987067d8cc6ee034abd18a78bd444cb41fd2c5 (patch)
treeabece5b448269503a91a98eba0446412d39d0562 /googletest
parent32dbcac06e1fa94e596fe1fc1d0d7c312c46c642 (diff)
downloadgoogletest-82987067d8cc6ee034abd18a78bd444cb41fd2c5.tar.gz
googletest-82987067d8cc6ee034abd18a78bd444cb41fd2c5.tar.bz2
googletest-82987067d8cc6ee034abd18a78bd444cb41fd2c5.zip
Googletest export
Change ValuesArray to require much less template instantiation depth. PiperOrigin-RevId: 218170842
Diffstat (limited to 'googletest')
-rw-r--r--googletest/include/gtest/internal/gtest-internal.h106
-rw-r--r--googletest/include/gtest/internal/gtest-param-util.h46
-rw-r--r--googletest/test/gtest_unittest.cc78
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) {