QString: add QStringView/QLatin1String overload of (non-multi) arg()

Use the new overload directly in QXmlStream*.

Saves 129B in QtCore text size on optimized GCC 6.1 Linux AMD64
builds, even though we added two more functions.

[ChangeLog][QtCore][QString] Added arg(QStringView),
arg(QLatin1String) overloads.

Change-Id: Idf7236dcab763824593f34182e4e0b16b5ed4321
Reviewed-by: Anton Kudryavtsev <antkudr@mail.ru>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Marc Mutz 2017-03-31 12:47:33 +02:00
parent 0a5b610679
commit e1e6506c8d
5 changed files with 109 additions and 22 deletions

View File

@ -262,6 +262,17 @@ void Widget::argFunction()
.arg(i).arg(total).arg(fileName);
//! [11]
{
//! [11]
int i; // current file's number
int total; // number of files to process
QStringView fileName; // current file's name
QString status = QString("Processing file %1 of %2: %3")
.arg(i).arg(total).arg(fileName);
//! [11]
}
//! [12] //! [13]
QString str;
//! [12]

View File

@ -7363,10 +7363,10 @@ struct ArgEscapeData
int escape_len; // total length of escape sequences which will be replaced
};
static ArgEscapeData findArgEscapes(const QString &s)
static ArgEscapeData findArgEscapes(QStringView s)
{
const QChar *uc_begin = s.unicode();
const QChar *uc_end = uc_begin + s.length();
const QChar *uc_begin = s.begin();
const QChar *uc_end = s.end();
ArgEscapeData d;
@ -7425,11 +7425,11 @@ static ArgEscapeData findArgEscapes(const QString &s)
return d;
}
static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int field_width,
const QString &arg, const QString &larg, QChar fillChar = QLatin1Char(' '))
static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, int field_width,
QStringView arg, QStringView larg, QChar fillChar)
{
const QChar *uc_begin = s.unicode();
const QChar *uc_end = uc_begin + s.length();
const QChar *uc_begin = s.begin();
const QChar *uc_end = s.end();
int abs_field_width = qAbs(field_width);
int result_len = s.length()
@ -7493,11 +7493,11 @@ static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int f
}
if (locale_arg) {
memcpy(rc, larg.unicode(), larg.length()*sizeof(QChar));
memcpy(rc, larg.data(), larg.length()*sizeof(QChar));
rc += larg.length();
}
else {
memcpy(rc, arg.unicode(), arg.length()*sizeof(QChar));
memcpy(rc, arg.data(), arg.length()*sizeof(QChar));
rc += arg.length();
}
@ -7519,6 +7519,7 @@ static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int f
return result;
}
#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a copy of this string with the lowest numbered place marker
replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
@ -7549,17 +7550,86 @@ static QString replaceArgEscapes(const QString &s, const ArgEscapeData &d, int f
in the range 1 to 99.
*/
QString QString::arg(const QString &a, int fieldWidth, QChar fillChar) const
{
return arg(QStringView(a), fieldWidth, fillChar);
}
#endif // QT_STRINGVIEW_LEVEL < 2
/*!
\overload
\since 5.10
Returns a copy of this string with the lowest-numbered place-marker
replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
\a fieldWidth specifies the minimum amount of space that \a a
shall occupy. If \a a requires less space than \a fieldWidth, it
is padded to \a fieldWidth with character \a fillChar. A positive
\a fieldWidth produces right-aligned text. A negative \a fieldWidth
produces left-aligned text.
This example shows how we might create a \c status string for
reporting progress while processing a list of files:
\snippet qstring/main.cpp 11-qstringview
First, \c arg(i) replaces \c %1. Then \c arg(total) replaces \c
%2. Finally, \c arg(fileName) replaces \c %3.
One advantage of using arg() over asprintf() is that the order of the
numbered place markers can change, if the application's strings are
translated into other languages, but each arg() will still replace
the lowest-numbered unreplaced place-marker, no matter where it
appears. Also, if place-marker \c %i appears more than once in the
string, arg() replaces all of them.
If there is no unreplaced place-marker remaining, a warning message
is printed and the result is undefined. Place-marker numbers must be
in the range 1 to 99.
*/
QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
{
ArgEscapeData d = findArgEscapes(*this);
if (d.occurrences == 0) {
qWarning("QString::arg: Argument missing: %s, %s", toLocal8Bit().data(),
a.toLocal8Bit().data());
if (Q_UNLIKELY(d.occurrences == 0)) {
qWarning("QString::arg: Argument missing: %ls, %ls", qUtf16Printable(*this),
qUtf16Printable(a.toString()));
return *this;
}
return replaceArgEscapes(*this, d, fieldWidth, a, a, fillChar);
}
/*!
\overload
\since 5.10
Returns a copy of this string with the lowest-numbered place-marker
replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
\a fieldWidth specifies the minimum amount of space that \a a
shall occupy. If \a a requires less space than \a fieldWidth, it
is padded to \a fieldWidth with character \a fillChar. A positive
\a fieldWidth produces right-aligned text. A negative \a fieldWidth
produces left-aligned text.
One advantage of using arg() over asprintf() is that the order of the
numbered place markers can change, if the application's strings are
translated into other languages, but each arg() will still replace
the lowest-numbered unreplaced place-marker, no matter where it
appears. Also, if place-marker \c %i appears more than once in the
string, arg() replaces all of them.
If there is no unreplaced place-marker remaining, a warning message
is printed and the result is undefined. Place-marker numbers must be
in the range 1 to 99.
*/
QString QString::arg(QLatin1String a, int fieldWidth, QChar fillChar) const
{
QVarLengthArray<ushort> utf16(a.size());
qt_from_latin1(utf16.data(), a.data(), a.size());
return arg(QStringView(utf16.data(), utf16.size()), fieldWidth, fillChar);
}
/*!
\fn QString QString::arg(const QString& a1, const QString& a2) const
\overload arg()

View File

@ -319,8 +319,14 @@ public:
QChar fillChar = QLatin1Char(' ')) const Q_REQUIRED_RESULT;
QString arg(QChar a, int fieldWidth = 0,
QChar fillChar = QLatin1Char(' ')) const Q_REQUIRED_RESULT;
#if QT_STRINGVIEW_LEVEL < 2
QString arg(const QString &a, int fieldWidth = 0,
QChar fillChar = QLatin1Char(' ')) const Q_REQUIRED_RESULT;
#endif
QString arg(QStringView a, int fieldWidth = 0,
QChar fillChar = QLatin1Char(' ')) const Q_REQUIRED_RESULT;
QString arg(QLatin1String a, int fieldWidth = 0,
QChar fillChar = QLatin1Char(' ')) const Q_REQUIRED_RESULT;
QString arg(const QString &a1, const QString &a2) const Q_REQUIRED_RESULT;
QString arg(const QString &a1, const QString &a2, const QString &a3) const Q_REQUIRED_RESULT;
QString arg(const QString &a1, const QString &a2, const QString &a3,

View File

@ -1558,7 +1558,7 @@ QStringRef QXmlStreamReaderPrivate::namespaceForPrefix(const QStringRef &prefix)
#if 1
if (namespaceProcessing && !prefix.isEmpty())
raiseWellFormedError(QXmlStream::tr("Namespace prefix '%1' not declared").arg(prefix.toString()));
raiseWellFormedError(QXmlStream::tr("Namespace prefix '%1' not declared").arg(prefix));
#endif
return QStringRef();
@ -1636,7 +1636,7 @@ void QXmlStreamReaderPrivate::resolveTag()
if (attributes[j].name() == attribute.name()
&& attributes[j].namespaceUri() == attribute.namespaceUri()
&& (namespaceProcessing || attributes[j].qualifiedName() == attribute.qualifiedName()))
raiseWellFormedError(QXmlStream::tr("Attribute '%1' redefined.").arg(attribute.qualifiedName().toString()));
raiseWellFormedError(QXmlStream::tr("Attribute '%1' redefined.").arg(attribute.qualifiedName()));
}
}
@ -1804,14 +1804,14 @@ void QXmlStreamReaderPrivate::startDocument()
if(hasStandalone)
err = QXmlStream::tr("The standalone pseudo attribute must appear after the encoding.");
if(!QXmlUtils::isEncName(name))
err = QXmlStream::tr("%1 is an invalid encoding name.").arg(name);
err = QXmlStream::tr("%1 is an invalid encoding name.").arg(value);
else {
#ifdef QT_NO_TEXTCODEC
readBuffer = QString::fromLatin1(rawReadBuffer.data(), nbytesread);
#else
QTextCodec *const newCodec = QTextCodec::codecForName(name.toLatin1());
if (!newCodec)
err = QXmlStream::tr("Encoding %1 is unsupported").arg(name);
err = QXmlStream::tr("Encoding %1 is unsupported").arg(value);
else if (newCodec != codec && !lockEncoding) {
codec = newCodec;
delete decoder;

View File

@ -4726,8 +4726,8 @@ void tst_QString::arg()
QString s14( "%1%2%3" );
QCOMPARE( s4.arg("foo"), QLatin1String("[foo]") );
QCOMPARE( s5.arg("foo"), QLatin1String("[foo]") );
QCOMPARE( s6.arg("foo"), QLatin1String("[foo]") );
QCOMPARE( s5.arg(QLatin1String("foo")), QLatin1String("[foo]") );
QCOMPARE( s6.arg(QStringViewLiteral("foo")), QLatin1String("[foo]") );
QCOMPARE( s7.arg("foo"), QLatin1String("[foo]") );
QCOMPARE( s8.arg("foo"), QLatin1String("[foo %1]") );
QCOMPARE( s8.arg("foo").arg("bar"), QLatin1String("[foo bar]") );
@ -4788,11 +4788,11 @@ void tst_QString::arg()
QCOMPARE( QString("%%%1%%%2").arg("foo").arg("bar"), QLatin1String("%%foo%%bar") );
QCOMPARE( QString("%1").arg("hello", -10), QLatin1String("hello ") );
QCOMPARE( QString("%1").arg("hello", -5), QLatin1String("hello") );
QCOMPARE( QString("%1").arg("hello", -2), QLatin1String("hello") );
QCOMPARE( QString("%1").arg(QLatin1String("hello"), -5), QLatin1String("hello") );
QCOMPARE( QString("%1").arg(QStringViewLiteral("hello"), -2), QLatin1String("hello") );
QCOMPARE( QString("%1").arg("hello", 0), QLatin1String("hello") );
QCOMPARE( QString("%1").arg("hello", 2), QLatin1String("hello") );
QCOMPARE( QString("%1").arg("hello", 5), QLatin1String("hello") );
QCOMPARE( QString("%1").arg(QLatin1String("hello"), 2), QLatin1String("hello") );
QCOMPARE( QString("%1").arg(QStringViewLiteral("hello"), 5), QLatin1String("hello") );
QCOMPARE( QString("%1").arg("hello", 10), QLatin1String(" hello") );
QCOMPARE( QString("%1%1").arg("hello"), QLatin1String("hellohello") );
QCOMPARE( QString("%2%1").arg("hello"), QLatin1String("%2hello") );