QString: towards QStringView::arg() pt.3: Long live QStringView/QLatin1String::arg()
This version of arg(), unlike its QString counterpart, transparently accepts views without conversion to QString, and is also extensible to further argument types, say a future QFormattedNumber. [ChangeLog][QtCore][QStringView/QLatin1String] Added arg(), taking arbitrarily many strings. Change-Id: If40ef3c445f63383e32573f3f515fdda84c7fe3a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
6f84829031
commit
35431062bd
@ -8754,19 +8754,23 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
|
|||||||
return replaceArgEscapes(*this, d, fieldWidth, arg, locale_arg, fillChar);
|
return replaceArgEscapes(*this, d, fieldWidth, arg, locale_arg, fillChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getEscape(const QChar *uc, qsizetype *pos, qsizetype len, int maxNumber = 999)
|
static inline ushort to_unicode(const QChar c) { return c.unicode(); }
|
||||||
|
static inline ushort to_unicode(const char c) { return QLatin1Char{c}.unicode(); }
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumber = 999)
|
||||||
{
|
{
|
||||||
int i = *pos;
|
int i = *pos;
|
||||||
++i;
|
++i;
|
||||||
if (i < len && uc[i] == QLatin1Char('L'))
|
if (i < len && uc[i] == QLatin1Char('L'))
|
||||||
++i;
|
++i;
|
||||||
if (i < len) {
|
if (i < len) {
|
||||||
int escape = uc[i].unicode() - '0';
|
int escape = to_unicode(uc[i]) - '0';
|
||||||
if (uint(escape) >= 10U)
|
if (uint(escape) >= 10U)
|
||||||
return -1;
|
return -1;
|
||||||
++i;
|
++i;
|
||||||
while (i < len) {
|
while (i < len) {
|
||||||
int digit = uc[i].unicode() - '0';
|
int digit = to_unicode(uc[i]) - '0';
|
||||||
if (uint(digit) >= 10U)
|
if (uint(digit) >= 10U)
|
||||||
break;
|
break;
|
||||||
escape = (escape * 10) + digit;
|
escape = (escape * 10) + digit;
|
||||||
@ -8817,18 +8821,23 @@ static int getEscape(const QChar *uc, qsizetype *pos, qsizetype len, int maxNumb
|
|||||||
namespace {
|
namespace {
|
||||||
struct Part
|
struct Part
|
||||||
{
|
{
|
||||||
Q_DECL_CONSTEXPR Part() : string{}, number{0} {}
|
Part() = default; // for QVarLengthArray; do not use
|
||||||
Q_DECL_CONSTEXPR Part(QStringView s, int num = -1)
|
Q_DECL_CONSTEXPR Part(QStringView s, int num = -1)
|
||||||
: string{s}, number{num} {}
|
: tag{QtPrivate::ArgBase::U16}, number{num}, data{s.utf16()}, size{s.size()} {}
|
||||||
|
Q_DECL_CONSTEXPR Part(QLatin1String s, int num = -1)
|
||||||
|
: tag{QtPrivate::ArgBase::L1}, number{num}, data{s.data()}, size{s.size()} {}
|
||||||
|
|
||||||
QStringView string;
|
void reset(QStringView s) noexcept { *this = {s, number}; }
|
||||||
|
void reset(QLatin1String s) noexcept { *this = {s, number}; }
|
||||||
|
|
||||||
|
QtPrivate::ArgBase::Tag tag;
|
||||||
int number;
|
int number;
|
||||||
|
const void *data;
|
||||||
|
qsizetype size;
|
||||||
};
|
};
|
||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
|
|
||||||
template <>
|
Q_DECLARE_TYPEINFO(Part, Q_PRIMITIVE_TYPE);
|
||||||
class QTypeInfo<Part> : public QTypeInfoMerger<Part, QStringView, int> {}; // Q_DECLARE_METATYPE
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -8837,7 +8846,8 @@ enum { ExpectedParts = 32 };
|
|||||||
typedef QVarLengthArray<Part, ExpectedParts> ParseResult;
|
typedef QVarLengthArray<Part, ExpectedParts> ParseResult;
|
||||||
typedef QVarLengthArray<int, ExpectedParts/2> ArgIndexToPlaceholderMap;
|
typedef QVarLengthArray<int, ExpectedParts/2> ArgIndexToPlaceholderMap;
|
||||||
|
|
||||||
static ParseResult parseMultiArgFormatString(QStringView s)
|
template <typename StringView>
|
||||||
|
static ParseResult parseMultiArgFormatString(StringView s)
|
||||||
{
|
{
|
||||||
ParseResult result;
|
ParseResult result;
|
||||||
|
|
||||||
@ -8884,16 +8894,29 @@ static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult &
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QString *args[])
|
static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QtPrivate::ArgBase *args[])
|
||||||
{
|
{
|
||||||
|
using namespace QtPrivate;
|
||||||
qsizetype totalSize = 0;
|
qsizetype totalSize = 0;
|
||||||
for (Part &part : parts) {
|
for (Part &part : parts) {
|
||||||
if (part.number != -1) {
|
if (part.number != -1) {
|
||||||
const auto it = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), part.number);
|
const auto it = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), part.number);
|
||||||
if (it != argIndexToPlaceholderMap.end())
|
if (it != argIndexToPlaceholderMap.end()) {
|
||||||
part.string = *args[it - argIndexToPlaceholderMap.begin()];
|
const auto &arg = *args[it - argIndexToPlaceholderMap.begin()];
|
||||||
|
switch (arg.tag) {
|
||||||
|
case ArgBase::L1:
|
||||||
|
part.reset(static_cast<const QLatin1StringArg&>(arg).string);
|
||||||
|
break;
|
||||||
|
case ArgBase::U8:
|
||||||
|
Q_UNREACHABLE(); // waiting for QUtf8String...
|
||||||
|
break;
|
||||||
|
case ArgBase::U16:
|
||||||
|
part.reset(static_cast<const QStringViewArg&>(arg).string);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
totalSize += part.string.size();
|
}
|
||||||
|
}
|
||||||
|
totalSize += part.size;
|
||||||
}
|
}
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
@ -8901,18 +8924,35 @@ static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const A
|
|||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
|
|
||||||
QString QString::multiArg(int numArgs, const QString **args) const
|
QString QString::multiArg(int numArgs, const QString **args) const
|
||||||
|
{
|
||||||
|
QVarLengthArray<QtPrivate::QStringViewArg, 9> sva;
|
||||||
|
sva.reserve(numArgs);
|
||||||
|
QVarLengthArray<const QtPrivate::ArgBase *, 9> pointers;
|
||||||
|
pointers.reserve(numArgs);
|
||||||
|
for (int i = 0; i < numArgs; ++i) {
|
||||||
|
sva.push_back(QtPrivate::qStringLikeToArg(*args[i]));
|
||||||
|
pointers.push_back(&sva.back());
|
||||||
|
}
|
||||||
|
return QtPrivate::argToQString(qToStringViewIgnoringNull(*this), static_cast<size_t>(numArgs), pointers.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ALWAYS_INLINE QString to_string(QLatin1String s) noexcept { return s; }
|
||||||
|
Q_ALWAYS_INLINE QString to_string(QStringView s) noexcept { return s.toString(); }
|
||||||
|
|
||||||
|
template <typename StringView>
|
||||||
|
static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPrivate::ArgBase **args)
|
||||||
{
|
{
|
||||||
// Step 1-2 above
|
// Step 1-2 above
|
||||||
ParseResult parts = parseMultiArgFormatString(qToStringViewIgnoringNull(*this));
|
ParseResult parts = parseMultiArgFormatString(pattern);
|
||||||
|
|
||||||
// 3-4
|
// 3-4
|
||||||
ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts);
|
ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts);
|
||||||
|
|
||||||
if (argIndexToPlaceholderMap.size() > numArgs) // 3a
|
if (static_cast<size_t>(argIndexToPlaceholderMap.size()) > numArgs) // 3a
|
||||||
argIndexToPlaceholderMap.resize(numArgs);
|
argIndexToPlaceholderMap.resize(int(numArgs));
|
||||||
else if (argIndexToPlaceholderMap.size() < numArgs) // 3b
|
else if (Q_UNLIKELY(static_cast<size_t>(argIndexToPlaceholderMap.size()) < numArgs)) // 3b
|
||||||
qWarning("QString::arg: %d argument(s) missing in %s",
|
qWarning("QString::arg: %d argument(s) missing in %ls",
|
||||||
numArgs - argIndexToPlaceholderMap.size(), toLocal8Bit().data());
|
int(numArgs - argIndexToPlaceholderMap.size()), qUtf16Printable(to_string(pattern)));
|
||||||
|
|
||||||
// 5
|
// 5
|
||||||
const qsizetype totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args);
|
const qsizetype totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args);
|
||||||
@ -8922,15 +8962,37 @@ QString QString::multiArg(int numArgs, const QString **args) const
|
|||||||
auto out = const_cast<QChar*>(result.constData());
|
auto out = const_cast<QChar*>(result.constData());
|
||||||
|
|
||||||
for (Part part : parts) {
|
for (Part part : parts) {
|
||||||
if (const qsizetype sz = part.string.size()) {
|
switch (part.tag) {
|
||||||
memcpy(out, part.string.data(), sz * sizeof(QChar));
|
case QtPrivate::ArgBase::L1:
|
||||||
out += sz;
|
if (part.size) {
|
||||||
|
qt_from_latin1(reinterpret_cast<ushort*>(out),
|
||||||
|
reinterpret_cast<const char*>(part.data), part.size);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case QtPrivate::ArgBase::U8:
|
||||||
|
Q_UNREACHABLE(); // waiting for QUtf8String
|
||||||
|
break;
|
||||||
|
case QtPrivate::ArgBase::U16:
|
||||||
|
if (part.size)
|
||||||
|
memcpy(out, part.data, part.size * sizeof(QChar));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out += part.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QtPrivate::argToQString(QStringView pattern, size_t n, const ArgBase **args)
|
||||||
|
{
|
||||||
|
return argToQStringImpl(pattern, n, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QtPrivate::argToQString(QLatin1String pattern, size_t n, const ArgBase **args)
|
||||||
|
{
|
||||||
|
return argToQStringImpl(pattern, n, args);
|
||||||
|
}
|
||||||
|
|
||||||
/*! \fn bool QString::isSimpleText() const
|
/*! \fn bool QString::isSimpleText() const
|
||||||
|
|
||||||
\internal
|
\internal
|
||||||
|
@ -106,6 +106,9 @@ public:
|
|||||||
Q_DECL_CONSTEXPR bool isNull() const noexcept { return !data(); }
|
Q_DECL_CONSTEXPR bool isNull() const noexcept { return !data(); }
|
||||||
Q_DECL_CONSTEXPR bool isEmpty() const noexcept { return !size(); }
|
Q_DECL_CONSTEXPR bool isEmpty() const noexcept { return !size(); }
|
||||||
|
|
||||||
|
template <typename...Args>
|
||||||
|
Q_REQUIRED_RESULT inline QString arg(Args &&...args) const;
|
||||||
|
|
||||||
Q_DECL_CONSTEXPR QLatin1Char at(int i) const
|
Q_DECL_CONSTEXPR QLatin1Char at(int i) const
|
||||||
{ return Q_ASSERT(i >= 0), Q_ASSERT(i < size()), QLatin1Char(m_data[i]); }
|
{ return Q_ASSERT(i >= 0), Q_ASSERT(i < size()), QLatin1Char(m_data[i]); }
|
||||||
Q_DECL_CONSTEXPR QLatin1Char operator[](int i) const { return at(i); }
|
Q_DECL_CONSTEXPR QLatin1Char operator[](int i) const { return at(i); }
|
||||||
@ -1979,6 +1982,58 @@ inline const QString &asString(const QString &s) { return s; }
|
|||||||
inline QString &&asString(QString &&s) { return std::move(s); }
|
inline QString &&asString(QString &&s) { return std::move(s); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// QStringView::arg() implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace QtPrivate {
|
||||||
|
|
||||||
|
struct ArgBase {
|
||||||
|
enum Tag : uchar { L1, U8, U16 } tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QStringViewArg : ArgBase {
|
||||||
|
QStringView string;
|
||||||
|
QStringViewArg() = default;
|
||||||
|
Q_DECL_CONSTEXPR explicit QStringViewArg(QStringView v) noexcept : ArgBase{U16}, string{v} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QLatin1StringArg : ArgBase {
|
||||||
|
QLatin1String string;
|
||||||
|
QLatin1StringArg() = default;
|
||||||
|
Q_DECL_CONSTEXPR explicit QLatin1StringArg(QLatin1String v) noexcept : ArgBase{L1}, string{v} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_REQUIRED_RESULT Q_CORE_EXPORT QString argToQString(QStringView pattern, size_t n, const ArgBase **args);
|
||||||
|
Q_REQUIRED_RESULT Q_CORE_EXPORT QString argToQString(QLatin1String pattern, size_t n, const ArgBase **args);
|
||||||
|
|
||||||
|
template <typename StringView, typename...Args>
|
||||||
|
Q_REQUIRED_RESULT Q_ALWAYS_INLINE QString argToQStringDispatch(StringView pattern, const Args &...args)
|
||||||
|
{
|
||||||
|
const ArgBase *argBases[] = {&args..., /* avoid zero-sized array */ nullptr};
|
||||||
|
return QtPrivate::argToQString(pattern, sizeof...(Args), argBases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECL_CONSTEXPR inline QStringViewArg qStringLikeToArg(QStringView s) noexcept { return QStringViewArg{s}; }
|
||||||
|
inline QStringViewArg qStringLikeToArg(const QChar &c) noexcept { return QStringViewArg{QStringView{&c, 1}}; }
|
||||||
|
Q_DECL_CONSTEXPR inline QLatin1StringArg qStringLikeToArg(QLatin1String s) noexcept { return QLatin1StringArg{s}; }
|
||||||
|
|
||||||
|
} // namespace QtPrivate
|
||||||
|
|
||||||
|
template <typename...Args>
|
||||||
|
Q_ALWAYS_INLINE
|
||||||
|
QString QStringView::arg(Args &&...args) const
|
||||||
|
{
|
||||||
|
return QtPrivate::argToQStringDispatch(*this, QtPrivate::qStringLikeToArg(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename...Args>
|
||||||
|
Q_ALWAYS_INLINE
|
||||||
|
QString QLatin1String::arg(Args &&...args) const
|
||||||
|
{
|
||||||
|
return QtPrivate::argToQStringDispatch(*this, QtPrivate::qStringLikeToArg(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
|
#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
|
||||||
|
@ -529,6 +529,24 @@ QT_BEGIN_NAMESPACE
|
|||||||
\sa operator[](), front(), back()
|
\sa operator[](), front(), back()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn QString QStringView::arg(Args &&...args) const
|
||||||
|
\fn QString QLatin1String::arg(Args &&...args) const
|
||||||
|
\since 5.14
|
||||||
|
|
||||||
|
Replaces occurrences of \c{%N} in this string with the corresponding
|
||||||
|
argument from \a args. The arguments are not positional: the first of
|
||||||
|
the \a args replaces the \c{%N} with the lowest \c{N} (all of them), the
|
||||||
|
second of the \a args the \c{%N} with the next-lowest \c{N} etc.
|
||||||
|
|
||||||
|
\c Args can consist of anything that implicitly converts to QStringView
|
||||||
|
or QLatin1String.
|
||||||
|
|
||||||
|
In addition, the following types are also supported: QChar, QLatin1Char.
|
||||||
|
|
||||||
|
\sa QString::arg()
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn QChar QStringView::front() const
|
\fn QChar QStringView::front() const
|
||||||
|
|
||||||
|
@ -226,6 +226,9 @@ public:
|
|||||||
// QString API
|
// QString API
|
||||||
//
|
//
|
||||||
|
|
||||||
|
template <typename...Args>
|
||||||
|
Q_REQUIRED_RESULT inline QString arg(Args &&...args) const; // defined in qstring.h
|
||||||
|
|
||||||
Q_REQUIRED_RESULT QByteArray toLatin1() const { return QtPrivate::convertToLatin1(*this); }
|
Q_REQUIRED_RESULT QByteArray toLatin1() const { return QtPrivate::convertToLatin1(*this); }
|
||||||
Q_REQUIRED_RESULT QByteArray toUtf8() const { return QtPrivate::convertToUtf8(*this); }
|
Q_REQUIRED_RESULT QByteArray toUtf8() const { return QtPrivate::convertToUtf8(*this); }
|
||||||
Q_REQUIRED_RESULT QByteArray toLocal8Bit() const { return QtPrivate::convertToLocal8Bit(*this); }
|
Q_REQUIRED_RESULT QByteArray toLocal8Bit() const { return QtPrivate::convertToLocal8Bit(*this); }
|
||||||
|
@ -45,6 +45,7 @@ class tst_QLatin1String : public QObject
|
|||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void at();
|
void at();
|
||||||
|
void arg() const;
|
||||||
void midLeftRight();
|
void midLeftRight();
|
||||||
void nullString();
|
void nullString();
|
||||||
void emptyString();
|
void emptyString();
|
||||||
@ -63,6 +64,47 @@ void tst_QLatin1String::at()
|
|||||||
QCOMPARE(l1[l1.size() - 1], QLatin1Char('d'));
|
QCOMPARE(l1[l1.size() - 1], QLatin1Char('d'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QLatin1String::arg() const
|
||||||
|
{
|
||||||
|
#define CHECK1(pattern, arg1, expected) \
|
||||||
|
do { \
|
||||||
|
auto p = QLatin1String(pattern); \
|
||||||
|
QCOMPARE(p.arg(QLatin1String(arg1)), expected); \
|
||||||
|
QCOMPARE(p.arg(QStringViewLiteral(arg1)), expected); \
|
||||||
|
QCOMPARE(p.arg(QStringLiteral(arg1)), expected); \
|
||||||
|
QCOMPARE(p.arg(QString(QLatin1String(arg1))), expected); \
|
||||||
|
} while (false) \
|
||||||
|
/*end*/
|
||||||
|
#define CHECK2(pattern, arg1, arg2, expected) \
|
||||||
|
do { \
|
||||||
|
auto p = QLatin1String(pattern); \
|
||||||
|
QCOMPARE(p.arg(QLatin1String(arg1), QLatin1String(arg2)), expected); \
|
||||||
|
QCOMPARE(p.arg(QStringViewLiteral(arg1), QLatin1String(arg2)), expected); \
|
||||||
|
QCOMPARE(p.arg(QLatin1String(arg1), QStringViewLiteral(arg2)), expected); \
|
||||||
|
QCOMPARE(p.arg(QStringViewLiteral(arg1), QStringViewLiteral(arg2)), expected); \
|
||||||
|
} while (false) \
|
||||||
|
/*end*/
|
||||||
|
|
||||||
|
CHECK1("", "World", "");
|
||||||
|
CHECK1("%1", "World", "World");
|
||||||
|
CHECK1("!%1?", "World", "!World?");
|
||||||
|
CHECK1("%1%1", "World", "WorldWorld");
|
||||||
|
CHECK1("%1%2", "World", "World%2");
|
||||||
|
CHECK1("%2%1", "World", "%2World");
|
||||||
|
|
||||||
|
CHECK2("", "Hello", "World", "");
|
||||||
|
CHECK2("%1", "Hello", "World", "Hello");
|
||||||
|
CHECK2("!%1, %2?", "Hello", "World", "!Hello, World?");
|
||||||
|
CHECK2("%1%1", "Hello", "World", "HelloHello");
|
||||||
|
CHECK2("%1%2", "Hello", "World", "HelloWorld");
|
||||||
|
CHECK2("%2%1", "Hello", "World", "WorldHello");
|
||||||
|
|
||||||
|
#undef CHECK2
|
||||||
|
#undef CHECK1
|
||||||
|
|
||||||
|
QCOMPARE(QLatin1String(" %2 %2 %1 %3 ").arg(QLatin1Char('c'), QChar::CarriageReturn, u'C'), " \r \r c C ");
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QLatin1String::midLeftRight()
|
void tst_QLatin1String::midLeftRight()
|
||||||
{
|
{
|
||||||
const QLatin1String l1("Hello World");
|
const QLatin1String l1("Hello World");
|
||||||
|
@ -134,6 +134,8 @@ private Q_SLOTS:
|
|||||||
void literals() const;
|
void literals() const;
|
||||||
void at() const;
|
void at() const;
|
||||||
|
|
||||||
|
void arg() const;
|
||||||
|
|
||||||
void fromQString() const;
|
void fromQString() const;
|
||||||
void fromQStringRef() const;
|
void fromQStringRef() const;
|
||||||
|
|
||||||
@ -425,6 +427,47 @@ void tst_QStringView::at() const
|
|||||||
QCOMPARE(sv.at(4), QChar('o')); QCOMPARE(sv[4], QChar('o'));
|
QCOMPARE(sv.at(4), QChar('o')); QCOMPARE(sv[4], QChar('o'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QStringView::arg() const
|
||||||
|
{
|
||||||
|
#define CHECK1(pattern, arg1, expected) \
|
||||||
|
do { \
|
||||||
|
auto p = QStringViewLiteral(pattern); \
|
||||||
|
QCOMPARE(p.arg(QLatin1String(arg1)), expected); \
|
||||||
|
QCOMPARE(p.arg(QStringViewLiteral(arg1)), expected); \
|
||||||
|
QCOMPARE(p.arg(QStringLiteral(arg1)), expected); \
|
||||||
|
QCOMPARE(p.arg(QString(QLatin1String(arg1))), expected); \
|
||||||
|
} while (false) \
|
||||||
|
/*end*/
|
||||||
|
#define CHECK2(pattern, arg1, arg2, expected) \
|
||||||
|
do { \
|
||||||
|
auto p = QStringViewLiteral(pattern); \
|
||||||
|
QCOMPARE(p.arg(QLatin1String(arg1), QLatin1String(arg2)), expected); \
|
||||||
|
QCOMPARE(p.arg(QStringViewLiteral(arg1), QLatin1String(arg2)), expected); \
|
||||||
|
QCOMPARE(p.arg(QLatin1String(arg1), QStringViewLiteral(arg2)), expected); \
|
||||||
|
QCOMPARE(p.arg(QStringViewLiteral(arg1), QStringViewLiteral(arg2)), expected); \
|
||||||
|
} while (false) \
|
||||||
|
/*end*/
|
||||||
|
|
||||||
|
CHECK1("", "World", "");
|
||||||
|
CHECK1("%1", "World", "World");
|
||||||
|
CHECK1("!%1?", "World", "!World?");
|
||||||
|
CHECK1("%1%1", "World", "WorldWorld");
|
||||||
|
CHECK1("%1%2", "World", "World%2");
|
||||||
|
CHECK1("%2%1", "World", "%2World");
|
||||||
|
|
||||||
|
CHECK2("", "Hello", "World", "");
|
||||||
|
CHECK2("%1", "Hello", "World", "Hello");
|
||||||
|
CHECK2("!%1, %2?", "Hello", "World", "!Hello, World?");
|
||||||
|
CHECK2("%1%1", "Hello", "World", "HelloHello");
|
||||||
|
CHECK2("%1%2", "Hello", "World", "HelloWorld");
|
||||||
|
CHECK2("%2%1", "Hello", "World", "WorldHello");
|
||||||
|
|
||||||
|
#undef CHECK2
|
||||||
|
#undef CHECK1
|
||||||
|
|
||||||
|
QCOMPARE(QStringViewLiteral(" %2 %2 %1 %3 ").arg(QLatin1Char('c'), QChar::CarriageReturn, u'C'), " \r \r c C ");
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QStringView::fromQString() const
|
void tst_QStringView::fromQString() const
|
||||||
{
|
{
|
||||||
QString null;
|
QString null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user