From fbef0711cfce7b8f149aac773d30ae48ce3e166c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 6 Nov 2020 17:09:13 -0500 Subject: [PATCH] Googletest export Change ACTION{,_Pn,_TEMPLATE} macros to build functors rather than ActionInterface<> subclasses, thus changing the Action<> wrappers they create to use the modernized (non-const) argument tuple type, allowing these macros to mutate their arguments. Functor-based Action<>s deep-copy the implementing object, so have the functors use a shared_ptr to the non-trivial state of bound value parameters. No longer specialize that shared state to the particular action signature, encoding that information instead only in the instantiation of the implementation function. PiperOrigin-RevId: 341116208 --- googlemock/include/gmock/gmock-actions.h | 189 +++++++++--------- .../include/gmock/gmock-generated-actions.h | 122 +++++------ .../gmock/gmock-generated-actions.h.pump | 122 +++++------ 3 files changed, 212 insertions(+), 221 deletions(-) diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index f95be3f03..fb33f7bfa 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -1480,68 +1480,72 @@ namespace internal { // TYPE DIRECTLY. struct ExcessiveArg {}; -// A helper class needed for implementing the ACTION* macros. -template -class ActionHelper { - public: - template - static Result Perform(Impl* impl, const std::tuple& args) { - static constexpr size_t kMaxArgs = sizeof...(Ts) <= 10 ? sizeof...(Ts) : 10; - return Apply(impl, args, MakeIndexSequence{}, - MakeIndexSequence<10 - kMaxArgs>{}); +// Builds an implementation of an Action<> for some particular signature, using +// a class defined by an ACTION* macro. +template struct ActionImpl; + +template +struct ImplBase { + struct Holder { + // Allows each copy of the Action<> to get to the Impl. + explicit operator const Impl&() const { return *ptr; } + std::shared_ptr ptr; + }; + using type = typename std::conditional::value, + Impl, Holder>::type; +}; + +template +struct ActionImpl : ImplBase::type { + using Base = typename ImplBase::type; + using function_type = R(Args...); + using args_type = std::tuple; + + ActionImpl() = default; // Only defined if appropriate for Base. + explicit ActionImpl(std::shared_ptr impl) : Base{std::move(impl)} { } + + R operator()(Args&&... arg) const { + static constexpr size_t kMaxArgs = + sizeof...(Args) <= 10 ? sizeof...(Args) : 10; + return Apply(MakeIndexSequence{}, + MakeIndexSequence<10 - kMaxArgs>{}, + args_type{std::forward(arg)...}); } - private: - template - static Result Apply(Impl* impl, const std::tuple& args, - IndexSequence, IndexSequence) { - return impl->template gmock_PerformImpl< - typename std::tuple_element>::type...>( - args, std::get(args)..., - ((void)rest_ids, ExcessiveArg())...); + template + R Apply(IndexSequence, IndexSequence, + const args_type& args) const { + // Impl need not be specific to the signature of action being implemented; + // only the implementing function body needs to have all of the specific + // types instantiated. Up to 10 of the args that are provided by the + // args_type get passed, followed by a dummy of unspecified type for the + // remainder up to 10 explicit args. + static const ExcessiveArg kExcessArg; + return static_cast(*this).template gmock_PerformImpl< + /*function_type=*/function_type, /*return_type=*/R, + /*args_type=*/args_type, + /*argN_type=*/typename std::tuple_element::type...>( + /*args=*/args, std::get(args)..., + ((void)excess_id, kExcessArg)...); } }; -// A helper base class needed for implementing the ACTION* macros. -// Implements constructor and conversion operator for Action. -// -// Template specialization for parameterless Action. -template -class ActionImpl { - public: - ActionImpl() = default; +// Stores a default-constructed Impl as part of the Action<>'s +// std::function<>. The Impl should be trivial to copy. +template +::testing::Action MakeAction() { + return ::testing::Action(ActionImpl()); +} - template - operator ::testing::Action() const { // NOLINT(runtime/explicit) - return ::testing::Action(new typename Derived::template gmock_Impl()); - } -}; - -// Template specialization for parameterized Action. -template