diff options
author | Lars Knoll <lars.knoll@qt.io> | 2020-09-23 19:32:24 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2020-10-07 14:57:51 +0200 |
commit | 8a7b74f6e71d6b8264f365148bf5a04db4038617 (patch) | |
tree | be16b5d1fb3299f75fa9641f5c113db4ed3791e0 | |
parent | 3807559d3779d2d6df4fb9180d2c4093ea1706ae (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.h | 5 | ||||
-rw-r--r-- | src/corelib/text/qstring.cpp | 57 | ||||
-rw-r--r-- | src/corelib/text/qstring.h | 11 | ||||
-rw-r--r-- | src/corelib/text/qstringalgorithms.h | 10 | ||||
-rw-r--r-- | src/corelib/text/qutf8stringview.h | 12 |
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); } |