Skip to content

Commit cd430b4

Browse files
Abseil Teamcopybara-github
authored andcommitted
AllOf, AnyOf, Optional: Avoid generating unnecessary match explanations
Previously, those matchers always invoked the child matchers with an IsInterested MatchResultListener, resulting in unnecessary work formatting match results that would be discarded. PiperOrigin-RevId: 750704295 Change-Id: I1639a3a15d269459f26b3aebc3a6cbdced6896a3
1 parent 155b337 commit cd430b4

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

googlemock/include/gmock/gmock-matchers.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,15 @@ class AllOfMatcherImpl : public MatcherInterface<const T&> {
13121312

13131313
bool MatchAndExplain(const T& x,
13141314
MatchResultListener* listener) const override {
1315+
if (!listener->IsInterested()) {
1316+
// Fast path to avoid unnecessary formatting.
1317+
for (const Matcher<T>& matcher : matchers_) {
1318+
if (!matcher.Matches(x)) {
1319+
return false;
1320+
}
1321+
}
1322+
return true;
1323+
}
13151324
// This method uses matcher's explanation when explaining the result.
13161325
// However, if matcher doesn't provide one, this method uses matcher's
13171326
// description.
@@ -1431,6 +1440,15 @@ class AnyOfMatcherImpl : public MatcherInterface<const T&> {
14311440

14321441
bool MatchAndExplain(const T& x,
14331442
MatchResultListener* listener) const override {
1443+
if (!listener->IsInterested()) {
1444+
// Fast path to avoid unnecessary formatting of match explanations.
1445+
for (const Matcher<T>& matcher : matchers_) {
1446+
if (matcher.Matches(x)) {
1447+
return true;
1448+
}
1449+
}
1450+
return false;
1451+
}
14341452
// This method uses matcher's explanation when explaining the result.
14351453
// However, if matcher doesn't provide one, this method uses matcher's
14361454
// description.
@@ -4118,6 +4136,10 @@ class OptionalMatcher {
41184136
return false;
41194137
}
41204138
const ValueType& value = *optional;
4139+
if (!listener->IsInterested()) {
4140+
// Fast path to avoid unnecessary generation of match explanation.
4141+
return value_matcher_.Matches(value);
4142+
}
41214143
StringMatchResultListener value_listener;
41224144
const bool match = value_matcher_.MatchAndExplain(value, &value_listener);
41234145
*listener << "whose value " << PrintToString(value)

googlemock/test/gmock-matchers-comparisons_test.cc

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
#include <functional>
3535
#include <memory>
36+
#include <optional>
3637
#include <string>
3738
#include <tuple>
3839
#include <vector>
@@ -2396,6 +2397,74 @@ TEST(ExplainMatchResultTest, AllOf_True_True_2) {
23962397
EXPECT_EQ("is >= 2, and is <= 3", Explain(m, 2));
23972398
}
23982399

2400+
// A matcher that records whether the listener was interested.
2401+
template <typename T>
2402+
class CountingMatcher : public MatcherInterface<T> {
2403+
public:
2404+
explicit CountingMatcher(const Matcher<T>& base_matcher,
2405+
std::vector<bool>* listener_interested)
2406+
: base_matcher_(base_matcher),
2407+
listener_interested_(listener_interested) {}
2408+
2409+
bool MatchAndExplain(T x, MatchResultListener* listener) const override {
2410+
listener_interested_->push_back(listener->IsInterested());
2411+
return base_matcher_.MatchAndExplain(x, listener);
2412+
}
2413+
2414+
void DescribeTo(ostream* os) const override { base_matcher_.DescribeTo(os); }
2415+
2416+
private:
2417+
Matcher<T> base_matcher_;
2418+
std::vector<bool>* listener_interested_;
2419+
};
2420+
2421+
TEST(AllOfTest, DoesNotFormatChildMatchersWhenNotInterested) {
2422+
std::vector<bool> listener_interested;
2423+
Matcher<int> matcher =
2424+
MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested));
2425+
EXPECT_TRUE(matcher.Matches(1));
2426+
EXPECT_THAT(listener_interested, ElementsAre(false));
2427+
listener_interested.clear();
2428+
Matcher<int> all_of_matcher = AllOf(matcher, matcher);
2429+
EXPECT_TRUE(all_of_matcher.Matches(1));
2430+
EXPECT_THAT(listener_interested, ElementsAre(false, false));
2431+
listener_interested.clear();
2432+
EXPECT_FALSE(all_of_matcher.Matches(0));
2433+
EXPECT_THAT(listener_interested, ElementsAre(false));
2434+
}
2435+
2436+
TEST(AnyOfTest, DoesNotFormatChildMatchersWhenNotInterested) {
2437+
std::vector<bool> listener_interested;
2438+
Matcher<int> matcher =
2439+
MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested));
2440+
EXPECT_TRUE(matcher.Matches(1));
2441+
EXPECT_THAT(listener_interested, ElementsAre(false));
2442+
listener_interested.clear();
2443+
Matcher<int> any_of_matcher = AnyOf(matcher, matcher);
2444+
EXPECT_TRUE(any_of_matcher.Matches(1));
2445+
EXPECT_THAT(listener_interested, ElementsAre(false));
2446+
listener_interested.clear();
2447+
EXPECT_FALSE(any_of_matcher.Matches(0));
2448+
EXPECT_THAT(listener_interested, ElementsAre(false, false));
2449+
}
2450+
2451+
TEST(OptionalTest, DoesNotFormatChildMatcherWhenNotInterested) {
2452+
std::vector<bool> listener_interested;
2453+
Matcher<int> matcher =
2454+
MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested));
2455+
EXPECT_TRUE(matcher.Matches(1));
2456+
EXPECT_THAT(listener_interested, ElementsAre(false));
2457+
listener_interested.clear();
2458+
Matcher<std::optional<int>> optional_matcher = Optional(matcher);
2459+
EXPECT_FALSE(optional_matcher.Matches(std::nullopt));
2460+
EXPECT_THAT(listener_interested, ElementsAre());
2461+
EXPECT_TRUE(optional_matcher.Matches(1));
2462+
EXPECT_THAT(listener_interested, ElementsAre(false));
2463+
listener_interested.clear();
2464+
EXPECT_FALSE(matcher.Matches(0));
2465+
EXPECT_THAT(listener_interested, ElementsAre(false));
2466+
}
2467+
23992468
INSTANTIATE_GTEST_MATCHER_TEST_P(ExplainmatcherResultTest);
24002469

24012470
TEST_P(ExplainmatcherResultTestP, MonomorphicMatcher) {

0 commit comments

Comments
 (0)