Cleanup help string construction in Clara

* Clara::Opt::getHelpColumns returns single item

  It could never return multiple items, but for some reason it
  was wrapping that single item in a vector.

* Use ReusableStringStream in Clara
* Reserve HelpColumns ahead of time
* Use StringRef for descriptions in HelpColumn type

The combination of these changes ends up removing about 7% (~200)
of allocations when Catch2 has to prepare output for `-h`.
This commit is contained in:
Martin Hořeňovský 2023-12-23 16:06:30 +01:00
parent 2295d2c8cc
commit 822c44a203
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
2 changed files with 11 additions and 9 deletions

View File

@ -11,6 +11,7 @@
#include <catch2/internal/catch_platform.hpp> #include <catch2/internal/catch_platform.hpp>
#include <catch2/internal/catch_string_manip.hpp> #include <catch2/internal/catch_string_manip.hpp>
#include <catch2/internal/catch_textflow.hpp> #include <catch2/internal/catch_textflow.hpp>
#include <catch2/internal/catch_reusable_string_stream.hpp>
#include <algorithm> #include <algorithm>
#include <ostream> #include <ostream>
@ -173,8 +174,8 @@ namespace Catch {
Opt::Opt(bool& ref) : Opt::Opt(bool& ref) :
ParserRefImpl(std::make_shared<Detail::BoundFlagRef>(ref)) {} ParserRefImpl(std::make_shared<Detail::BoundFlagRef>(ref)) {}
std::vector<Detail::HelpColumns> Opt::getHelpColumns() const { Detail::HelpColumns Opt::getHelpColumns() const {
std::ostringstream oss; ReusableStringStream oss;
bool first = true; bool first = true;
for (auto const& opt : m_optNames) { for (auto const& opt : m_optNames) {
if (first) if (first)
@ -185,7 +186,7 @@ namespace Catch {
} }
if (!m_hint.empty()) if (!m_hint.empty())
oss << " <" << m_hint << '>'; oss << " <" << m_hint << '>';
return { { oss.str(), static_cast<std::string>(m_description) } }; return { oss.str(), m_description };
} }
bool Opt::isMatch(std::string const& optToken) const { bool Opt::isMatch(std::string const& optToken) const {
@ -310,9 +311,9 @@ namespace Catch {
std::vector<Detail::HelpColumns> Parser::getHelpColumns() const { std::vector<Detail::HelpColumns> Parser::getHelpColumns() const {
std::vector<Detail::HelpColumns> cols; std::vector<Detail::HelpColumns> cols;
cols.reserve( m_options.size() );
for ( auto const& o : m_options ) { for ( auto const& o : m_options ) {
auto childCols = o.getHelpColumns(); cols.push_back(o.getHelpColumns());
cols.insert( cols.end(), childCols.begin(), childCols.end() );
} }
return cols; return cols;
} }
@ -355,7 +356,7 @@ namespace Catch {
.width( optWidth ) .width( optWidth )
.indent( 2 ) + .indent( 2 ) +
TextFlow::Spacer( 4 ) + TextFlow::Spacer( 4 ) +
TextFlow::Column( cols.right ) TextFlow::Column( static_cast<std::string>(cols.descriptions) )
.width( consoleWidth - 7 - optWidth ); .width( consoleWidth - 7 - optWidth );
os << row << '\n'; os << row << '\n';
} }

View File

@ -164,7 +164,8 @@ namespace Catch {
ResultType m_type; ResultType m_type;
}; };
template <typename T> class ResultValueBase : public ResultBase { template <typename T>
class ResultValueBase : public ResultBase {
public: public:
auto value() const -> T const& { auto value() const -> T const& {
enforceOk(); enforceOk();
@ -286,7 +287,7 @@ namespace Catch {
struct HelpColumns { struct HelpColumns {
std::string left; std::string left;
std::string right; StringRef descriptions;
}; };
template <typename T> template <typename T>
@ -571,7 +572,7 @@ namespace Catch {
return *this; return *this;
} }
std::vector<Detail::HelpColumns> getHelpColumns() const; Detail::HelpColumns getHelpColumns() const;
bool isMatch(std::string const& optToken) const; bool isMatch(std::string const& optToken) const;