QAnyStringView: use new comparison helper macros

Also extend unit-test to use new test helper functions.
Remove the now-redundant test for three-way comparison, because it is
covered by the test helper functions.

Task-number: QTBUG-117661
Change-Id: I242b560c281245e04e34353c80000a20998fc677
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Ivan Solovev 2024-02-29 16:18:23 +01:00
parent 868a5342bb
commit 2bc9ad0e5d
4 changed files with 111 additions and 59 deletions

View File

@ -17,6 +17,12 @@ QT_BEGIN_NAMESPACE
\ingroup tools \ingroup tools
\ingroup string-processing \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 A QAnyStringView references a contiguous portion of a string it does
not own. It acts as an interface type to all kinds of strings, not own. It acts as an interface type to all kinds of strings,
without the need to construct a QString first. 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==(const QAnyStringView &lhs, const QAnyStringView & rhs)
\fn bool QAnyStringView::operator!=(QAnyStringView lhs, QAnyStringView rhs) \fn bool QAnyStringView::operator!=(const QAnyStringView & lhs, const QAnyStringView & rhs)
\fn bool QAnyStringView::operator<=(QAnyStringView lhs, QAnyStringView rhs) \fn bool QAnyStringView::operator<=(const QAnyStringView & lhs, const QAnyStringView & rhs)
\fn bool QAnyStringView::operator>=(QAnyStringView lhs, QAnyStringView rhs) \fn bool QAnyStringView::operator>=(const QAnyStringView & lhs, const QAnyStringView & rhs)
\fn bool QAnyStringView::operator<(QAnyStringView lhs, QAnyStringView rhs) \fn bool QAnyStringView::operator<(const QAnyStringView & lhs, const QAnyStringView & rhs)
\fn bool QAnyStringView::operator>(QAnyStringView lhs, QAnyStringView rhs) \fn bool QAnyStringView::operator>(const QAnyStringView & lhs, const QAnyStringView & rhs)
Operators that compare \a lhs to \a rhs. Operators that compare \a lhs to \a rhs.

View File

@ -4,6 +4,7 @@
#ifndef QANYSTRINGVIEW_H #ifndef QANYSTRINGVIEW_H
#define QANYSTRINGVIEW_H #define QANYSTRINGVIEW_H
#include <QtCore/qcompare.h>
#include <QtCore/qlatin1stringview.h> #include <QtCore/qlatin1stringview.h>
#include <QtCore/qstringview.h> #include <QtCore/qstringview.h>
#include <QtCore/qutf8stringview.h> #include <QtCore/qutf8stringview.h>
@ -301,24 +302,15 @@ public:
{ return size(); } { return size(); }
private: 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); } { return QAnyStringView::equal(lhs, rhs); }
[[nodiscard]] friend inline bool operator!=(QAnyStringView lhs, QAnyStringView rhs) noexcept friend Qt::strong_ordering
{ return !QAnyStringView::equal(lhs, rhs); } compareThreeWay(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
{
#if defined(__cpp_impl_three_way_comparison) && !defined(Q_QDOC) const int res = QAnyStringView::compare(lhs, rhs);
[[nodiscard]] friend inline auto operator<=>(QAnyStringView lhs, QAnyStringView rhs) noexcept return Qt::compareThreeWay(res, 0);
{ return QAnyStringView::compare(lhs, rhs) <=> 0; } }
#else Q_DECLARE_STRONGLY_ORDERED(QAnyStringView)
[[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
#ifndef QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s); Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s);

View File

@ -16,6 +16,7 @@ qt_internal_add_test(tst_qanystringview
tst_qanystringview.cpp tst_qanystringview.cpp
LIBRARIES LIBRARIES
Qt::CorePrivate Qt::CorePrivate
Qt::TestPrivate
) )
## Scopes: ## Scopes:

View File

@ -12,6 +12,7 @@
# include <private/qt_winrtbase_p.h> # include <private/qt_winrtbase_p.h>
#endif #endif
#include <private/qxmlstream_p.h> #include <private/qxmlstream_p.h>
#include <private/qcomparisontesthelper_p.h>
#include <QTest> #include <QTest>
@ -378,8 +379,9 @@ private Q_SLOTS:
void fromQStringBuilder_QString_QString() const { fromQStringBuilder(u"1"_s % u"2"_s, u"12"); } void fromQStringBuilder_QString_QString() const { fromQStringBuilder(u"1"_s % u"2"_s, u"12"); }
void comparisonCompiles();
void comparison_data();
void comparison(); void comparison();
void compare3way();
private: private:
template <typename StringBuilder> template <typename StringBuilder>
@ -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"; QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView>();
const QAnyStringView upperAa = u"AA"; QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, char16_t>();
const QAnyStringView bb = u"bb"; QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, QChar>();
QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, const char16_t *>();
QVERIFY(aa == aa); QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, const char *>();
QVERIFY(aa != bb); QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, QByteArray>();
QVERIFY(aa < bb); QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, QByteArrayView>();
QVERIFY(bb > aa); QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, QString>();
QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, QStringView>();
QCOMPARE(QAnyStringView::compare(aa, aa), 0); QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, QUtf8StringView>();
QVERIFY(QAnyStringView::compare(aa, upperAa) != 0); QTestPrivate::testAllComparisonOperatorsCompile<QAnyStringView, QLatin1StringView>();
QCOMPARE(QAnyStringView::compare(aa, upperAa, Qt::CaseInsensitive), 0);
QVERIFY(QAnyStringView::compare(aa, bb) < 0);
QVERIFY(QAnyStringView::compare(bb, aa) > 0);
} }
void tst_QAnyStringView::compare3way() void tst_QAnyStringView::comparison_data()
{ {
#define COMPARE_3WAY(lhs, rhs, res) \ QTest::addColumn<QAnyStringView>("lhs");
do { \ QTest::addColumn<QAnyStringView>("rhs");
const auto qt_3way_cmp_res = (lhs) <=> (rhs); \ QTest::addColumn<int>("csr"); // case sensitive result
static_assert(std::is_same_v<decltype(qt_3way_cmp_res), decltype(res)>); \ QTest::addColumn<int>("cir"); // case insensitive result
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)
ONLY_3WAY( auto row = [&](QAnyStringView l, QAnyStringView r, int csr, int cir) {
const QAnyStringView aa = u"aa"; QTest::addRow("%s_vs_%s", qPrintable(l.toString()), qPrintable(r.toString()))
const QAnyStringView upperAa = u"AA"; << l << r << csr << cir;
const QAnyStringView bb = u"bb"; };
COMPARE_3WAY(aa, aa, std::strong_ordering::equal); row(u"aa", u"aa", 0, 0);
COMPARE_3WAY(aa, bb, std::strong_ordering::less); row(u"aa", u"AA", 1, 0);
COMPARE_3WAY(bb, aa, std::strong_ordering::greater); row(u"ab", u"b", -1, -1);
COMPARE_3WAY(upperAa, aa, std::strong_ordering::less); row(u"ab", u"aBb", 1, -1);
COMPARE_3WAY(aa, upperAa, std::strong_ordering::greater); row(u"ab", u"B", 1, -1);
); }
#undef COMPARE_3WAY
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<const char16_t*>(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) QTEST_APPLESS_MAIN(tst_QAnyStringView)