Optimize string building in QCommandLineParserPrivate::helpText()

- Don't detach QCoreApplication::arguments() by calling first(),
  call constFirst()
- Use
    QString foo;
    foo += initial;
  instead of
    QString foo = initial;
  where 'foo' receives more appends later (does not force an
  initial capacity that is known to be too small).
- Use QStringBuilder more
- Don't use QStringLiteral in QStringBuilder expressions
- Reserve optionNameList. Its max. size is known ahead of time.
- Don't create optionNameStrings for hidden options.
  The result was never used, they just served as placeholders
  for the lock-step iteration that followed and wrapped the text.
- Don't create a QStringList to join(), append to the result
  string directly.
- Cache the return value of option.valueName().

Not only is this faster, it also saves more than 2KiB in text
size on optimized GCC 4.9 Linux AMD64 builds.

Change-Id: Id1d88f3c36a521ac71f3a7436810ed31319077ae
Reviewed-by: David Faure <david.faure@kdab.com>
bb10
Marc Mutz 2015-12-25 16:58:47 +01:00
parent db0453742c
commit ad74c95399
1 changed files with 22 additions and 20 deletions

View File

@ -1069,16 +1069,12 @@ QString QCommandLineParserPrivate::helpText() const
{
const QLatin1Char nl('\n');
QString text;
const QString exeName = QCoreApplication::instance()->arguments().first();
QString usage = exeName;
if (!commandLineOptionList.isEmpty()) {
usage += QLatin1Char(' ');
usage += QCommandLineParser::tr("[options]");
}
foreach (const PositionalArgumentDefinition &arg, positionalArgumentDefinitions) {
usage += QLatin1Char(' ');
usage += arg.syntax;
}
QString usage;
usage += QCoreApplication::instance()->arguments().constFirst(); // executable name
if (!commandLineOptionList.isEmpty())
usage += QLatin1Char(' ') + QCommandLineParser::tr("[options]");
foreach (const PositionalArgumentDefinition &arg, positionalArgumentDefinitions)
usage += QLatin1Char(' ') + arg.syntax;
text += QCommandLineParser::tr("Usage: %1").arg(usage) + nl;
if (!description.isEmpty())
text += description + nl;
@ -1086,27 +1082,33 @@ QString QCommandLineParserPrivate::helpText() const
if (!commandLineOptionList.isEmpty())
text += QCommandLineParser::tr("Options:") + nl;
QStringList optionNameList;
optionNameList.reserve(commandLineOptionList.size());
int longestOptionNameString = 0;
foreach (const QCommandLineOption &option, commandLineOptionList) {
QStringList optionNames;
foreach (const QString &optionName, option.names()) {
if (optionName.length() == 1)
optionNames.append(QLatin1Char('-') + optionName);
else
optionNames.append(QStringLiteral("--") + optionName);
if (option.isHidden())
continue;
const QStringList optionNames = option.names();
QString optionNamesString;
foreach (const QString &optionName, optionNames) {
const int numDashes = optionName.length() == 1 ? 1 : 2;
optionNamesString += QLatin1String("--", numDashes) + optionName + QLatin1String(", ");
}
QString optionNamesString = optionNames.join(QStringLiteral(", "));
if (!option.valueName().isEmpty())
optionNamesString += QStringLiteral(" <") + option.valueName() + QLatin1Char('>');
if (!optionNames.isEmpty())
optionNamesString.chop(2); // remove trailing ", "
const auto valueName = option.valueName();
if (!valueName.isEmpty())
optionNamesString += QLatin1String(" <") + valueName + QLatin1Char('>');
optionNameList.append(optionNamesString);
longestOptionNameString = qMax(longestOptionNameString, optionNamesString.length());
}
++longestOptionNameString;
auto optionNameIterator = optionNameList.cbegin();
for (int i = 0; i < commandLineOptionList.count(); ++i) {
const QCommandLineOption &option = commandLineOptionList.at(i);
if (option.isHidden())
continue;
text += wrapText(optionNameList.at(i), longestOptionNameString, option.description());
text += wrapText(*optionNameIterator, longestOptionNameString, option.description());
++optionNameIterator;
}
if (!positionalArgumentDefinitions.isEmpty()) {
if (!commandLineOptionList.isEmpty())