summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2020-09-23 19:32:24 +0200
committerLars Knoll <lars.knoll@qt.io>2020-10-07 14:57:51 +0200
commit8a7b74f6e71d6b8264f365148bf5a04db4038617 (patch)
treebe16b5d1fb3299f75fa9641f5c113db4ed3791e0
parent3807559d3779d2d6df4fb9180d2c4093ea1706ae (diff)
Optimize equality operators for string classes
Using compare() for those operators is not a good idea, as we can't shortcut comparisons if the string sizes are different. This alone made our HTML parser in QtGui around 15% slower. Don't go through QAnyStringView to implement compare() for QUtf8StringView, use QtPrivate::compareStrings() directly instead. Task-number: QTBUG-86354 Change-Id: I04869c29c9918161990dc1baf8e943b3a264ff3c Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
-rw-r--r--src/corelib/text/qanystringview.h5
-rw-r--r--src/corelib/text/qstring.cpp57
-rw-r--r--src/corelib/text/qstring.h11
-rw-r--r--src/corelib/text/qstringalgorithms.h10
-rw-r--r--src/corelib/text/qutf8stringview.h12
5 files changed, 82 insertions, 13 deletions
diff --git a/src/corelib/text/qanystringview.h b/src/corelib/text/qanystringview.h
index 647f43f265..c073eda3b6 100644
--- a/src/corelib/text/qanystringview.h
+++ b/src/corelib/text/qanystringview.h
@@ -200,6 +200,7 @@ public:
[[nodiscard]] constexpr const void *data() const noexcept { return m_data; }
[[nodiscard]] Q_CORE_EXPORT static int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
+ [[nodiscard]] Q_CORE_EXPORT static bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept;
//
// STL compatibility API:
@@ -224,9 +225,9 @@ public:
private:
[[nodiscard]] friend inline bool operator==(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) == 0; }
+ { return QAnyStringView::equal(lhs, rhs); }
[[nodiscard]] friend inline bool operator!=(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return !operator==(lhs, rhs); }
+ { return !QAnyStringView::equal(lhs, rhs); }
#ifdef __cpp_impl_three_way_comparison
[[nodiscard]] friend inline auto operator<=>(QAnyStringView lhs, QAnyStringView rhs) noexcept
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 2838e513f1..71e51ab0fc 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -1325,6 +1325,63 @@ int QAnyStringView::compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSens
});
}
+bool QtPrivate::equalStrings(QStringView lhs, QStringView rhs) noexcept
+{
+ return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size()) == 0;
+}
+
+bool QtPrivate::equalStrings(QStringView lhs, QLatin1String rhs) noexcept
+{
+ return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size()) == 0;
+}
+
+bool QtPrivate::equalStrings(QLatin1String lhs, QStringView rhs) noexcept
+{
+ return QtPrivate::equalStrings(rhs, lhs);
+}
+
+bool QtPrivate::equalStrings(QLatin1String lhs, QLatin1String rhs) noexcept
+{
+ return lhs.size() == rhs.size() && (!lhs.size() || qstrncmp(lhs.data(), rhs.data(), lhs.size()) == 0);
+}
+
+bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QStringView rhs) noexcept
+{
+ return QUtf8::compareUtf8(lhs, rhs) == 0;
+}
+
+bool QtPrivate::equalStrings(QStringView lhs, QBasicUtf8StringView<false> rhs) noexcept
+{
+ return QtPrivate::equalStrings(rhs, lhs);
+}
+
+bool QtPrivate::equalStrings(QLatin1String lhs, QBasicUtf8StringView<false> rhs) noexcept
+{
+ QString r = rhs.toString();
+ return QtPrivate::equalStrings(lhs, r); // ### optimize!
+}
+
+bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QLatin1String rhs) noexcept
+{
+ return QtPrivate::equalStrings(rhs, lhs);
+}
+
+bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs) noexcept
+{
+ return lhs.size() == rhs.size() && (!lhs.size() || qstrncmp(lhs.data(), rhs.data(), lhs.size()) == 0);
+}
+
+bool QAnyStringView::equal(QAnyStringView lhs, QAnyStringView rhs) noexcept
+{
+ if (lhs.size() != rhs.size() && lhs.isUtf8() == rhs.isUtf8())
+ return false;
+ return lhs.visit([rhs](auto lhs) {
+ return rhs.visit([lhs](auto rhs) {
+ return QtPrivate::equalStrings(lhs, rhs);
+ });
+ });
+}
+
/*!
\relates QStringView
\internal
diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h
index 5c809592e8..00efa8d1b0 100644
--- a/src/corelib/text/qstring.h
+++ b/src/corelib/text/qstring.h
@@ -1042,11 +1042,6 @@ QString QBasicUtf8StringView<UseChar8T>::toString() const
return QString::fromUtf8(data(), int(size()));
}
-template<bool UseChar8T>
-inline int QBasicUtf8StringView<UseChar8T>::compare(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs,
- Qt::CaseSensitivity cs) noexcept
-{ return QAnyStringView::compare(lhs, rhs, cs); }
-
//
// QAnyStringView inline members that require QString:
//
@@ -1444,7 +1439,7 @@ inline bool operator<=(QLatin1String lhs, QChar rhs) noexcept { return !(rhs <
inline bool operator>=(QLatin1String lhs, QChar rhs) noexcept { return !(rhs > lhs); }
// QStringView <> QStringView
-inline bool operator==(QStringView lhs, QStringView rhs) noexcept { return lhs.size() == rhs.size() && QtPrivate::compareStrings(lhs, rhs) == 0; }
+inline bool operator==(QStringView lhs, QStringView rhs) noexcept { return lhs.size() == rhs.size() && QtPrivate::equalStrings(lhs, rhs); }
inline bool operator!=(QStringView lhs, QStringView rhs) noexcept { return !(lhs == rhs); }
inline bool operator< (QStringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) < 0; }
inline bool operator<=(QStringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) <= 0; }
@@ -1467,14 +1462,14 @@ inline bool operator> (QChar lhs, QStringView rhs) noexcept { return QStringView
inline bool operator>=(QChar lhs, QStringView rhs) noexcept { return QStringView(&lhs, 1) >= rhs; }
// QStringView <> QLatin1String
-inline bool operator==(QStringView lhs, QLatin1String rhs) noexcept { return lhs.size() == rhs.size() && QtPrivate::compareStrings(lhs, rhs) == 0; }
+inline bool operator==(QStringView lhs, QLatin1String rhs) noexcept { return lhs.size() == rhs.size() && QtPrivate::equalStrings(lhs, rhs); }
inline bool operator!=(QStringView lhs, QLatin1String rhs) noexcept { return !(lhs == rhs); }
inline bool operator< (QStringView lhs, QLatin1String rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) < 0; }
inline bool operator<=(QStringView lhs, QLatin1String rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) <= 0; }
inline bool operator> (QStringView lhs, QLatin1String rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) > 0; }
inline bool operator>=(QStringView lhs, QLatin1String rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) >= 0; }
-inline bool operator==(QLatin1String lhs, QStringView rhs) noexcept { return lhs.size() == rhs.size() && QtPrivate::compareStrings(lhs, rhs) == 0; }
+inline bool operator==(QLatin1String lhs, QStringView rhs) noexcept { return lhs.size() == rhs.size() && QtPrivate::equalStrings(lhs, rhs); }
inline bool operator!=(QLatin1String lhs, QStringView rhs) noexcept { return !(lhs == rhs); }
inline bool operator< (QLatin1String lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) < 0; }
inline bool operator<=(QLatin1String lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) <= 0; }
diff --git a/src/corelib/text/qstringalgorithms.h b/src/corelib/text/qstringalgorithms.h
index 5e2eb1912a..6d8fe114f1 100644
--- a/src/corelib/text/qstringalgorithms.h
+++ b/src/corelib/text/qstringalgorithms.h
@@ -86,6 +86,16 @@ namespace QtPrivate {
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int compareStrings(QBasicUtf8StringView<false> lhs, QLatin1String rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int compareStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QStringView lhs, QStringView rhs) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QStringView lhs, QLatin1String rhs) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QStringView lhs, QBasicUtf8StringView<false> rhs) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QLatin1String lhs, QStringView rhs) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QLatin1String lhs, QLatin1String rhs) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QLatin1String lhs, QBasicUtf8StringView<false> rhs) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QBasicUtf8StringView<false> lhs, QStringView rhs) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QBasicUtf8StringView<false> lhs, QLatin1String rhs) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs) noexcept;
+
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
diff --git a/src/corelib/text/qutf8stringview.h b/src/corelib/text/qutf8stringview.h
index 98357ae5a9..55621588bd 100644
--- a/src/corelib/text/qutf8stringview.h
+++ b/src/corelib/text/qutf8stringview.h
@@ -306,11 +306,17 @@ public:
#endif
private:
- [[nodiscard]] static inline int compare(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs,
- Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
+ [[nodiscard]] static inline int compare(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
+ {
+ return QtPrivate::compareStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()),
+ QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
+ }
[[nodiscard]] friend inline bool operator==(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
- { return QBasicUtf8StringView::compare(lhs, rhs) == 0; }
+ {
+ return QtPrivate::equalStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()),
+ QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
+ }
[[nodiscard]] friend inline bool operator!=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
{ return !operator==(lhs, rhs); }