From 2ebd7dc10e2257a5195d6688c37da94daf5b8ce5 Mon Sep 17 00:00:00 2001 From: Eirik Byrkjeflot Anonsen Date: Tue, 5 Apr 2016 18:21:49 +0200 Subject: [PATCH] Eliminate dynamic cast by implementing MultipleReporters as a linked list This eliminates one use of RTTI in Catch. I also tend to think that this is a more sensible design. --- include/reporters/catch_reporter_multi.hpp | 131 ++++++++++----------- 1 file changed, 60 insertions(+), 71 deletions(-) diff --git a/include/reporters/catch_reporter_multi.hpp b/include/reporters/catch_reporter_multi.hpp index d3282666..a9bedd89 100644 --- a/include/reporters/catch_reporter_multi.hpp +++ b/include/reporters/catch_reporter_multi.hpp @@ -13,132 +13,121 @@ namespace Catch { class MultipleReporters : public SharedImpl { - typedef std::vector > Reporters; - Reporters m_reporters; + Ptr m_reporter; + Ptr m_next; public: + MultipleReporters( Ptr const& reporter ) + : m_reporter( reporter ) + , m_next( CATCH_NULL ) + { + } + + MultipleReporters( Ptr const& first, Ptr const& second ) + : m_reporter( first ) + , m_next( new MultipleReporters( second ) ) + { + } + void add( Ptr const& reporter ) { - m_reporters.push_back( reporter ); + if( m_next ) + m_next->add( reporter ); + else + m_next = new MultipleReporters( reporter ); } public: // IStreamingReporter virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { - return m_reporters[0]->getPreferences(); + return m_reporter->getPreferences(); } virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->noMatchingTestCases( spec ); + m_reporter->noMatchingTestCases( spec ); + if( m_next ) + m_next->noMatchingTestCases( spec ); } virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testRunStarting( testRunInfo ); + m_reporter->testRunStarting( testRunInfo ); + if( m_next ) + m_next->testRunStarting( testRunInfo ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testGroupStarting( groupInfo ); + m_reporter->testGroupStarting( groupInfo ); + if( m_next ) + m_next->testGroupStarting( groupInfo ); } virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testCaseStarting( testInfo ); + m_reporter->testCaseStarting( testInfo ); + if( m_next ) + m_next->testCaseStarting( testInfo ); } virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->sectionStarting( sectionInfo ); + m_reporter->sectionStarting( sectionInfo ); + if( m_next ) + m_next->sectionStarting( sectionInfo ); } virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->assertionStarting( assertionInfo ); + m_reporter->assertionStarting( assertionInfo ); + if( m_next ) + m_next->assertionStarting( assertionInfo ); } // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { - bool clearBuffer = false; - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - clearBuffer |= (*it)->assertionEnded( assertionStats ); + bool clearBuffer = m_reporter->assertionEnded( assertionStats ); + // Be careful with how the two calls' return values are anded. + // We don't want short-circuiting to eliminate one of the calls. + if( m_next && m_next->assertionEnded( assertionStats ) ) + return true; return clearBuffer; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->sectionEnded( sectionStats ); + m_reporter->sectionEnded( sectionStats ); + if( m_next ) + m_next->sectionEnded( sectionStats ); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testCaseEnded( testCaseStats ); + m_reporter->testCaseEnded( testCaseStats ); + if( m_next ) + m_next->testCaseEnded( testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testGroupEnded( testGroupStats ); + m_reporter->testGroupEnded( testGroupStats ); + if( m_next ) + m_next->testGroupEnded( testGroupStats ); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testRunEnded( testRunStats ); + m_reporter->testRunEnded( testRunStats ); + if( m_next ) + m_next->testRunEnded( testRunStats ); } virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->skipTest( testInfo ); + m_reporter->skipTest( testInfo ); + if( m_next ) + m_next->skipTest( testInfo ); } }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { - Ptr resultingReporter; - - if( existingReporter ) { - MultipleReporters* multi = dynamic_cast( existingReporter.get() ); - if( !multi ) { - multi = new MultipleReporters; - resultingReporter = Ptr( multi ); - if( existingReporter ) - multi->add( existingReporter ); - } - else - resultingReporter = existingReporter; - multi->add( additionalReporter ); - } - else - resultingReporter = additionalReporter; - - return resultingReporter; + if( !existingReporter ) + return additionalReporter; + return Ptr( new MultipleReporters(existingReporter, additionalReporter) ); }