mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 13:26:10 +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:
parent
5d637d4c6b
commit
eaafd07674
@ -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,16 +164,15 @@ 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 =
|
||||||
@ -183,8 +182,9 @@ namespace Catch {
|
|||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user