diff --git a/src/corelib/text/qanystringview.cpp b/src/corelib/text/qanystringview.cpp index df117c3fc40..4129257c02d 100644 --- a/src/corelib/text/qanystringview.cpp +++ b/src/corelib/text/qanystringview.cpp @@ -17,6 +17,12 @@ QT_BEGIN_NAMESPACE \ingroup tools \ingroup string-processing + \compares strong + \compareswith strong char16_t QChar {const char16_t *} {const char *} \ + QByteArray QByteArrayView QString QStringView QUtf8StringView \ + QLatin1StringView + \endcompareswith + A QAnyStringView references a contiguous portion of a string it does not own. It acts as an interface type to all kinds of strings, without the need to construct a QString first. @@ -582,12 +588,12 @@ QT_BEGIN_NAMESPACE */ /*! - \fn bool QAnyStringView::operator==(QAnyStringView lhs, QAnyStringView rhs) - \fn bool QAnyStringView::operator!=(QAnyStringView lhs, QAnyStringView rhs) - \fn bool QAnyStringView::operator<=(QAnyStringView lhs, QAnyStringView rhs) - \fn bool QAnyStringView::operator>=(QAnyStringView lhs, QAnyStringView rhs) - \fn bool QAnyStringView::operator<(QAnyStringView lhs, QAnyStringView rhs) - \fn bool QAnyStringView::operator>(QAnyStringView lhs, QAnyStringView rhs) + \fn bool QAnyStringView::operator==(const QAnyStringView &lhs, const QAnyStringView & rhs) + \fn bool QAnyStringView::operator!=(const QAnyStringView & lhs, const QAnyStringView & rhs) + \fn bool QAnyStringView::operator<=(const QAnyStringView & lhs, const QAnyStringView & rhs) + \fn bool QAnyStringView::operator>=(const QAnyStringView & lhs, const QAnyStringView & rhs) + \fn bool QAnyStringView::operator<(const QAnyStringView & lhs, const QAnyStringView & rhs) + \fn bool QAnyStringView::operator>(const QAnyStringView & lhs, const QAnyStringView & rhs) Operators that compare \a lhs to \a rhs. diff --git a/src/corelib/text/qanystringview.h b/src/corelib/text/qanystringview.h index d74d371e2d8..b7f3650275f 100644 --- a/src/corelib/text/qanystringview.h +++ b/src/corelib/text/qanystringview.h @@ -4,6 +4,7 @@ #ifndef QANYSTRINGVIEW_H #define QANYSTRINGVIEW_H +#include #include #include #include @@ -301,24 +302,15 @@ public: { return size(); } private: - [[nodiscard]] friend inline bool operator==(QAnyStringView lhs, QAnyStringView rhs) noexcept + friend bool comparesEqual(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept { return QAnyStringView::equal(lhs, rhs); } - [[nodiscard]] friend inline bool operator!=(QAnyStringView lhs, QAnyStringView rhs) noexcept - { return !QAnyStringView::equal(lhs, rhs); } - -#if defined(__cpp_impl_three_way_comparison) && !defined(Q_QDOC) - [[nodiscard]] friend inline auto operator<=>(QAnyStringView lhs, QAnyStringView rhs) noexcept - { return QAnyStringView::compare(lhs, rhs) <=> 0; } -#else - [[nodiscard]] friend inline bool operator<=(QAnyStringView lhs, QAnyStringView rhs) noexcept - { return QAnyStringView::compare(lhs, rhs) <= 0; } - [[nodiscard]] friend inline bool operator>=(QAnyStringView lhs, QAnyStringView rhs) noexcept - { return QAnyStringView::compare(lhs, rhs) >= 0; } - [[nodiscard]] friend inline bool operator<(QAnyStringView lhs, QAnyStringView rhs) noexcept - { return QAnyStringView::compare(lhs, rhs) < 0; } - [[nodiscard]] friend inline bool operator>(QAnyStringView lhs, QAnyStringView rhs) noexcept - { return QAnyStringView::compare(lhs, rhs) > 0; } -#endif + friend Qt::strong_ordering + compareThreeWay(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept + { + const int res = QAnyStringView::compare(lhs, rhs); + return Qt::compareThreeWay(res, 0); + } + Q_DECLARE_STRONGLY_ORDERED(QAnyStringView) #ifndef QT_NO_DEBUG_STREAM Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s); diff --git a/tests/auto/corelib/text/qanystringview/CMakeLists.txt b/tests/auto/corelib/text/qanystringview/CMakeLists.txt index 492e89be4d9..96837dadf60 100644 --- a/tests/auto/corelib/text/qanystringview/CMakeLists.txt +++ b/tests/auto/corelib/text/qanystringview/CMakeLists.txt @@ -16,6 +16,7 @@ qt_internal_add_test(tst_qanystringview tst_qanystringview.cpp LIBRARIES Qt::CorePrivate + Qt::TestPrivate ) ## Scopes: diff --git a/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp b/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp index 6c29ac1cc24..0eaadb870c6 100644 --- a/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp +++ b/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp @@ -12,6 +12,7 @@ # include #endif #include +#include #include @@ -378,8 +379,9 @@ private Q_SLOTS: void fromQStringBuilder_QString_QString() const { fromQStringBuilder(u"1"_s % u"2"_s, u"12"); } + void comparisonCompiles(); + void comparison_data(); void comparison(); - void compare3way(); private: template @@ -819,46 +821,97 @@ void tst_QAnyStringView::conversion_tests(String string) const } } -void tst_QAnyStringView::comparison() +void tst_QAnyStringView::comparisonCompiles() { - const QAnyStringView aa = u"aa"; - const QAnyStringView upperAa = u"AA"; - const QAnyStringView bb = u"bb"; - - QVERIFY(aa == aa); - QVERIFY(aa != bb); - QVERIFY(aa < bb); - QVERIFY(bb > aa); - - QCOMPARE(QAnyStringView::compare(aa, aa), 0); - QVERIFY(QAnyStringView::compare(aa, upperAa) != 0); - QCOMPARE(QAnyStringView::compare(aa, upperAa, Qt::CaseInsensitive), 0); - QVERIFY(QAnyStringView::compare(aa, bb) < 0); - QVERIFY(QAnyStringView::compare(bb, aa) > 0); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); + QTestPrivate::testAllComparisonOperatorsCompile(); } -void tst_QAnyStringView::compare3way() +void tst_QAnyStringView::comparison_data() { -#define COMPARE_3WAY(lhs, rhs, res) \ - do { \ - const auto qt_3way_cmp_res = (lhs) <=> (rhs); \ - static_assert(std::is_same_v); \ - QCOMPARE(std::is_eq(qt_3way_cmp_res), std::is_eq(res)); \ - QCOMPARE(std::is_lt(qt_3way_cmp_res), std::is_lt(res)); \ - QCOMPARE(std::is_gt(qt_3way_cmp_res), std::is_gt(res)); \ - } while (false) + QTest::addColumn("lhs"); + QTest::addColumn("rhs"); + QTest::addColumn("csr"); // case sensitive result + QTest::addColumn("cir"); // case insensitive result - ONLY_3WAY( - const QAnyStringView aa = u"aa"; - const QAnyStringView upperAa = u"AA"; - const QAnyStringView bb = u"bb"; - COMPARE_3WAY(aa, aa, std::strong_ordering::equal); - COMPARE_3WAY(aa, bb, std::strong_ordering::less); - COMPARE_3WAY(bb, aa, std::strong_ordering::greater); - COMPARE_3WAY(upperAa, aa, std::strong_ordering::less); - COMPARE_3WAY(aa, upperAa, std::strong_ordering::greater); - ); -#undef COMPARE_3WAY + auto row = [&](QAnyStringView l, QAnyStringView r, int csr, int cir) { + QTest::addRow("%s_vs_%s", qPrintable(l.toString()), qPrintable(r.toString())) + << l << r << csr << cir; + }; + row(u"aa", u"aa", 0, 0); + row(u"aa", u"AA", 1, 0); + row(u"ab", u"b", -1, -1); + row(u"ab", u"aBb", 1, -1); + row(u"ab", u"B", 1, -1); +} + +static int sign(int x) +{ + return x == 0 ? 0 : (x < 0 ? -1 : 1); +} + +void tst_QAnyStringView::comparison() +{ + QFETCH(const QAnyStringView, lhs); + QFETCH(const QAnyStringView, rhs); + QFETCH(const int, csr); + QFETCH(const int, cir); + + QCOMPARE(sign(QAnyStringView::compare(lhs, rhs)), csr); + QCOMPARE(sign(QAnyStringView::compare(lhs, rhs, Qt::CaseInsensitive)), cir); + + const Qt::strong_ordering ordering = [&csr] { + if (csr == 0) + return Qt::strong_ordering::equal; + else if (csr < 0) + return Qt::strong_ordering::less; + else + return Qt::strong_ordering::greater; + }(); + QT_TEST_ALL_COMPARISON_OPS(lhs, rhs, ordering); + + const QString rhs_str = rhs.toString(); + QT_TEST_ALL_COMPARISON_OPS(lhs, rhs_str, ordering); + + const QStringView rhs_sv(rhs_str); + QT_TEST_ALL_COMPARISON_OPS(lhs, rhs_sv, ordering); + + if (!rhs_str.contains(QChar(u'\0'))) { + const char16_t *utfData = reinterpret_cast(rhs_str.constData()); + QT_TEST_ALL_COMPARISON_OPS(lhs, utfData, ordering); + } + + if (rhs_str.size() == 1) { + const QChar ch = rhs_str.front(); + QT_TEST_ALL_COMPARISON_OPS(lhs, ch, ordering); + } + + if (rhs.isLatin1()) { + const QLatin1StringView rhs_l1 = rhs.asLatin1StringView(); + QT_TEST_ALL_COMPARISON_OPS(lhs, rhs_l1, ordering); + } + + const QByteArray rhs_u8 = rhs_str.toUtf8(); + + const QUtf8StringView rhs_u8sv(rhs_u8.data(), rhs_u8.size()); + QT_TEST_ALL_COMPARISON_OPS(lhs, rhs_u8sv, ordering); + + QT_TEST_ALL_COMPARISON_OPS(lhs, rhs_u8, ordering); + const QByteArrayView rhs_u8view{rhs_u8.begin(), rhs_u8.size()}; + QT_TEST_ALL_COMPARISON_OPS(lhs, rhs_u8view, ordering); + if (!rhs_str.contains(QChar(u'\0'))) { + const char *rhs_u8data = rhs_u8.constData(); + QT_TEST_ALL_COMPARISON_OPS(lhs, rhs_u8data, ordering); + } } QTEST_APPLESS_MAIN(tst_QAnyStringView)