mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Avoid copying TokenStreams while parsing
The code is now even worse mess than before, due to the ad-hoc implementation of Result-ish type based on virtual functions in Clara, but it has dropped the allocations for empty binary down to 151.
This commit is contained in:
		| @@ -145,8 +145,8 @@ namespace Catch { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             ParseState::ParseState( ParseResultType type, |             ParseState::ParseState( ParseResultType type, | ||||||
|                                     TokenStream const& remainingTokens ): |                                     TokenStream remainingTokens ): | ||||||
|                 m_type( type ), m_remainingTokens( remainingTokens ) {} |                 m_type( type ), m_remainingTokens( CATCH_MOVE(remainingTokens) ) {} | ||||||
|  |  | ||||||
|             ParserResult BoundFlagRef::setFlag( bool flag ) { |             ParserResult BoundFlagRef::setFlag( bool flag ) { | ||||||
|                 m_ref = flag; |                 m_ref = flag; | ||||||
| @@ -164,27 +164,27 @@ namespace Catch { | |||||||
| } // namespace Detail | } // namespace Detail | ||||||
|  |  | ||||||
|         Detail::InternalParseResult Arg::parse(std::string const&, |         Detail::InternalParseResult Arg::parse(std::string const&, | ||||||
|                                                Detail::TokenStream const& tokens) const { |                                                Detail::TokenStream tokens) const { | ||||||
|             auto validationResult = validate(); |             auto validationResult = validate(); | ||||||
|             if (!validationResult) |             if (!validationResult) | ||||||
|                 return Detail::InternalParseResult(validationResult); |                 return Detail::InternalParseResult(validationResult); | ||||||
|  |  | ||||||
|             auto remainingTokens = tokens; |             auto token = *tokens; | ||||||
|             auto const& token = *remainingTokens; |  | ||||||
|             if (token.type != Detail::TokenType::Argument) |             if (token.type != Detail::TokenType::Argument) | ||||||
|                 return Detail::InternalParseResult::ok(Detail::ParseState( |                 return Detail::InternalParseResult::ok(Detail::ParseState( | ||||||
|                     ParseResultType::NoMatch, remainingTokens)); |                     ParseResultType::NoMatch, CATCH_MOVE(tokens))); | ||||||
|  |  | ||||||
|             assert(!m_ref->isFlag()); |             assert(!m_ref->isFlag()); | ||||||
|             auto valueRef = |             auto valueRef = | ||||||
|                 static_cast<Detail::BoundValueRefBase*>(m_ref.get()); |                 static_cast<Detail::BoundValueRefBase*>(m_ref.get()); | ||||||
|  |  | ||||||
|             auto result = valueRef->setValue(static_cast<std::string>(token.token)); |             auto result = valueRef->setValue(static_cast<std::string>(token.token)); | ||||||
|             if (!result) |             if ( !result ) | ||||||
|                 return Detail::InternalParseResult(result); |                 return Detail::InternalParseResult( result ); | ||||||
|             else |             else | ||||||
|                 return Detail::InternalParseResult::ok(Detail::ParseState( |                 return Detail::InternalParseResult::ok( | ||||||
|                     ParseResultType::Matched, ++remainingTokens)); |                     Detail::ParseState( ParseResultType::Matched, | ||||||
|  |                                         CATCH_MOVE( ++tokens ) ) ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Opt::Opt(bool& ref) : |         Opt::Opt(bool& ref) : | ||||||
| @@ -215,15 +215,14 @@ namespace Catch { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         Detail::InternalParseResult Opt::parse(std::string const&, |         Detail::InternalParseResult Opt::parse(std::string const&, | ||||||
|                                        Detail::TokenStream const& tokens) const { |                                        Detail::TokenStream tokens) const { | ||||||
|             auto validationResult = validate(); |             auto validationResult = validate(); | ||||||
|             if (!validationResult) |             if (!validationResult) | ||||||
|                 return Detail::InternalParseResult(validationResult); |                 return Detail::InternalParseResult(validationResult); | ||||||
|  |  | ||||||
|             auto remainingTokens = tokens; |             if (tokens && | ||||||
|             if (remainingTokens && |                 tokens->type == Detail::TokenType::Option) { | ||||||
|                 remainingTokens->type == Detail::TokenType::Option) { |                 auto const& token = *tokens; | ||||||
|                 auto const& token = *remainingTokens; |  | ||||||
|                 if (isMatch(token.token)) { |                 if (isMatch(token.token)) { | ||||||
|                     if (m_ref->isFlag()) { |                     if (m_ref->isFlag()) { | ||||||
|                         auto flagRef = |                         auto flagRef = | ||||||
| @@ -235,17 +234,17 @@ namespace Catch { | |||||||
|                         if (result.value() == |                         if (result.value() == | ||||||
|                             ParseResultType::ShortCircuitAll) |                             ParseResultType::ShortCircuitAll) | ||||||
|                             return Detail::InternalParseResult::ok(Detail::ParseState( |                             return Detail::InternalParseResult::ok(Detail::ParseState( | ||||||
|                                 result.value(), remainingTokens)); |                                 result.value(), CATCH_MOVE(tokens))); | ||||||
|                     } else { |                     } else { | ||||||
|                         auto valueRef = |                         auto valueRef = | ||||||
|                             static_cast<Detail::BoundValueRefBase*>( |                             static_cast<Detail::BoundValueRefBase*>( | ||||||
|                                 m_ref.get()); |                                 m_ref.get()); | ||||||
|                         ++remainingTokens; |                         ++tokens; | ||||||
|                         if (!remainingTokens) |                         if (!tokens) | ||||||
|                             return Detail::InternalParseResult::runtimeError( |                             return Detail::InternalParseResult::runtimeError( | ||||||
|                                 "Expected argument following " + |                                 "Expected argument following " + | ||||||
|                                 token.token); |                                 token.token); | ||||||
|                         auto const& argToken = *remainingTokens; |                         auto const& argToken = *tokens; | ||||||
|                         if (argToken.type != Detail::TokenType::Argument) |                         if (argToken.type != Detail::TokenType::Argument) | ||||||
|                             return Detail::InternalParseResult::runtimeError( |                             return Detail::InternalParseResult::runtimeError( | ||||||
|                                 "Expected argument following " + |                                 "Expected argument following " + | ||||||
| @@ -256,14 +255,14 @@ namespace Catch { | |||||||
|                         if (result.value() == |                         if (result.value() == | ||||||
|                             ParseResultType::ShortCircuitAll) |                             ParseResultType::ShortCircuitAll) | ||||||
|                             return Detail::InternalParseResult::ok(Detail::ParseState( |                             return Detail::InternalParseResult::ok(Detail::ParseState( | ||||||
|                                 result.value(), remainingTokens)); |                                 result.value(), CATCH_MOVE(tokens))); | ||||||
|                     } |                     } | ||||||
|                     return Detail::InternalParseResult::ok(Detail::ParseState( |                     return Detail::InternalParseResult::ok(Detail::ParseState( | ||||||
|                         ParseResultType::Matched, ++remainingTokens)); |                         ParseResultType::Matched, CATCH_MOVE(++tokens))); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return Detail::InternalParseResult::ok( |             return Detail::InternalParseResult::ok( | ||||||
|                 Detail::ParseState(ParseResultType::NoMatch, remainingTokens)); |                 Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens))); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Detail::Result Opt::validate() const { |         Detail::Result Opt::validate() const { | ||||||
| @@ -295,9 +294,9 @@ namespace Catch { | |||||||
|  |  | ||||||
|         Detail::InternalParseResult |         Detail::InternalParseResult | ||||||
|             ExeName::parse(std::string const&, |             ExeName::parse(std::string const&, | ||||||
|                            Detail::TokenStream const& tokens) const { |                            Detail::TokenStream tokens) const { | ||||||
|             return Detail::InternalParseResult::ok( |             return Detail::InternalParseResult::ok( | ||||||
|                 Detail::ParseState(ParseResultType::NoMatch, tokens)); |                 Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens))); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         ParserResult ExeName::set(std::string const& newName) { |         ParserResult ExeName::set(std::string const& newName) { | ||||||
| @@ -394,7 +393,7 @@ namespace Catch { | |||||||
|  |  | ||||||
|         Detail::InternalParseResult |         Detail::InternalParseResult | ||||||
|         Parser::parse( std::string const& exeName, |         Parser::parse( std::string const& exeName, | ||||||
|                        Detail::TokenStream const& tokens ) const { |                        Detail::TokenStream tokens ) const { | ||||||
|  |  | ||||||
|             struct ParserInfo { |             struct ParserInfo { | ||||||
|                 ParserBase const* parser = nullptr; |                 ParserBase const* parser = nullptr; | ||||||
| @@ -412,7 +411,7 @@ namespace Catch { | |||||||
|             m_exeName.set( exeName ); |             m_exeName.set( exeName ); | ||||||
|  |  | ||||||
|             auto result = Detail::InternalParseResult::ok( |             auto result = Detail::InternalParseResult::ok( | ||||||
|                 Detail::ParseState( ParseResultType::NoMatch, tokens ) ); |                 Detail::ParseState( ParseResultType::NoMatch, CATCH_MOVE(tokens) ) ); | ||||||
|             while ( result.value().remainingTokens() ) { |             while ( result.value().remainingTokens() ) { | ||||||
|                 bool tokenParsed = false; |                 bool tokenParsed = false; | ||||||
|  |  | ||||||
| @@ -420,7 +419,7 @@ namespace Catch { | |||||||
|                     if ( parseInfo.parser->cardinality() == 0 || |                     if ( parseInfo.parser->cardinality() == 0 || | ||||||
|                          parseInfo.count < parseInfo.parser->cardinality() ) { |                          parseInfo.count < parseInfo.parser->cardinality() ) { | ||||||
|                         result = parseInfo.parser->parse( |                         result = parseInfo.parser->parse( | ||||||
|                             exeName, result.value().remainingTokens() ); |                             exeName, CATCH_MOVE(result).value().remainingTokens() ); | ||||||
|                         if ( !result ) |                         if ( !result ) | ||||||
|                             return result; |                             return result; | ||||||
|                         if ( result.value().type() != |                         if ( result.value().type() != | ||||||
|   | |||||||
| @@ -166,10 +166,14 @@ namespace Catch { | |||||||
|             template <typename T> |             template <typename T> | ||||||
|             class ResultValueBase : public ResultBase { |             class ResultValueBase : public ResultBase { | ||||||
|             public: |             public: | ||||||
|                 auto value() const -> T const& { |                 T const& value() const& { | ||||||
|                     enforceOk(); |                     enforceOk(); | ||||||
|                     return m_value; |                     return m_value; | ||||||
|                 } |                 } | ||||||
|  |                 T&& value() && { | ||||||
|  |                     enforceOk(); | ||||||
|  |                     return CATCH_MOVE( m_value ); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|             protected: |             protected: | ||||||
|                 ResultValueBase( ResultType type ): ResultBase( type ) {} |                 ResultValueBase( ResultType type ): ResultBase( type ) {} | ||||||
| @@ -179,13 +183,23 @@ namespace Catch { | |||||||
|                     if ( m_type == ResultType::Ok ) |                     if ( m_type == ResultType::Ok ) | ||||||
|                         new ( &m_value ) T( other.m_value ); |                         new ( &m_value ) T( other.m_value ); | ||||||
|                 } |                 } | ||||||
|  |                 ResultValueBase( ResultValueBase&& other ): | ||||||
|                 ResultValueBase( ResultType, T const& value ): ResultBase( ResultType::Ok ) { |                     ResultBase( other ) { | ||||||
|                     new ( &m_value ) T( value ); |                     if ( m_type == ResultType::Ok ) | ||||||
|  |                         new ( &m_value ) T( CATCH_MOVE(other.m_value) ); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 auto operator=( ResultValueBase const& other ) |  | ||||||
|                     -> ResultValueBase& { |                 ResultValueBase( ResultType, T const& value ): | ||||||
|  |                     ResultBase( ResultType::Ok ) { | ||||||
|  |                     new ( &m_value ) T( value ); | ||||||
|  |                 } | ||||||
|  |                 ResultValueBase( ResultType, T&& value ): | ||||||
|  |                     ResultBase( ResultType::Ok ) { | ||||||
|  |                     new ( &m_value ) T( CATCH_MOVE(value) ); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 ResultValueBase& operator=( ResultValueBase const& other ) { | ||||||
|                     if ( m_type == ResultType::Ok ) |                     if ( m_type == ResultType::Ok ) | ||||||
|                         m_value.~T(); |                         m_value.~T(); | ||||||
|                     ResultBase::operator=( other ); |                     ResultBase::operator=( other ); | ||||||
| @@ -193,6 +207,14 @@ namespace Catch { | |||||||
|                         new ( &m_value ) T( other.m_value ); |                         new ( &m_value ) T( other.m_value ); | ||||||
|                     return *this; |                     return *this; | ||||||
|                 } |                 } | ||||||
|  |                 ResultValueBase& operator=( ResultValueBase&& other ) { | ||||||
|  |                     if ( m_type == ResultType::Ok ) m_value.~T(); | ||||||
|  |                     ResultBase::operator=( other ); | ||||||
|  |                     if ( m_type == ResultType::Ok ) | ||||||
|  |                         new ( &m_value ) T( CATCH_MOVE(other.m_value) ); | ||||||
|  |                     return *this; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |  | ||||||
|                 ~ResultValueBase() override { |                 ~ResultValueBase() override { | ||||||
|                     if ( m_type == ResultType::Ok ) |                     if ( m_type == ResultType::Ok ) | ||||||
| @@ -220,8 +242,8 @@ namespace Catch { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 template <typename U> |                 template <typename U> | ||||||
|                 static auto ok( U const& value ) -> BasicResult { |                 static auto ok( U&& value ) -> BasicResult { | ||||||
|                     return { ResultType::Ok, value }; |                     return { ResultType::Ok, CATCH_FORWARD(value) }; | ||||||
|                 } |                 } | ||||||
|                 static auto ok() -> BasicResult { return { ResultType::Ok }; } |                 static auto ok() -> BasicResult { return { ResultType::Ok }; } | ||||||
|                 static auto logicError( std::string&& message ) |                 static auto logicError( std::string&& message ) | ||||||
| @@ -268,12 +290,15 @@ namespace Catch { | |||||||
|             class ParseState { |             class ParseState { | ||||||
|             public: |             public: | ||||||
|                 ParseState( ParseResultType type, |                 ParseState( ParseResultType type, | ||||||
|                             TokenStream const& remainingTokens ); |                             TokenStream remainingTokens ); | ||||||
|  |  | ||||||
|                 ParseResultType type() const { return m_type; } |                 ParseResultType type() const { return m_type; } | ||||||
|                 TokenStream const& remainingTokens() const { |                 TokenStream const& remainingTokens() const& { | ||||||
|                     return m_remainingTokens; |                     return m_remainingTokens; | ||||||
|                 } |                 } | ||||||
|  |                 TokenStream&& remainingTokens() && { | ||||||
|  |                     return CATCH_MOVE( m_remainingTokens ); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|             private: |             private: | ||||||
|                 ParseResultType m_type; |                 ParseResultType m_type; | ||||||
| @@ -446,7 +471,7 @@ namespace Catch { | |||||||
|                 virtual ~ParserBase() = default; |                 virtual ~ParserBase() = default; | ||||||
|                 virtual auto validate() const -> Result { return Result::ok(); } |                 virtual auto validate() const -> Result { return Result::ok(); } | ||||||
|                 virtual auto parse( std::string const& exeName, |                 virtual auto parse( std::string const& exeName, | ||||||
|                                     TokenStream const& tokens ) const |                                     TokenStream tokens ) const | ||||||
|                     -> InternalParseResult = 0; |                     -> InternalParseResult = 0; | ||||||
|                 virtual size_t cardinality() const; |                 virtual size_t cardinality() const; | ||||||
|  |  | ||||||
| @@ -538,7 +563,7 @@ namespace Catch { | |||||||
|  |  | ||||||
|             Detail::InternalParseResult |             Detail::InternalParseResult | ||||||
|                 parse(std::string const&, |                 parse(std::string const&, | ||||||
|                       Detail::TokenStream const& tokens) const override; |                       Detail::TokenStream tokens) const override; | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         // A parser for options |         // A parser for options | ||||||
| @@ -587,7 +612,7 @@ namespace Catch { | |||||||
|  |  | ||||||
|             Detail::InternalParseResult |             Detail::InternalParseResult | ||||||
|                 parse(std::string const&, |                 parse(std::string const&, | ||||||
|                       Detail::TokenStream const& tokens) const override; |                       Detail::TokenStream tokens) const override; | ||||||
|  |  | ||||||
|             Detail::Result validate() const override; |             Detail::Result validate() const override; | ||||||
|         }; |         }; | ||||||
| @@ -610,7 +635,7 @@ namespace Catch { | |||||||
|             // handled specially |             // handled specially | ||||||
|             Detail::InternalParseResult |             Detail::InternalParseResult | ||||||
|                 parse(std::string const&, |                 parse(std::string const&, | ||||||
|                       Detail::TokenStream const& tokens) const override; |                       Detail::TokenStream tokens) const override; | ||||||
|  |  | ||||||
|             std::string const& name() const { return *m_name; } |             std::string const& name() const { return *m_name; } | ||||||
|             Detail::ParserResult set(std::string const& newName); |             Detail::ParserResult set(std::string const& newName); | ||||||
| @@ -672,7 +697,7 @@ namespace Catch { | |||||||
|             using ParserBase::parse; |             using ParserBase::parse; | ||||||
|             Detail::InternalParseResult |             Detail::InternalParseResult | ||||||
|                 parse(std::string const& exeName, |                 parse(std::string const& exeName, | ||||||
|                       Detail::TokenStream const& tokens) const override; |                       Detail::TokenStream tokens) const override; | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         /** |         /** | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Martin Hořeňovský
					Martin Hořeňovský