diff --git a/src/corelib/text/qanystringview.cpp b/src/corelib/text/qanystringview.cpp index ff699ce44c7..dca7e24ed21 100644 --- a/src/corelib/text/qanystringview.cpp +++ b/src/corelib/text/qanystringview.cpp @@ -696,5 +696,13 @@ QDebug operator<<(QDebug d, QAnyStringView s) return d; } +/*! + \fn template QString QAnyStringView::arg(Args &&...args) const + \since 6.9 + + \include qstringview.cpp qstring-multi-arg + + \sa QString::arg(Args&&...) +*/ QT_END_NAMESPACE diff --git a/src/corelib/text/qanystringview.h b/src/corelib/text/qanystringview.h index e5c3d0f80e7..a0b6845524f 100644 --- a/src/corelib/text/qanystringview.h +++ b/src/corelib/text/qanystringview.h @@ -279,6 +279,8 @@ public: constexpr void chop(qsizetype n) { verify(0, n); setSize(size() - n); } + template + [[nodiscard]] inline QString arg(Args &&...args) const; [[nodiscard]] inline QString toString() const; // defined in qstring.h diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index ba748772cbc..d94bdc25e6f 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -1621,6 +1621,19 @@ QString QLatin1StringView::arg(Args &&...args) const return QtPrivate::argToQStringDispatch(*this, QtPrivate::qStringLikeToArg(args)...); } +template +template +QString QBasicUtf8StringView::arg(Args &&...args) const +{ + return QtPrivate::argToQStringDispatch(*this, QtPrivate::qStringLikeToArg(args)...); +} + +template +QString QAnyStringView::arg(Args &&...args) const +{ + return QtPrivate::argToQStringDispatch(*this, QtPrivate::qStringLikeToArg(args)...); +} + template qsizetype erase(QString &s, const T &t) { diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index 0381e2bec5e..ad6d618bc59 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -505,6 +505,7 @@ QT_BEGIN_NAMESPACE \fn template QString QString::arg(Args &&...args) const \since 5.14 +//![qstring-multi-arg] 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 @@ -514,6 +515,7 @@ QT_BEGIN_NAMESPACE QStringView or QLatin1StringView. In addition, the following types are also supported: QChar, QLatin1Char. +//![qstring-multi-arg] \sa QString::arg() */ diff --git a/src/corelib/text/qutf8stringview.h b/src/corelib/text/qutf8stringview.h index 9c74efb685b..185cf335425 100644 --- a/src/corelib/text/qutf8stringview.h +++ b/src/corelib/text/qutf8stringview.h @@ -215,6 +215,9 @@ public: [[nodiscard]] constexpr storage_type at(qsizetype n) const { return (*this)[n]; } + template + [[nodiscard]] inline QString arg(Args &&...args) const; + [[nodiscard]] constexpr QBasicUtf8StringView mid(qsizetype pos, qsizetype n = -1) const { diff --git a/src/corelib/text/qutf8stringview.qdoc b/src/corelib/text/qutf8stringview.qdoc index 303425caa49..e5cc6407475 100644 --- a/src/corelib/text/qutf8stringview.qdoc +++ b/src/corelib/text/qutf8stringview.qdoc @@ -761,3 +761,12 @@ Returns maxSize(). */ + +/*! + \fn template QString QUtf8StringView::arg(Args &&...args) const + \since 6.9 + + \include qstringview.cpp qstring-multi-arg + + \sa QString::arg(Args&&...) +*/ diff --git a/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp b/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp index bcd2715f0b6..ce2a11bc72f 100644 --- a/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp +++ b/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp @@ -399,6 +399,8 @@ private Q_SLOTS: void comparison_data(); void comparison(); + void arg() const; + private: template void fromQStringBuilder(StringBuilder &&sb, QStringView expected) const; @@ -962,5 +964,61 @@ void tst_QAnyStringView::comparison() } } +void tst_QAnyStringView::arg() const +{ + // nullness checks + QCOMPARE(QAnyStringView().arg(QStringView()), ""); + QCOMPARE(QAnyStringView(u"%1").arg(QStringView()), ""); + +#define CHECK1IMPL(pattern, arg1, expected) \ + do { \ + auto p = QAnyStringView(pattern); \ + QCOMPARE(p.arg(QLatin1StringView(arg1)), expected); \ + QCOMPARE(p.arg(u"" arg1), expected); \ + QCOMPARE(p.arg(QStringLiteral(arg1)), expected); \ + QCOMPARE(p.arg(QString(QLatin1StringView(arg1))), expected); \ + } while (false) \ + /*end*/ +#define CHECK1(pattern, arg1, expected) \ + do { \ + CHECK1IMPL("" pattern, arg1, expected); \ + CHECK1IMPL(u8"" pattern, arg1, expected); \ + CHECK1IMPL(pattern ""_L1, arg1, expected); \ + CHECK1IMPL(u"" pattern, arg1, expected); \ + } while (false) \ + /*end*/ +#define CHECK2(pattern, arg1, arg2, expected) \ + do { \ + auto p = QAnyStringView(pattern); \ + QCOMPARE(p.arg(QLatin1StringView(arg1), QLatin1StringView(arg2)), expected); \ + QCOMPARE(p.arg(u"" arg1, QLatin1StringView(arg2)), expected); \ + QCOMPARE(p.arg(QLatin1StringView(arg1), u"" arg2), expected); \ + QCOMPARE(p.arg(u"" arg1, u"" 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_EQ(QAnyStringView(u8"ä %2 %2—%1 %3 ").arg(QLatin1Char('c'), QChar::CarriageReturn, u'C'), + u"ä \r \r—c C "_s); + QCOMPARE_EQ(QUtf8StringView(u8"ä %2 %2—%1 %3 ").arg(QLatin1Char('c'), QChar::CarriageReturn, u'C'), + u"ä \r \r—c C "_s); +} + QTEST_APPLESS_MAIN(tst_QAnyStringView) #include "tst_qanystringview.moc" diff --git a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp index d281162f88d..43287ea89a0 100644 --- a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -549,7 +549,7 @@ private: template void arg1_impl() const; private Q_SLOTS: - // let Formats = {QString, QStringView, QLatin1String} + // let Formats = {QString, QStringView, QLatin1String, QUtf8StringView, QAnyStringView} // let Arguments = Formats ∪ {QByteArray, const char*, const char8_t*. const char16_t*, std::u16string, char, QChar, QLatin1Char, char16_t} // test Formats × Arguments: void arg1_QString_QString_data() { arg1_data(); } @@ -631,6 +631,106 @@ private Q_SLOTS: void arg1_QLatin1StringView_char16_t_data() { arg1_data(false); } void arg1_QLatin1StringView_char16_t() { arg1_impl(); } + void arg1_QUtf8StringView_QString_data() { arg1_data(); } + void arg1_QUtf8StringView_QString() { arg1_impl(); } + void arg1_QUtf8StringView_QStringView_data() { arg1_data(); } + void arg1_QUtf8StringView_QStringView() { arg1_impl(); } + void arg1_QUtf8StringView_QLatin1StringView_data() { arg1_data(); } + void arg1_QUtf8StringView_QLatin1StringView() { arg1_impl(); } + void arg1_QUtf8StringView_QByteArray_data() { arg1_data(); } + void arg1_QUtf8StringView_QByteArray() { arg1_impl(); } + void arg1_QUtf8StringView_const_char_star_data() { arg1_data(); } + void arg1_QUtf8StringView_const_char_star() { arg1_impl(); } + void arg1_QUtf8StringView_const_char8_t_star_data() { arg1_data(); } + void arg1_QUtf8StringView_const_char8_t_star() { IF_CHAR8T((arg1_impl())); } + void arg1_QUtf8StringView_const_char16_t_star_data() { arg1_data(); } + void arg1_QUtf8StringView_const_char16_t_star() { arg1_impl(); } + void arg1_QUtf8StringView_stdu16string_data() { arg1_data(); } + void arg1_QUtf8StringView_stdu16string() { arg1_impl(); } + void arg1_QUtf8StringView_char_data() { arg1_data(false); } + void arg1_QUtf8StringView_char() { arg1_impl(); } + void arg1_QUtf8StringView_QChar_data() { arg1_data(false); } + void arg1_QUtf8StringView_QChar() { arg1_impl(); } + void arg1_QUtf8StringView_QLatin1Char_data() { arg1_data(false); } + void arg1_QUtf8StringView_QLatin1Char() { arg1_impl(); } + void arg1_QUtf8StringView_char16_t_data() { arg1_data(false); } + void arg1_QUtf8StringView_char16_t() { arg1_impl(); } + + void arg1_QAnyStringViewUsingL1_QString_data() { arg1_data(); } + void arg1_QAnyStringViewUsingL1_QString() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_QStringView_data() { arg1_data(); } + void arg1_QAnyStringViewUsingL1_QStringView() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_QLatin1StringView_data() { arg1_data(); } + void arg1_QAnyStringViewUsingL1_QLatin1StringView() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_QByteArray_data() { arg1_data(); } + void arg1_QAnyStringViewUsingL1_QByteArray() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_const_char_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingL1_const_char_star() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_const_char8_t_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingL1_const_char8_t_star() { IF_CHAR8T((arg1_impl())); } + void arg1_QAnyStringViewUsingL1_const_char16_t_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingL1_const_char16_t_star() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_stdu16string_data() { arg1_data(); } + void arg1_QAnyStringViewUsingL1_stdu16string() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_char_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingL1_char() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_QChar_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingL1_QChar() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_QLatin1Char_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingL1_QLatin1Char() { arg1_impl(); } + void arg1_QAnyStringViewUsingL1_char16_t_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingL1_char16_t() { arg1_impl(); } + + void arg1_QAnyStringViewUsingU8_QString_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU8_QString() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_QStringView_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU8_QStringView() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_QLatin1StringView_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU8_QLatin1StringView() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_QByteArray_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU8_QByteArray() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_const_char_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU8_const_char_star() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_const_char8_t_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU8_const_char8_t_star() { IF_CHAR8T((arg1_impl())); } + void arg1_QAnyStringViewUsingU8_const_char16_t_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU8_const_char16_t_star() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_stdu16string_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU8_stdu16string() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_char_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingU8_char() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_QChar_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingU8_QChar() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_QLatin1Char_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingU8_QLatin1Char() { arg1_impl(); } + void arg1_QAnyStringViewUsingU8_char16_t_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingU8_char16_t() { arg1_impl(); } + + void arg1_QAnyStringViewUsingU16_QString_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU16_QString() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_QStringView_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU16_QStringView() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_QLatin1StringView_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU16_QLatin1StringView() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_QByteArray_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU16_QByteArray() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_const_char_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU16_const_char_star() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_const_char8_t_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU16_const_char8_t_star() { IF_CHAR8T((arg1_impl())); } + void arg1_QAnyStringViewUsingU16_const_char16_t_star_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU16_const_char16_t_star() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_stdu16string_data() { arg1_data(); } + void arg1_QAnyStringViewUsingU16_stdu16string() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_char_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingU16_char() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_QChar_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingU16_QChar() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_QLatin1Char_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingU16_QLatin1Char() { arg1_impl(); } + void arg1_QAnyStringViewUsingU16_char16_t_data() { arg1_data(false); } + void arg1_QAnyStringViewUsingU16_char16_t() { arg1_impl(); } + private: void split_data(bool rhsHasVariableLength = true); template void split_impl() const;