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 <thiago.macieira@intel.com>
This commit is contained in:
Giuseppe D'Angelo 2025-02-24 16:09:18 +01:00
parent 04d17b2e22
commit 874be50e7b
5 changed files with 76 additions and 2 deletions

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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"