mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 05:16:10 +01:00
Args and TokenStream use StringRefs instead of std::strings
Because TokenStream is copied around a lot, moving it to use `StringRef` removes _a lot_ of allocations per `Opt` in the parser. Args are not copied around much, but changing them as well makes it obvious that they do not participate in the ownership. The changes add up to removing ~180 allocations for "empty" invocation of the test binary. (`./tests/ExtraTests/NoTests --allow-running-no-tests -o /dev/null` is down to 317 allocs)
This commit is contained in:
parent
cd3c7ebe87
commit
5d637d4c6b
@ -37,6 +37,19 @@ namespace {
|
||||
return optName;
|
||||
}
|
||||
|
||||
static size_t find_first_separator(Catch::StringRef sr) {
|
||||
auto is_separator = []( char c ) {
|
||||
return c == ' ' || c == ':' || c == '=';
|
||||
};
|
||||
size_t pos = 0;
|
||||
while (pos < sr.size()) {
|
||||
if (is_separator(sr[pos])) { return pos; }
|
||||
++pos;
|
||||
}
|
||||
|
||||
return Catch::StringRef::npos;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Catch {
|
||||
@ -52,23 +65,23 @@ namespace Catch {
|
||||
}
|
||||
|
||||
if ( it != itEnd ) {
|
||||
auto const& next = *it;
|
||||
StringRef next = *it;
|
||||
if ( isOptPrefix( next[0] ) ) {
|
||||
auto delimiterPos = next.find_first_of( " :=" );
|
||||
if ( delimiterPos != std::string::npos ) {
|
||||
auto delimiterPos = find_first_separator(next);
|
||||
if ( delimiterPos != StringRef::npos ) {
|
||||
m_tokenBuffer.push_back(
|
||||
{ TokenType::Option,
|
||||
next.substr( 0, delimiterPos ) } );
|
||||
m_tokenBuffer.push_back(
|
||||
{ TokenType::Argument,
|
||||
next.substr( delimiterPos + 1 ) } );
|
||||
next.substr( delimiterPos + 1, next.size() ) } );
|
||||
} else {
|
||||
if ( next[1] != '-' && next.size() > 2 ) {
|
||||
std::string opt = "- ";
|
||||
// Combined short args, e.g. "-ab" for "-a -b"
|
||||
for ( size_t i = 1; i < next.size(); ++i ) {
|
||||
opt[1] = next[i];
|
||||
m_tokenBuffer.push_back(
|
||||
{ TokenType::Option, opt } );
|
||||
{ TokenType::Option,
|
||||
next.substr( i, 1 ) } );
|
||||
}
|
||||
} else {
|
||||
m_tokenBuffer.push_back(
|
||||
@ -128,7 +141,7 @@ namespace Catch {
|
||||
size_t ParserBase::cardinality() const { return 1; }
|
||||
|
||||
InternalParseResult ParserBase::parse( Args const& args ) const {
|
||||
return parse( args.exeName(), TokenStream( args ) );
|
||||
return parse( static_cast<std::string>(args.exeName()), TokenStream( args ) );
|
||||
}
|
||||
|
||||
ParseState::ParseState( ParseResultType type,
|
||||
@ -166,7 +179,7 @@ namespace Catch {
|
||||
auto valueRef =
|
||||
static_cast<Detail::BoundValueRefBase*>(m_ref.get());
|
||||
|
||||
auto result = valueRef->setValue(remainingTokens->token);
|
||||
auto result = valueRef->setValue(static_cast<std::string>(token.token));
|
||||
if (!result)
|
||||
return Detail::InternalParseResult(result);
|
||||
else
|
||||
@ -192,7 +205,7 @@ namespace Catch {
|
||||
return { oss.str(), m_description };
|
||||
}
|
||||
|
||||
bool Opt::isMatch(std::string const& optToken) const {
|
||||
bool Opt::isMatch(StringRef optToken) const {
|
||||
auto normalisedToken = normaliseOpt(optToken);
|
||||
for (auto const& name : m_optNames) {
|
||||
if (normaliseOpt(name) == normalisedToken)
|
||||
@ -237,7 +250,7 @@ namespace Catch {
|
||||
return Detail::InternalParseResult::runtimeError(
|
||||
"Expected argument following " +
|
||||
token.token);
|
||||
const auto result = valueRef->setValue(argToken.token);
|
||||
const auto result = valueRef->setValue(static_cast<std::string>(argToken.token));
|
||||
if (!result)
|
||||
return Detail::InternalParseResult(result);
|
||||
if (result.value() ==
|
||||
@ -433,7 +446,7 @@ namespace Catch {
|
||||
Args::Args(int argc, char const* const* argv) :
|
||||
m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
|
||||
|
||||
Args::Args(std::initializer_list<std::string> args) :
|
||||
Args::Args(std::initializer_list<StringRef> args) :
|
||||
m_exeName(*args.begin()),
|
||||
m_args(args.begin() + 1, args.end()) {}
|
||||
|
||||
|
@ -102,17 +102,16 @@ namespace Catch {
|
||||
enum class TokenType { Option, Argument };
|
||||
struct Token {
|
||||
TokenType type;
|
||||
std::string token;
|
||||
StringRef token;
|
||||
};
|
||||
|
||||
// Abstracts iterators into args as a stream of tokens, with option
|
||||
// arguments uniformly handled
|
||||
class TokenStream {
|
||||
using Iterator = std::vector<std::string>::const_iterator;
|
||||
using Iterator = std::vector<StringRef>::const_iterator;
|
||||
Iterator it;
|
||||
Iterator itEnd;
|
||||
std::vector<Token> m_tokenBuffer;
|
||||
|
||||
void loadBuffer();
|
||||
|
||||
public:
|
||||
@ -582,7 +581,7 @@ namespace Catch {
|
||||
|
||||
Detail::HelpColumns getHelpColumns() const;
|
||||
|
||||
bool isMatch(std::string const& optToken) const;
|
||||
bool isMatch(StringRef optToken) const;
|
||||
|
||||
using ParserBase::parse;
|
||||
|
||||
@ -676,18 +675,20 @@ namespace Catch {
|
||||
Detail::TokenStream const& tokens) const override;
|
||||
};
|
||||
|
||||
// Transport for raw args (copied from main args, or supplied via
|
||||
// init list for testing)
|
||||
/**
|
||||
* Wrapper over argc + argv, assumes that the inputs outlive it
|
||||
*/
|
||||
class Args {
|
||||
friend Detail::TokenStream;
|
||||
std::string m_exeName;
|
||||
std::vector<std::string> m_args;
|
||||
StringRef m_exeName;
|
||||
std::vector<StringRef> m_args;
|
||||
|
||||
public:
|
||||
Args(int argc, char const* const* argv);
|
||||
Args(std::initializer_list<std::string> args);
|
||||
// Helper constructor for testing
|
||||
Args(std::initializer_list<StringRef> args);
|
||||
|
||||
std::string const& exeName() const { return m_exeName; }
|
||||
StringRef exeName() const { return m_exeName; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -25,6 +25,8 @@ namespace Catch {
|
||||
using size_type = std::size_t;
|
||||
using const_iterator = const char*;
|
||||
|
||||
static constexpr size_type npos{ static_cast<size_type>( -1 ) };
|
||||
|
||||
private:
|
||||
static constexpr char const* const s_empty = "";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user