aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Jacobs <jacobsa@google.com>2022-05-02 08:29:36 -0700
committerCopybara-Service <copybara-worker@google.com>2022-05-02 08:30:07 -0700
commit51767261238513893d0cbd3fe2d7822ea4cf57a9 (patch)
treef658e307bbcd9f2bf45eb9529472cf4d4151930b
parent8ded48c37be09d8cc3665af1b414c5d53c0862e7 (diff)
downloadgoogletest-51767261238513893d0cbd3fe2d7822ea4cf57a9.zip
googletest-51767261238513893d0cbd3fe2d7822ea4cf57a9.tar.gz
googletest-51767261238513893d0cbd3fe2d7822ea4cf57a9.tar.bz2
gmock-actions: support ByMove in a specialization of ReturnAction.
Rather than branching on whether the return type is ByMoveWrapper within ReturnAction itself, hoist the distinction to outside. This allows the main class template to be modified without worrying about this special case, which means we can stop using a shared pointer to the value (introduced as a linked_ptr in commit 3d1c78b2bf to support ByMove) in this commit and simplify the class template further in a future commit with the eventual aim of directly supporting move-only result types. PiperOrigin-RevId: 445938943 Change-Id: I7bc71ea301d5e493ac6ecbe57d62738a48a2721a
-rw-r--r--googlemock/include/gmock/gmock-actions.h59
1 files changed, 34 insertions, 25 deletions
diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h
index f9fee55..578315f 100644
--- a/googlemock/include/gmock/gmock-actions.h
+++ b/googlemock/include/gmock/gmock-actions.h
@@ -900,12 +900,12 @@ struct ByMoveWrapper {
// of gtl::Container() is passed into Return.
//
template <typename R>
-class ReturnAction {
+class ReturnAction final {
public:
// Constructs a ReturnAction object from the value to be returned.
// 'value' is passed by value instead of by const reference in order
// to allow Return("string literal") to compile.
- explicit ReturnAction(R value) : value_(new R(std::move(value))) {}
+ explicit ReturnAction(R value) : value_(std::move(value)) {}
// This template type conversion operator allows Return(x) to be
// used in ANY function that returns x's type.
@@ -924,19 +924,19 @@ class ReturnAction {
"use ReturnRef instead of Return to return a reference");
static_assert(!std::is_void<Result>::value,
"Can't use Return() on an action expected to return `void`.");
- return Action<F>(new Impl<R, F>(value_));
+ return Action<F>(new Impl<F>(value_));
}
private:
// Implements the Return(x) action for a particular function type F.
- template <typename R_, typename F>
+ template <typename F>
class Impl : public ActionInterface<F> {
public:
typedef typename Function<F>::Result Result;
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
- explicit Impl(const std::shared_ptr<R>& value)
- : value_before_cast_(*value),
+ explicit Impl(const R& value)
+ : value_before_cast_(value),
// Make an implicit conversion to Result before initializing the
// Result object we store, avoiding calling any explicit constructor
// of Result from R.
@@ -961,30 +961,39 @@ class ReturnAction {
Impl& operator=(const Impl&) = delete;
};
- // Partially specialize for ByMoveWrapper. This version of ReturnAction will
- // move its contents instead.
- template <typename R_, typename F>
- class Impl<ByMoveWrapper<R_>, F> : public ActionInterface<F> {
- public:
- typedef typename Function<F>::Result Result;
- typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+ R value_;
+};
+
+// A specialization of ReturnAction<R> when R is ByMoveWrapper<T> for some T.
+//
+// This version applies the type system-defeating hack of moving from T even in
+// the const call operator, checking at runtime that it isn't called more than
+// once, since the user has declared their intent to do so by using ByMove.
+template <typename T>
+class ReturnAction<ByMoveWrapper<T>> final {
+ public:
+ explicit ReturnAction(ByMoveWrapper<T> wrapper)
+ : state_(new State(std::move(wrapper.payload))) {}
- explicit Impl(const std::shared_ptr<R>& wrapper)
- : performed_(false), wrapper_(wrapper) {}
+ T operator()() const {
+ GTEST_CHECK_(!state_->called)
+ << "A ByMove() action must be performed at most once.";
- Result Perform(const ArgumentTuple&) override {
- GTEST_CHECK_(!performed_)
- << "A ByMove() action should only be performed once.";
- performed_ = true;
- return std::move(wrapper_->payload);
- }
+ state_->called = true;
+ return std::move(state_->value);
+ }
- private:
- bool performed_;
- const std::shared_ptr<R> wrapper_;
+ private:
+ // We store our state on the heap so that we are copyable as required by
+ // Action, despite the fact that we are stateful and T may not be copyable.
+ struct State {
+ explicit State(T&& value_in) : value(std::move(value_in)) {}
+
+ T value;
+ bool called = false;
};
- const std::shared_ptr<R> value_;
+ const std::shared_ptr<State> state_;
};
// Implements the ReturnNull() action.