Googletest export
Change ValuesArray to require much less template instantiation depth. PiperOrigin-RevId: 218170842
This commit is contained in:
		
							parent
							
								
									b7c8d3dafa
								
							
						
					
					
						commit
						f557390b86
					
				@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user