diff options
Diffstat (limited to 'googletest/include/gtest/internal')
-rw-r--r-- | googletest/include/gtest/internal/gtest-internal.h | 106 | ||||
-rw-r--r-- | googletest/include/gtest/internal/gtest-param-util.h | 46 |
2 files changed, 115 insertions, 37 deletions
diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 0fe05e2..9d1d863 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 2dea63c..d5d4da9 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 |