Googletest export
Use std::function to implement type erasure in Action, wrapping the legacy ActionInterface if necessary. This makes functors / std::function the primary way to implement Action; the existing ActionInterface implementations are handled through ActionAdaptor. The existing actions are not (yet) migrated though; they'll pay the cost of one additional indirection - but that should be negligible. PiperOrigin-RevId: 226126137
This commit is contained in:
parent
e26a3fa13c
commit
9494c45e75
@ -69,9 +69,6 @@ namespace testing {
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename F1, typename F2>
|
|
||||||
class ActionAdaptor;
|
|
||||||
|
|
||||||
// BuiltInDefaultValueGetter<T, true>::Get() returns a
|
// BuiltInDefaultValueGetter<T, true>::Get() returns a
|
||||||
// default-constructed T value. BuiltInDefaultValueGetter<T,
|
// default-constructed T value. BuiltInDefaultValueGetter<T,
|
||||||
// false>::Get() crashes with an error.
|
// false>::Get() crashes with an error.
|
||||||
@ -342,6 +339,19 @@ class ActionInterface {
|
|||||||
// object as a handle to it.
|
// object as a handle to it.
|
||||||
template <typename F>
|
template <typename F>
|
||||||
class Action {
|
class Action {
|
||||||
|
// Adapter class to allow constructing Action from a legacy ActionInterface.
|
||||||
|
// New code should create Actions from functors instead.
|
||||||
|
struct ActionAdapter {
|
||||||
|
// Adapter must be copyable to satisfy std::function requirements.
|
||||||
|
::std::shared_ptr<ActionInterface<F>> impl_;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
typename internal::Function<F>::Result operator()(Args&&... args) {
|
||||||
|
return impl_->Perform(
|
||||||
|
::std::forward_as_tuple(::std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename internal::Function<F>::Result Result;
|
typedef typename internal::Function<F>::Result Result;
|
||||||
typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
|
typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
|
||||||
@ -359,19 +369,17 @@ class Action {
|
|||||||
Action(G&& fun) : fun_(::std::forward<G>(fun)) {} // NOLINT
|
Action(G&& fun) : fun_(::std::forward<G>(fun)) {} // NOLINT
|
||||||
|
|
||||||
// Constructs an Action from its implementation.
|
// Constructs an Action from its implementation.
|
||||||
explicit Action(ActionInterface<F>* impl) : impl_(impl) {}
|
explicit Action(ActionInterface<F>* impl)
|
||||||
|
: fun_(ActionAdapter{::std::shared_ptr<ActionInterface<F>>(impl)}) {}
|
||||||
|
|
||||||
// This constructor allows us to turn an Action<Func> object into an
|
// This constructor allows us to turn an Action<Func> object into an
|
||||||
// Action<F>, as long as F's arguments can be implicitly converted
|
// Action<F>, as long as F's arguments can be implicitly converted
|
||||||
// to Func's and Func's return type can be implicitly converted to
|
// to Func's and Func's return type can be implicitly converted to F's.
|
||||||
// F's.
|
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
explicit Action(const Action<Func>& action);
|
explicit Action(const Action<Func>& action) : fun_(action.fun_) {}
|
||||||
|
|
||||||
// Returns true iff this is the DoDefault() action.
|
// Returns true iff this is the DoDefault() action.
|
||||||
bool IsDoDefault() const {
|
bool IsDoDefault() const { return fun_ == nullptr; }
|
||||||
return impl_ == nullptr && fun_ == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Performs the action. Note that this method is const even though
|
// Performs the action. Note that this method is const even though
|
||||||
// the corresponding method in ActionInterface is not. The reason
|
// the corresponding method in ActionInterface is not. The reason
|
||||||
@ -383,25 +391,15 @@ class Action {
|
|||||||
if (IsDoDefault()) {
|
if (IsDoDefault()) {
|
||||||
internal::IllegalDoDefault(__FILE__, __LINE__);
|
internal::IllegalDoDefault(__FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
if (fun_ != nullptr) {
|
return internal::Apply(fun_, ::std::move(args));
|
||||||
return internal::Apply(fun_, ::std::move(args));
|
|
||||||
}
|
|
||||||
return impl_->Perform(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename F1, typename F2>
|
|
||||||
friend class internal::ActionAdaptor;
|
|
||||||
|
|
||||||
template <typename G>
|
template <typename G>
|
||||||
friend class Action;
|
friend class Action;
|
||||||
|
|
||||||
// Action can be implemented either as a generic functor (via std::function),
|
// fun_ is an empty function iff this is the DoDefault() action.
|
||||||
// or legacy ActionInterface. The invariant is that at most one of fun_ and
|
|
||||||
// impl_ may be nonnull; both are null iff this is the default action.
|
|
||||||
// FIXME: Fold the ActionInterface into std::function.
|
|
||||||
::std::function<F> fun_;
|
::std::function<F> fun_;
|
||||||
::std::shared_ptr<ActionInterface<F>> impl_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The PolymorphicAction class template makes it easy to implement a
|
// The PolymorphicAction class template makes it easy to implement a
|
||||||
@ -480,26 +478,6 @@ inline PolymorphicAction<Impl> MakePolymorphicAction(const Impl& impl) {
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// Allows an Action<F2> object to pose as an Action<F1>, as long as F2
|
|
||||||
// and F1 are compatible.
|
|
||||||
template <typename F1, typename F2>
|
|
||||||
class ActionAdaptor : public ActionInterface<F1> {
|
|
||||||
public:
|
|
||||||
typedef typename internal::Function<F1>::Result Result;
|
|
||||||
typedef typename internal::Function<F1>::ArgumentTuple ArgumentTuple;
|
|
||||||
|
|
||||||
explicit ActionAdaptor(const Action<F2>& from) : impl_(from.impl_) {}
|
|
||||||
|
|
||||||
Result Perform(const ArgumentTuple& args) override {
|
|
||||||
return impl_->Perform(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::shared_ptr<ActionInterface<F2>> impl_;
|
|
||||||
|
|
||||||
GTEST_DISALLOW_ASSIGN_(ActionAdaptor);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper struct to specialize ReturnAction to execute a move instead of a copy
|
// Helper struct to specialize ReturnAction to execute a move instead of a copy
|
||||||
// on return. Useful for move-only types, but could be used on any type.
|
// on return. Useful for move-only types, but could be used on any type.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -1066,20 +1044,6 @@ struct DoAllAction {
|
|||||||
// EXPECT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin));
|
// EXPECT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin));
|
||||||
typedef internal::IgnoredValue Unused;
|
typedef internal::IgnoredValue Unused;
|
||||||
|
|
||||||
// This constructor allows us to turn an Action<From> object into an
|
|
||||||
// Action<To>, as long as To's arguments can be implicitly converted
|
|
||||||
// to From's and From's return type cann be implicitly converted to
|
|
||||||
// To's.
|
|
||||||
template <typename To>
|
|
||||||
template <typename From>
|
|
||||||
Action<To>::Action(const Action<From>& from)
|
|
||||||
:
|
|
||||||
fun_(from.fun_),
|
|
||||||
impl_(from.impl_ == nullptr
|
|
||||||
? nullptr
|
|
||||||
: new internal::ActionAdaptor<To, From>(from)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates an action that does actions a1, a2, ..., sequentially in
|
// Creates an action that does actions a1, a2, ..., sequentially in
|
||||||
// each invocation.
|
// each invocation.
|
||||||
template <typename... Action>
|
template <typename... Action>
|
||||||
|
Loading…
Reference in New Issue
Block a user