Don't take ownership of SECTION's name for inactive sections

This eliminates 1945 (432709 -> 430764) allocations from running
`./tests/SelfTest -o /dev/null`. In general terms, this saves
an allocation every time an unvisited `SECTION` is passed, which
means that the saved allocations are quadratic in number of sibling
(same level) `SECTION`s in a test case.
This commit is contained in:
Martin Hořeňovský 2023-01-28 00:35:40 +01:00
parent 43f02027e4
commit 65ffee5189
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
5 changed files with 34 additions and 7 deletions

View File

@ -44,8 +44,9 @@ namespace Catch {
public: public:
virtual ~IResultCapture(); virtual ~IResultCapture();
virtual bool sectionStarted( SectionInfo const& sectionInfo, virtual bool sectionStarted( StringRef sectionName,
Counts& assertions ) = 0; SourceLineInfo const& sectionLineInfo,
Counts& assertions ) = 0;
virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0; virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0;

View File

@ -297,13 +297,17 @@ namespace Catch {
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
} }
bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { bool RunContext::sectionStarted(StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts & assertions) {
ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(sectionInfo.name, sectionInfo.lineInfo)); ITracker& sectionTracker =
SectionTracker::acquire( m_trackerContext,
TestCaseTracking::NameAndLocationRef(
sectionName, sectionLineInfo ) );
if (!sectionTracker.isOpen()) if (!sectionTracker.isOpen())
return false; return false;
m_activeSections.push_back(&sectionTracker); m_activeSections.push_back(&sectionTracker);
SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
m_reporter->sectionStarting(sectionInfo); m_reporter->sectionStarting(sectionInfo);

View File

@ -68,7 +68,9 @@ namespace Catch {
ResultWas::OfType resultType, ResultWas::OfType resultType,
AssertionReaction &reaction ) override; AssertionReaction &reaction ) override;
bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; bool sectionStarted( StringRef sectionName,
SourceLineInfo const& sectionLineInfo,
Counts& assertions ) override;
void sectionEnded( SectionEndInfo&& endInfo ) override; void sectionEnded( SectionEndInfo&& endInfo ) override;
void sectionEndedEarly( SectionEndInfo&& endInfo ) override; void sectionEndedEarly( SectionEndInfo&& endInfo ) override;

View File

@ -15,7 +15,7 @@ namespace Catch {
Section::Section( SectionInfo&& info ): Section::Section( SectionInfo&& info ):
m_info( CATCH_MOVE( info ) ), m_info( CATCH_MOVE( info ) ),
m_sectionIncluded( m_sectionIncluded(
getResultCapture().sectionStarted( m_info, m_assertions ) ) { getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) {
// Non-"included" sections will not use the timing information // Non-"included" sections will not use the timing information
// anyway, so don't bother with the potential syscall. // anyway, so don't bother with the potential syscall.
if (m_sectionIncluded) { if (m_sectionIncluded) {
@ -23,6 +23,23 @@ namespace Catch {
} }
} }
Section::Section( SourceLineInfo const& _lineInfo,
StringRef _name,
const char* const ):
m_info( { "invalid", static_cast<std::size_t>(-1) }, "" ),
m_sectionIncluded(
getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
// We delay initialization the SectionInfo member until we know
// this section needs it, so we avoid allocating std::string for name.
// We also delay timer start to avoid the potential syscall unless we
// will actually use the result.
if ( m_sectionIncluded ) {
m_info.name = static_cast<std::string>( _name );
m_info.lineInfo = _lineInfo;
m_timer.start();
}
}
Section::~Section() { Section::~Section() {
if( m_sectionIncluded ) { if( m_sectionIncluded ) {
SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() }; SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() };

View File

@ -20,6 +20,9 @@ namespace Catch {
class Section : Detail::NonCopyable { class Section : Detail::NonCopyable {
public: public:
Section( SectionInfo&& info ); Section( SectionInfo&& info );
Section( SourceLineInfo const& _lineInfo,
StringRef _name,
const char* const = nullptr );
~Section(); ~Section();
// This indicates whether the section should be executed or not // This indicates whether the section should be executed or not
@ -38,7 +41,7 @@ namespace Catch {
#define INTERNAL_CATCH_SECTION( ... ) \ #define INTERNAL_CATCH_SECTION( ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \