diff options
author | Giuseppe D'Angelo <[email protected]> | 2025-02-24 16:09:18 +0100 |
---|---|---|
committer | Giuseppe D'Angelo <[email protected]> | 2025-02-26 15:27:32 +0100 |
commit | 874be50e7b773698abf0b099b0b32a9cbb3cff2d (patch) | |
tree | 9a3e78e2d17fe6984f8264e732fadc3e838ce65b | |
parent | 04d17b2e229cee5e63596832b021c2316d9e4a05 (diff) |
QStringView: introduce a user-defined literal operator
Although char16_t string literals implicitly convert to QStringView,
there are corner-cases where one may want to explicitly create a
QStringView out of them.
A couple of examples I've found is where these string literals decay
into pointers:
// range is a std::initializer_list<const char16_t *>
for (QStringView v : { u"foo", u"bar" }) { ... }
// ternary will decay arguments
void print(QStringView);
print(check ? u"hi" : u"there");
When this happens the resulting code gets pessimized and polluted by
runtime calls to qustrlen in order to build the QStringView objects [1].
We can restore optimal codegen by directly dealing with QStringView
objects instead. Adding explicit conversions may make the code
cumbersome to read, so I'm introducing a UDL for QStringView, matching
the one for QString (and std::string_view).
[1] for instance: https://gcc.godbolt.org/z/eY7xvEje3
Apply the new operator to a couple of places.
[ChangeLog][QtCore][QStringView] Is it now possible to create
QStringView objects by using the u""_sv user-defined literal.
Fixes: QTBUG-123851
Change-Id: I8af7d2e211b356d284de160a222eab9e91d09500
Reviewed-by: Thiago Macieira <[email protected]>
-rw-r--r-- | src/corelib/ipc/qtipccommon.cpp | 2 | ||||
-rw-r--r-- | src/corelib/text/qstringview.cpp | 40 | ||||
-rw-r--r-- | src/corelib/text/qstringview.h | 11 | ||||
-rw-r--r-- | src/widgets/styles/qcommonstyle.cpp | 2 | ||||
-rw-r--r-- | tests/auto/corelib/text/qstringview/tst_qstringview.cpp | 23 |
5 files changed, 76 insertions, 2 deletions
diff --git a/src/corelib/ipc/qtipccommon.cpp b/src/corelib/ipc/qtipccommon.cpp index 3d9a7281a00..355f6fbc602 100644 --- a/src/corelib/ipc/qtipccommon.cpp +++ b/src/corelib/ipc/qtipccommon.cpp @@ -200,7 +200,7 @@ QNativeIpcKey QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcT QStringView prefix; QStringView payload = key; // see https://learn.microsoft.com/en-us/windows/win32/termserv/kernel-object-namespaces - for (QStringView candidate : { u"Local\\", u"Global\\" }) { + for (QStringView candidate : { u"Local\\"_sv, u"Global\\"_sv }) { if (!key.startsWith(candidate)) continue; prefix = candidate; diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index 64d4ffc1f1d..923eed5539c 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -1496,4 +1496,44 @@ or the character \a ch Returns maxSize(). */ +/*! + \fn Qt::Literals::StringLiterals::operator""_sv(const char16_t *str, size_t size) + + \relates QStringView + \since 6.10 + + Literal operator that creates a QStringView out of the first + \a size characters in the char16_t string literal \a str. + + There is rarely need to explicitly construct a QStringView from a + char16_t string literal, as QStringView is implicitly constructible + from one: + + \code + QStringView greeting = u"hello"; // OK even without _sv + + void print(QStringView s); + print(u"world"); // OK even without _sv + \endcode + + To use this operator, you need to be using the corresponding + namespace(s): + + \code + using namespace Qt::Literals::StringLiterals; + auto sv = u"peace"_sv; + \endcode + + Note that the returned QStringView will span over any NUL embedded + in the string literal. This is different from passing the string + literal to QStringView's constructor (explicitly or implicitly): + + \code + QStringView sv1 = u"abc\0def"; // sv1 == "abc" + QStringView sv2 = u"abc\0def"_sv; // sv2 == "abc\0def" + \endcode + + \sa Qt::Literals::StringLiterals +*/ + QT_END_NAMESPACE diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index 454dd1fdad9..abf57e0ac8c 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -512,6 +512,17 @@ qsizetype QtPrivate::findString(QStringView str, qsizetype from, QChar ch, Qt::C return -1; } +namespace Qt { +inline namespace Literals { +inline namespace StringLiterals { +constexpr QStringView operator""_sv(const char16_t *str, size_t size) noexcept +{ + return QStringView(str, qsizetype(size)); +} +} // StringLiterals +} // Literals +} // Qt + QT_END_NAMESPACE #endif /* QSTRINGVIEW_H */ diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 4f78c8d7072..a86964122ab 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -6071,7 +6071,7 @@ QIcon QCommonStylePrivate::iconFromResourceTheme(QCommonStyle::StandardPixmap st addIconFiles(u"normalizedockup-", dockTitleIconSizes, icon); break; case QStyle::SP_ToolBarHorizontalExtensionButton: - addIconFiles(rtl(option) ? u"toolbar-ext-h-rtl-" : u"toolbar-ext-h-", toolBarExtHSizes, icon); + addIconFiles(rtl(option) ? u"toolbar-ext-h-rtl-"_sv : u"toolbar-ext-h-"_sv, toolBarExtHSizes, icon); break; case QStyle::SP_ToolBarVerticalExtensionButton: addIconFiles(u"toolbar-ext-v-", toolBarExtVSizes, icon); diff --git a/tests/auto/corelib/text/qstringview/tst_qstringview.cpp b/tests/auto/corelib/text/qstringview/tst_qstringview.cpp index 237abcc498d..aa470ac7991 100644 --- a/tests/auto/corelib/text/qstringview/tst_qstringview.cpp +++ b/tests/auto/corelib/text/qstringview/tst_qstringview.cpp @@ -287,6 +287,7 @@ private Q_SLOTS: void tokenize() const; void std_stringview_conversion(); + void userDefinedLiterals(); private: template <typename String> @@ -974,5 +975,27 @@ void tst_QStringView::std_stringview_conversion() QCOMPARE(sv, std::u16string_view(u"Hello\0world\0", 12)); } +void tst_QStringView::userDefinedLiterals() +{ + using namespace Qt::StringLiterals; + auto sv = u"test"_sv; + static_assert(std::is_same_v<decltype(sv), QStringView>); + + QCOMPARE(sv.size(), 4); + QCOMPARE(sv, "test"); + + sv = u""_sv; + QCOMPARE(sv.size(), 0); + QCOMPARE(sv, ""); + + sv = u"embedded\0nul"_sv; + QCOMPARE(sv.size(), 12); + QCOMPARE(sv, QStringView(u"embedded\0nul", 12)); + + constexpr auto csv = u"constexpr test"_sv; + static_assert(csv.size() == 14); + QCOMPARE(csv, "constexpr test"); +} + QTEST_APPLESS_MAIN(tst_QStringView) #include "tst_qstringview.moc" |