summaryrefslogtreecommitdiff
path: root/src/mongo/unittest/unittest.h
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2019-04-24 18:18:39 -0400
committerMathias Stearn <mathias@10gen.com>2019-05-01 19:14:20 -0400
commitf6d863188b71b420f13b8249579d34de76d80d9c (patch)
tree3d1de115082ca8bde41e6b9029b2bbb1d6e4cbb9 /src/mongo/unittest/unittest.h
parent3ca7cf08c389d877f4e427012533fa0785d96d10 (diff)
downloadmongo-f6d863188b71b420f13b8249579d34de76d80d9c.tar.gz
SERVER-40802 move some expensive and commonly instantiated functions out of line
Diffstat (limited to 'src/mongo/unittest/unittest.h')
-rw-r--r--src/mongo/unittest/unittest.h134
1 files changed, 114 insertions, 20 deletions
diff --git a/src/mongo/unittest/unittest.h b/src/mongo/unittest/unittest.h
index 13e037773a6..7d52c333934 100644
--- a/src/mongo/unittest/unittest.h
+++ b/src/mongo/unittest/unittest.h
@@ -103,8 +103,9 @@
* Binary comparison utility macro. Do not use directly.
*/
#define ASSERT_COMPARISON_(OP, a, b) \
- if (auto ca = ::mongo::unittest::ComparisonAssertion<::mongo::unittest::ComparisonOp::OP>( \
- __FILE__, __LINE__, #a, #b, a, b)) \
+ if (auto ca = \
+ ::mongo::unittest::ComparisonAssertion<::mongo::unittest::ComparisonOp::OP>::make( \
+ __FILE__, __LINE__, #a, #b, a, b)) \
ca.failure().stream()
/**
@@ -116,17 +117,17 @@
/**
* Assert a function call returns its input unchanged.
*/
-#define ASSERT_IDENTITY(INPUT, FUNCTION) \
- [&](auto&& v) { \
- if (auto ca = \
- ::mongo::unittest::ComparisonAssertion<::mongo::unittest::ComparisonOp::kEq>( \
- __FILE__, \
- __LINE__, \
- #INPUT, \
- #FUNCTION "(" #INPUT ")", \
- v, \
- FUNCTION(std::forward<decltype(v)>(v)))) \
- ca.failure().stream(); \
+#define ASSERT_IDENTITY(INPUT, FUNCTION) \
+ [&](auto&& v) { \
+ if (auto ca = ::mongo::unittest::ComparisonAssertion< \
+ ::mongo::unittest::ComparisonOp::kEq>::make(__FILE__, \
+ __LINE__, \
+ #INPUT, \
+ #FUNCTION "(" #INPUT ")", \
+ v, \
+ FUNCTION( \
+ std::forward<decltype(v)>(v)))) \
+ ca.failure().stream(); \
}(INPUT)
/**
@@ -636,14 +637,13 @@ private:
return ">="_sd;
}
-public:
template <typename A, typename B>
- ComparisonAssertion(const std::string& theFile,
- unsigned theLine,
- StringData aExpression,
- StringData bExpression,
- const A& a,
- const B& b) {
+ NOINLINE_DECL ComparisonAssertion(const char* theFile,
+ unsigned theLine,
+ StringData aExpression,
+ StringData bExpression,
+ const A& a,
+ const B& b) {
if (comparator(OpTag<op>{})(a, b)) {
return;
}
@@ -653,6 +653,41 @@ public:
<< opName << " " << b << ")";
_assertion = std::make_unique<TestAssertionFailure>(theFile, theLine, os.str());
}
+
+public:
+ // Use a single implementation (identical to the templated one) for all string-like types.
+ // This is particularly important to avoid making unique instantiations for each length of
+ // string literal.
+ static ComparisonAssertion make(const char* theFile,
+ unsigned theLine,
+ StringData aExpression,
+ StringData bExpression,
+ StringData a,
+ StringData b);
+
+
+ // Use a single implementation (identical to the templated one) for all pointer and array types.
+ // Note: this is selected instead of the StringData overload for char* and string literals
+ // because they are supposed to compare pointers, not contents.
+ static ComparisonAssertion make(const char* theFile,
+ unsigned theLine,
+ StringData aExpression,
+ StringData bExpression,
+ const void* a,
+ const void* b);
+ TEMPLATE(typename A, typename B)
+ REQUIRES(!(std::is_convertible_v<A, StringData> && std::is_convertible_v<B, StringData>)&& //
+ !(std::is_pointer_v<A> && std::is_pointer_v<B>)&& //
+ !(std::is_array_v<A> && std::is_array_v<B>))
+ static ComparisonAssertion make(const char* theFile,
+ unsigned theLine,
+ StringData aExpression,
+ StringData bExpression,
+ const A& a,
+ const B& b) {
+ return ComparisonAssertion(theFile, theLine, aExpression, bExpression, a, b);
+ }
+
explicit operator bool() const {
return static_cast<bool>(_assertion);
}
@@ -664,6 +699,65 @@ private:
std::unique_ptr<TestAssertionFailure> _assertion;
};
+// Explicit instantiation of ComparisonAssertion ctor and factory for a pair of types.
+#define TEMPLATE_COMPARISON_ASSERTION_CTOR_CROSS(EXTERN, OP, A, B) \
+ EXTERN template ComparisonAssertion<ComparisonOp::OP>::ComparisonAssertion( \
+ const char*, unsigned, StringData, StringData, const A&, const B&); \
+ EXTERN template ComparisonAssertion<ComparisonOp::OP> \
+ ComparisonAssertion<ComparisonOp::OP>::make( \
+ const char*, unsigned, StringData, StringData, const A&, const B&); \
+ EXTERN template ComparisonAssertion<ComparisonOp::OP>::ComparisonAssertion( \
+ const char*, unsigned, StringData, StringData, const B&, const A&); \
+ EXTERN template ComparisonAssertion<ComparisonOp::OP> \
+ ComparisonAssertion<ComparisonOp::OP>::make( \
+ const char*, unsigned, StringData, StringData, const B&, const A&)
+
+// Explicit instantiation of ComparisonAssertion ctor and factory for a single type.
+#define TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(EXTERN, OP, T) \
+ EXTERN template ComparisonAssertion<ComparisonOp::OP>::ComparisonAssertion( \
+ const char*, unsigned, StringData, StringData, const T&, const T&); \
+ EXTERN template ComparisonAssertion<ComparisonOp::OP> \
+ ComparisonAssertion<ComparisonOp::OP>::make( \
+ const char*, unsigned, StringData, StringData, const T&, const T&)
+
+// Call with `extern` to declace extern instantiations, and with no args to explicitly instantiate.
+#define INSTANTIATE_COMPARISON_ASSERTION_CTORS(...) \
+ __VA_ARGS__ template class ComparisonAssertion<ComparisonOp::kEq>; \
+ __VA_ARGS__ template class ComparisonAssertion<ComparisonOp::kNe>; \
+ __VA_ARGS__ template class ComparisonAssertion<ComparisonOp::kGt>; \
+ __VA_ARGS__ template class ComparisonAssertion<ComparisonOp::kGe>; \
+ __VA_ARGS__ template class ComparisonAssertion<ComparisonOp::kLt>; \
+ __VA_ARGS__ template class ComparisonAssertion<ComparisonOp::kLe>; \
+ \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, int); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, long); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, long long); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, unsigned int); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, unsigned long); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, unsigned long long); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, bool); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, double); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, OID); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, BSONType); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, Timestamp); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, Date_t); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, Status); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kEq, ErrorCodes::Error); \
+ \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_CROSS(__VA_ARGS__, kEq, int, long); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_CROSS(__VA_ARGS__, kEq, int, long long); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_CROSS(__VA_ARGS__, kEq, long, long long); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_CROSS(__VA_ARGS__, kEq, unsigned int, unsigned long); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_CROSS(__VA_ARGS__, kEq, Status, ErrorCodes::Error); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_CROSS(__VA_ARGS__, kEq, ErrorCodes::Error, int); \
+ \
+ /* These are the only types that are often used with ASSERT_NE*/ \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kNe, Status); \
+ TEMPLATE_COMPARISON_ASSERTION_CTOR_SELF(__VA_ARGS__, kNe, unsigned long);
+
+// Declare that these definitions will be provided in unittest.cpp.
+INSTANTIATE_COMPARISON_ASSERTION_CTORS(extern);
+
/**
* Get the value out of a StatusWith<T>, or throw an exception if it is not OK.
*/