From f6d863188b71b420f13b8249579d34de76d80d9c Mon Sep 17 00:00:00 2001 From: Mathias Stearn Date: Wed, 24 Apr 2019 18:18:39 -0400 Subject: SERVER-40802 move some expensive and commonly instantiated functions out of line --- src/mongo/unittest/unittest.h | 134 +++++++++++++++++++++++++++++++++++------- 1 file changed, 114 insertions(+), 20 deletions(-) (limited to 'src/mongo/unittest/unittest.h') 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(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(v)))) \ + ca.failure().stream(); \ }(INPUT) /** @@ -636,14 +637,13 @@ private: return ">="_sd; } -public: template - 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{})(a, b)) { return; } @@ -653,6 +653,41 @@ public: << opName << " " << b << ")"; _assertion = std::make_unique(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 && std::is_convertible_v)&& // + !(std::is_pointer_v && std::is_pointer_v)&& // + !(std::is_array_v && std::is_array_v)) + 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(_assertion); } @@ -664,6 +699,65 @@ private: std::unique_ptr _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::ComparisonAssertion( \ + const char*, unsigned, StringData, StringData, const A&, const B&); \ + EXTERN template ComparisonAssertion \ + ComparisonAssertion::make( \ + const char*, unsigned, StringData, StringData, const A&, const B&); \ + EXTERN template ComparisonAssertion::ComparisonAssertion( \ + const char*, unsigned, StringData, StringData, const B&, const A&); \ + EXTERN template ComparisonAssertion \ + ComparisonAssertion::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::ComparisonAssertion( \ + const char*, unsigned, StringData, StringData, const T&, const T&); \ + EXTERN template ComparisonAssertion \ + ComparisonAssertion::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; \ + __VA_ARGS__ template class ComparisonAssertion; \ + __VA_ARGS__ template class ComparisonAssertion; \ + __VA_ARGS__ template class ComparisonAssertion; \ + __VA_ARGS__ template class ComparisonAssertion; \ + __VA_ARGS__ template class ComparisonAssertion; \ + \ + 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, or throw an exception if it is not OK. */ -- cgit v1.2.1