summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qstring.cpp
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2020-05-20 15:20:07 +0200
committerLars Knoll <lars.knoll@qt.io>2020-08-31 22:57:49 +0200
commit2c9529e158fc589c48e6b1fb61dca2133e33ac4d (patch)
treee9429715ab339d95c2ba9456bf39a894e8b41539 /src/corelib/text/qstring.cpp
parentf0ae973244026ca5382f05630bd799b44154d224 (diff)
Long live Q{Any,Utf8}StringView!
We need to add these two classes at the same time, because QAnyStringView makes all QUtf8StringView relational operators moot. We might want to add some later, esp. for UTF-8/UTf-8 comparisons, to avoid the pessimization that we can't early-out on size() mismatch in QAnyStringView equality operators, but that's an optimization, not a correctness issue, and can be fixed in a source-compatible way even after Qt 6 is released. To deal with the char8_t problem in C++20, make QUtf8StringView a class template out of which two UTF-8 views can be instantiated: the Qt 7 version, which depends on C++20 char8_t as value_type, and the Qt 6 version where value_type is a char. Use inline namespaces to map the QUtf8StringView identifier to one or the other, depending on the C++ version used to compile the user code. The inline namespace names must needs be a bit ugly, as their inline'ness depends on __cpp_char8_t. If we simply used q_v1/q_v2 we'd be blocking these names for Qt inline namespaces forever, because it's likely that inline'ness of other users of inline namespaces in Qt depends on things other than __cpp_char8_t. While inline'ness of namespaces is, theoretically speaking, a compile-time-only property, at least Clang warns about mixed use of inline on a given namespace, so we need to bite the bullet here. This is also the reason for the QT_BEGIN_..._NAMESPACE macros: GCC is ok with the first declaration making a namespace inline, while Clang warns upon re-opening an inline namespace as a non-inline one. [ChangeLog][QtCore][QUtf8StringView] New class. [ChangeLog][QtCore][QAnyStringView] New class. Change-Id: Ia7179760fca0e0b67d52f5accb0a62e389b17913 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/text/qstring.cpp')
-rw-r--r--src/corelib/text/qstring.cpp127
1 files changed, 102 insertions, 25 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 068247adb48..bf37f2e6756 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -1186,8 +1186,7 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l)
return 0;
}
-template <typename Number>
-constexpr int lencmp(Number lhs, Number rhs) noexcept
+constexpr int lencmp(qsizetype lhs, qsizetype rhs) noexcept
{
return lhs == rhs ? 0 :
lhs > rhs ? 1 :
@@ -1283,6 +1282,49 @@ static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSens
return r ? r : lencmp(lhs.size(), rhs.size());
}
+static int qt_compare_strings(QBasicUtf8StringView<false> lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
+{
+ if (cs == Qt::CaseSensitive)
+ return QUtf8::compareUtf8(lhs.data(), lhs.size(), rhs.data(), rhs.size());
+ else
+ return ucstricmp8(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
+
+static int qt_compare_strings(QStringView lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return -qt_compare_strings(rhs, lhs, cs);
+}
+
+static int qt_compare_strings(QLatin1String lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return qt_compare_strings(lhs, rhs.toString(), cs); // ### optimize!
+}
+
+static int qt_compare_strings(QBasicUtf8StringView<false> lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return -qt_compare_strings(rhs, lhs, cs);
+}
+
+static int qt_compare_strings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
+{
+ if (lhs.isEmpty())
+ return lencmp(0, rhs.size());
+ if (cs == Qt::CaseInsensitive)
+ return qt_compare_strings(lhs.toString(), rhs.toString(), cs); // ### optimize!
+ const auto l = std::min(lhs.size(), rhs.size());
+ int r = qstrncmp(lhs.data(), rhs.data(), l);
+ return r ? r : lencmp(lhs.size(), rhs.size());
+}
+
+int QAnyStringView::compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return lhs.visit([rhs, cs](auto lhs) {
+ return rhs.visit([lhs, cs](auto rhs) {
+ return qt_compare_strings(lhs, rhs, cs);
+ });
+ });
+}
+
/*!
\relates QStringView
\internal
@@ -1329,19 +1371,19 @@ int QtPrivate::compareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensit
/*!
\relates QStringView
\internal
- \since 5.10
+ \since 6.0
\overload
+*/
+int QtPrivate::compareStrings(QStringView lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return qt_compare_strings(lhs, rhs, cs);
+}
- Returns an integer that compares to 0 as \a lhs compares to \a rhs.
-
- If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
- otherwise the comparison is case-insensitive.
-
- Case-sensitive comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would expect.
- Consider sorting user-visible strings with QString::localeAwareCompare().
-
- \sa {Comparing Strings}
+/*!
+ \relates QStringView
+ \internal
+ \since 5.10
+ \overload
*/
int QtPrivate::compareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
{
@@ -1375,23 +1417,43 @@ int QtPrivate::compareStrings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSens
\internal
\since 6.0
\overload
+*/
+int QtPrivate::compareStrings(QLatin1String lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return qt_compare_strings(lhs, rhs, cs);
+}
- Returns an integer that compares to 0 as \a lhs compares to \a rhs.
+/*!
+ \relates QStringView
+ \internal
+ \since 6.0
+ \overload
+*/
+int QtPrivate::compareStrings(QBasicUtf8StringView<false> lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return qt_compare_strings(lhs, rhs, cs);
+}
- If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
- otherwise the comparison is case-insensitive.
+/*!
+ \relates QStringView
+ \internal
+ \since 6.0
+ \overload
+*/
+int QtPrivate::compareStrings(QBasicUtf8StringView<false> lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return qt_compare_strings(lhs, rhs, cs);
+}
- Case-sensitive comparison is based exclusively on the numeric values of the
- decoded Unicode code points and is very fast, but is not what a human would
- expect. Consider sorting user-visible strings with
- QString::localeAwareCompare().
+/*!
+ \relates QStringView
+ \internal
+ \since 6.0
+ \overload
*/
-int QtPrivate::compareStringsUtf8(const char *u8str, qsizetype u8len, QStringView rhs, Qt::CaseSensitivity cs) noexcept
+int QtPrivate::compareStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
{
- if (cs == Qt::CaseSensitive)
- return QUtf8::compareUtf8(u8str, u8len, rhs.data(), rhs.size());
- else
- return ucstricmp8(u8str, u8str + u8len, rhs.begin(), rhs.end());
+ return qt_compare_strings(lhs, rhs, cs);
}
#define REHASH(a) \
@@ -4797,6 +4859,21 @@ QByteArray QString::toLatin1_helper(const QString &string)
}
/*!
+ \since 6.0
+ \internal
+ \relates QAnyStringView
+
+ Returns a UTF-16 representation of \a string as a QString.
+
+ \sa QString::toLatin1(), QStringView::toLatin1(), QtPrivate::convertToUtf8(),
+ QtPrivate::convertToLocal8Bit(), QtPrivate::convertToUcs4()
+*/
+QString QtPrivate::convertToQString(QAnyStringView string)
+{
+ return string.visit([] (auto string) { return string.toString(); });
+}
+
+/*!
\since 5.10
\internal
\relates QStringView