summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2023-04-11 10:54:26 -0700
committerCopybara-Service <copybara-worker@google.com>2023-04-11 10:55:11 -0700
commit8fa9461cc28e053d66f17132808d287ae51575e2 (patch)
treedb0717a7f90d588243994b56d4bb206be31cc9a2
parent7f6f9c12adefe8130565b7425dc387d284c009e4 (diff)
downloadgoogletest-git-8fa9461cc28e053d66f17132808d287ae51575e2.tar.gz
Fix FunctionMocker compilation slowdown in 9d21db9e0a60a1ea61ec19331c9bc0dd33e907b1
The slowdown appears to be due to an implicit conversion of distinct (yet semantically identical) lambdas to `std::function`. Lifting out the lambdas into functors that don't get re-instantiated reduces compilation times by nearly half. Fixes #4156 PiperOrigin-RevId: 523447948 Change-Id: Ib0ae0761a54d7b1f2b706b14b2858eedf47e2297
-rw-r--r--googlemock/include/gmock/gmock-spec-builders.h73
1 files changed, 55 insertions, 18 deletions
diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h
index 4e498d8f..2a33acb1 100644
--- a/googlemock/include/gmock/gmock-spec-builders.h
+++ b/googlemock/include/gmock/gmock-spec-builders.h
@@ -204,6 +204,9 @@ class GTEST_API_ UntypedFunctionMockerBase {
using UntypedExpectations = std::vector<std::shared_ptr<ExpectationBase>>;
+ struct UninterestingCallCleanupHandler;
+ struct FailureCleanupHandler;
+
// Returns an Expectation object that references and co-owns exp,
// which must be an expectation on this mock function.
Expectation GetHandleOf(ExpectationBase* exp);
@@ -1396,6 +1399,41 @@ class Cleanup final {
std::function<void()> f_;
};
+struct UntypedFunctionMockerBase::UninterestingCallCleanupHandler {
+ CallReaction reaction;
+ std::stringstream& ss;
+
+ ~UninterestingCallCleanupHandler() {
+ ReportUninterestingCall(reaction, ss.str());
+ }
+};
+
+struct UntypedFunctionMockerBase::FailureCleanupHandler {
+ std::stringstream& ss;
+ std::stringstream& why;
+ std::stringstream& loc;
+ const ExpectationBase* untyped_expectation;
+ bool found;
+ bool is_excessive;
+
+ ~FailureCleanupHandler() {
+ ss << "\n" << why.str();
+
+ if (!found) {
+ // No expectation matches this call - reports a failure.
+ Expect(false, nullptr, -1, ss.str());
+ } else if (is_excessive) {
+ // We had an upper-bound violation and the failure message is in ss.
+ Expect(false, untyped_expectation->file(), untyped_expectation->line(),
+ ss.str());
+ } else {
+ // We had an expected call and the matching expectation is
+ // described in ss.
+ Log(kInfo, loc.str() + ss.str(), 2);
+ }
+ }
+};
+
template <typename F>
class FunctionMocker;
@@ -1794,8 +1832,15 @@ R FunctionMocker<R(Args...)>::InvokeWith(ArgumentTuple&& args)
//
// We use RAII to do the latter in case R is void or a non-moveable type. In
// either case we can't assign it to a local variable.
- const Cleanup report_uninteresting_call(
- [&] { ReportUninterestingCall(reaction, ss.str()); });
+ //
+ // Note that std::bind() is essential here.
+ // We *don't* use any local callback types (like lambdas).
+ // Doing so slows down compilation dramatically because the *constructor* of
+ // std::function<T> is re-instantiated with different template
+ // parameters each time.
+ const UninterestingCallCleanupHandler report_uninteresting_call = {
+ reaction, ss
+ };
return PerformActionAndPrintResult(nullptr, std::move(args), ss.str(), ss);
}
@@ -1839,22 +1884,14 @@ R FunctionMocker<R(Args...)>::InvokeWith(ArgumentTuple&& args)
//
// We use RAII to do the latter in case R is void or a non-moveable type. In
// either case we can't assign it to a local variable.
- const Cleanup handle_failures([&] {
- ss << "\n" << why.str();
-
- if (!found) {
- // No expectation matches this call - reports a failure.
- Expect(false, nullptr, -1, ss.str());
- } else if (is_excessive) {
- // We had an upper-bound violation and the failure message is in ss.
- Expect(false, untyped_expectation->file(), untyped_expectation->line(),
- ss.str());
- } else {
- // We had an expected call and the matching expectation is
- // described in ss.
- Log(kInfo, loc.str() + ss.str(), 2);
- }
- });
+ //
+ // Note that we *don't* use any local callback types (like lambdas) here.
+ // Doing so slows down compilation dramatically because the *constructor* of
+ // std::function<T> is re-instantiated with different template
+ // parameters each time.
+ const FailureCleanupHandler handle_failures = {
+ ss, why, loc, untyped_expectation, found, is_excessive
+ };
return PerformActionAndPrintResult(untyped_action, std::move(args), ss.str(),
ss);