QByteArray: use comparison helper macros

Replace the existing friend relational operators with the macros.
Add the previously-missing relational opertors with QChar and char16_t.

This allows to remove the last dummy relational operators and the
macros to generate them in tst_qstringapisymmetry.

Because of a bug in libstdc++[0], we have to explicitly keep the
QBA vs QBA relational operators even in C++20 mode. This problem is
specific to QByteArray, because it is convertible to const void *.

[0]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114153

Task-number: QTBUG-117661
Change-Id: Iac7f81cd3274331b7c7695a51803321b511361c0
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Ivan Solovev 2024-02-22 16:49:37 +01:00
parent ee612626f9
commit 7068418a13
4 changed files with 118 additions and 127 deletions

View File

@ -809,6 +809,14 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
\reentrant
\compares strong
\compareswith strong {const char *} QByteArrayView
\endcompareswith
\compareswith strong QChar char16_t QString QStringView QLatin1StringView \
QUtf8StringView
When comparing with string types, the content is interpreted as utf-8.
\endcompareswith
QByteArray can be used to store both raw bytes (including '\\0's)
and traditional 8-bit '\\0'-terminated strings. Using QByteArray
is much more convenient than using \c{const char *}. Behind the
@ -3382,164 +3390,164 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
}
#endif // QT_NO_DATASTREAM
/*! \fn bool QByteArray::operator==(const QByteArray &a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator==(const QByteArray &lhs, const QByteArray &rhs)
\overload
Returns \c true if byte array \a a1 is equal to byte array \a a2;
Returns \c true if byte array \a lhs is equal to byte array \a rhs;
otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator==(const QByteArray &a1, const char *a2)
/*! \fn bool QByteArray::operator==(const QByteArray &lhs, const char * const &rhs)
\overload
Returns \c true if byte array \a a1 is equal to the '\\0'-terminated string
\a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is equal to the '\\0'-terminated string
\a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator==(const char *a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator==(const char * const &lhs, const QByteArray &rhs)
\overload
Returns \c true if '\\0'-terminated string \a a1 is equal to byte array \a
a2; otherwise returns \c false.
Returns \c true if '\\0'-terminated string \a lhs is equal to byte array \a
rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator!=(const QByteArray &a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator!=(const QByteArray &lhs, const QByteArray &rhs)
\overload
Returns \c true if byte array \a a1 is not equal to byte array \a a2;
Returns \c true if byte array \a lhs is not equal to byte array \a rhs;
otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator!=(const QByteArray &a1, const char *a2)
/*! \fn bool QByteArray::operator!=(const QByteArray &lhs, const char * const &rhs)
\overload
Returns \c true if byte array \a a1 is not equal to the '\\0'-terminated
string \a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is not equal to the '\\0'-terminated
string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator!=(const char *a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator!=(const char * const &lhs, const QByteArray &rhs)
\overload
Returns \c true if '\\0'-terminated string \a a1 is not equal to byte array
\a a2; otherwise returns \c false.
Returns \c true if '\\0'-terminated string \a lhs is not equal to byte array
\a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator<(const QByteArray &a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator<(const QByteArray &lhs, const QByteArray &rhs)
\overload
Returns \c true if byte array \a a1 is lexically less than byte array
\a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is lexically less than byte array
\a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator<(const QByteArray &a1, const char *a2)
/*! \fn bool QByteArray::operator<(const QByteArray &lhs, const char * const &rhs)
\overload
Returns \c true if byte array \a a1 is lexically less than the
'\\0'-terminated string \a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is lexically less than the
'\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator<(const char *a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator<(const char * const &lhs, const QByteArray &rhs)
\overload
Returns \c true if '\\0'-terminated string \a a1 is lexically less than byte
array \a a2; otherwise returns \c false.
Returns \c true if '\\0'-terminated string \a lhs is lexically less than byte
array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator<=(const QByteArray &a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator<=(const QByteArray &lhs, const QByteArray &rhs)
\overload
Returns \c true if byte array \a a1 is lexically less than or equal
to byte array \a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is lexically less than or equal
to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator<=(const QByteArray &a1, const char *a2)
/*! \fn bool QByteArray::operator<=(const QByteArray &lhs, const char * const &rhs)
\overload
Returns \c true if byte array \a a1 is lexically less than or equal to the
'\\0'-terminated string \a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is lexically less than or equal to the
'\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator<=(const char *a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator<=(const char * const &lhs, const QByteArray &rhs)
\overload
Returns \c true if '\\0'-terminated string \a a1 is lexically less than or
equal to byte array \a a2; otherwise returns \c false.
Returns \c true if '\\0'-terminated string \a lhs is lexically less than or
equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator>(const QByteArray &a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator>(const QByteArray &lhs, const QByteArray &rhs)
\overload
Returns \c true if byte array \a a1 is lexically greater than byte
array \a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is lexically greater than byte
array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator>(const QByteArray &a1, const char *a2)
/*! \fn bool QByteArray::operator>(const QByteArray &lhs, const char * const &rhs)
\overload
Returns \c true if byte array \a a1 is lexically greater than the
'\\0'-terminated string \a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is lexically greater than the
'\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator>(const char *a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator>(const char * const &lhs, const QByteArray &rhs)
\overload
Returns \c true if '\\0'-terminated string \a a1 is lexically greater than
byte array \a a2; otherwise returns \c false.
Returns \c true if '\\0'-terminated string \a lhs is lexically greater than
byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator>=(const QByteArray &a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator>=(const QByteArray &lhs, const QByteArray &rhs)
\overload
Returns \c true if byte array \a a1 is lexically greater than or
equal to byte array \a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is lexically greater than or
equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator>=(const QByteArray &a1, const char *a2)
/*! \fn bool QByteArray::operator>=(const QByteArray &lhs, const char * const &rhs)
\overload
Returns \c true if byte array \a a1 is lexically greater than or equal to
the '\\0'-terminated string \a a2; otherwise returns \c false.
Returns \c true if byte array \a lhs is lexically greater than or equal to
the '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
/*! \fn bool QByteArray::operator>=(const char *a1, const QByteArray &a2)
/*! \fn bool QByteArray::operator>=(const char * const &lhs, const QByteArray &rhs)
\overload
Returns \c true if '\\0'-terminated string \a a1 is lexically greater than
or equal to byte array \a a2; otherwise returns \c false.
Returns \c true if '\\0'-terminated string \a lhs is lexically greater than
or equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/

View File

@ -368,57 +368,6 @@ public:
QT_ASCII_CAST_WARN inline bool operator>=(const QString &s2) const;
#endif // QT_CORE_REMOVED_SINCE(6, 8)
#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
friend inline bool operator==(const QByteArray &a1, const QByteArray &a2) noexcept
{ return QByteArrayView(a1) == QByteArrayView(a2); }
friend inline bool operator==(const QByteArray &a1, const char *a2) noexcept
{ return QByteArrayView(a1) == QByteArrayView(a2); }
friend inline bool operator==(const char *a1, const QByteArray &a2) noexcept
{ return QByteArrayView(a1) == QByteArrayView(a2); }
friend inline bool operator!=(const QByteArray &a1, const QByteArray &a2) noexcept
{ return !(a1==a2); }
friend inline bool operator!=(const QByteArray &a1, const char *a2) noexcept
{ return QByteArrayView(a1) != QByteArrayView(a2); }
friend inline bool operator!=(const char *a1, const QByteArray &a2) noexcept
{ return QByteArrayView(a1) != QByteArrayView(a2); }
friend inline bool operator<(const QByteArray &a1, const QByteArray &a2) noexcept
{ return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) < 0; }
friend inline bool operator<(const QByteArray &a1, const char *a2) noexcept
{ return QtPrivate::compareMemory(a1, a2) < 0; }
friend inline bool operator<(const char *a1, const QByteArray &a2) noexcept
{ return QtPrivate::compareMemory(a1, a2) < 0; }
friend inline bool operator<=(const QByteArray &a1, const QByteArray &a2) noexcept
{ return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) <= 0; }
friend inline bool operator<=(const QByteArray &a1, const char *a2) noexcept
{ return QtPrivate::compareMemory(a1, a2) <= 0; }
friend inline bool operator<=(const char *a1, const QByteArray &a2) noexcept
{ return QtPrivate::compareMemory(a1, a2) <= 0; }
friend inline bool operator>(const QByteArray &a1, const QByteArray &a2) noexcept
{ return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) > 0; }
friend inline bool operator>(const QByteArray &a1, const char *a2) noexcept
{ return QtPrivate::compareMemory(a1, a2) > 0; }
friend inline bool operator>(const char *a1, const QByteArray &a2) noexcept
{ return QtPrivate::compareMemory(a1, a2) > 0; }
friend inline bool operator>=(const QByteArray &a1, const QByteArray &a2) noexcept
{ return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) >= 0; }
friend inline bool operator>=(const QByteArray &a1, const char *a2) noexcept
{ return QtPrivate::compareMemory(a1, a2) >= 0; }
friend inline bool operator>=(const char *a1, const QByteArray &a2) noexcept
{ return QtPrivate::compareMemory(a1, a2) >= 0; }
// Check isEmpty() instead of isNull() for backwards compatibility.
friend inline bool operator==(const QByteArray &a1, std::nullptr_t) noexcept { return a1.isEmpty(); }
friend inline bool operator!=(const QByteArray &a1, std::nullptr_t) noexcept { return !a1.isEmpty(); }
friend inline bool operator< (const QByteArray & , std::nullptr_t) noexcept { return false; }
friend inline bool operator> (const QByteArray &a1, std::nullptr_t) noexcept { return !a1.isEmpty(); }
friend inline bool operator<=(const QByteArray &a1, std::nullptr_t) noexcept { return a1.isEmpty(); }
friend inline bool operator>=(const QByteArray & , std::nullptr_t) noexcept { return true; }
friend inline bool operator==(std::nullptr_t, const QByteArray &a2) noexcept { return a2 == nullptr; }
friend inline bool operator!=(std::nullptr_t, const QByteArray &a2) noexcept { return a2 != nullptr; }
friend inline bool operator< (std::nullptr_t, const QByteArray &a2) noexcept { return a2 > nullptr; }
friend inline bool operator> (std::nullptr_t, const QByteArray &a2) noexcept { return a2 < nullptr; }
friend inline bool operator<=(std::nullptr_t, const QByteArray &a2) noexcept { return a2 >= nullptr; }
friend inline bool operator>=(std::nullptr_t, const QByteArray &a2) noexcept { return a2 <= nullptr; }
short toShort(bool *ok = nullptr, int base = 10) const;
ushort toUShort(bool *ok = nullptr, int base = 10) const;
@ -566,7 +515,43 @@ private:
const int res = QtPrivate::compareMemory(QByteArrayView(lhs), rhs);
return Qt::compareThreeWay(res, 0);
}
Q_DECLARE_STRONGLY_ORDERED(QByteArray)
Q_DECLARE_STRONGLY_ORDERED(QByteArray, QByteArrayView)
Q_DECLARE_STRONGLY_ORDERED(QByteArray, const char *)
#if defined(__GLIBCXX__) && defined(__cpp_lib_three_way_comparison)
// libstdc++ has a bug [0] when `operator const void *()` is preferred over
// `operator<=>()` when calling std::less<> and other similar methods.
// Fix it by explicitly providing relational operators in such case.
// [0]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114153
friend bool operator<(const QByteArray &lhs, const QByteArray &rhs) noexcept
{ return is_lt(compareThreeWay(lhs, rhs)); }
friend bool operator<=(const QByteArray &lhs, const QByteArray &rhs) noexcept
{ return is_lteq(compareThreeWay(lhs, rhs)); }
friend bool operator>(const QByteArray &lhs, const QByteArray &rhs) noexcept
{ return is_gt(compareThreeWay(lhs, rhs)); }
friend bool operator>=(const QByteArray &lhs, const QByteArray &rhs) noexcept
{ return is_gteq(compareThreeWay(lhs, rhs)); }
#endif // defined(__GLIBCXX__) && defined(__cpp_lib_three_way_comparison)
// Check isEmpty() instead of isNull() for backwards compatibility.
friend bool comparesEqual(const QByteArray &lhs, std::nullptr_t) noexcept
{ return lhs.isEmpty(); }
friend Qt::strong_ordering compareThreeWay(const QByteArray &lhs, std::nullptr_t) noexcept
{ return lhs.isEmpty() ? Qt::strong_ordering::equivalent : Qt::strong_ordering::greater; }
Q_DECLARE_STRONGLY_ORDERED(QByteArray, std::nullptr_t)
// defined in qstring.cpp
friend Q_CORE_EXPORT bool comparesEqual(const QByteArray &lhs, const QChar &rhs) noexcept;
friend Q_CORE_EXPORT Qt::strong_ordering
compareThreeWay(const QByteArray &lhs, const QChar &rhs) noexcept;
friend Q_CORE_EXPORT bool comparesEqual(const QByteArray &lhs, char16_t rhs) noexcept;
friend Q_CORE_EXPORT Qt::strong_ordering
compareThreeWay(const QByteArray &lhs, char16_t rhs) noexcept;
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
Q_DECLARE_STRONGLY_ORDERED(QByteArray, QChar, QT_ASCII_CAST_WARN)
Q_DECLARE_STRONGLY_ORDERED(QByteArray, char16_t, QT_ASCII_CAST_WARN)
#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
void reallocData(qsizetype alloc, QArrayData::AllocationOption option);
void reallocGrowData(qsizetype n);

View File

@ -6731,6 +6731,28 @@ Qt::strong_ordering QByteArrayView::compareThreeWay(const QByteArrayView &lhs,
return Qt::compareThreeWay(res, 0);
}
bool comparesEqual(const QByteArray &lhs, const QChar &rhs) noexcept
{
return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
}
Qt::strong_ordering compareThreeWay(const QByteArray &lhs, const QChar &rhs) noexcept
{
const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
return Qt::compareThreeWay(res, 0);
}
bool comparesEqual(const QByteArray &lhs, char16_t rhs) noexcept
{
return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
}
Qt::strong_ordering compareThreeWay(const QByteArray &lhs, char16_t rhs) noexcept
{
const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
return Qt::compareThreeWay(res, 0);
}
/*!
\internal
\since 6.8

View File

@ -32,7 +32,6 @@ struct QAnyStringViewUsingU16 : QAnyStringView {}; // QAnyStringView with Utf-1
template <typename T>
QString toQString(const T &t) { return QString(t); }
QString toQString(QStringView view) { return view.toString(); }
QString toQString(QUtf8StringView view) { return view.toString(); }
template <typename Iterable>
QStringList toQStringList(const Iterable &i) {
@ -45,29 +44,6 @@ QStringList toQStringList(const Iterable &i) {
template <typename LHS, typename RHS>
constexpr bool is_fake_comparator_v = false;
// FIXME: these are missing at the time of writing, add them, then remove the dummies here:
#define MAKE_RELOP(op, A1, A2) \
static bool operator op (A1 lhs, A2 rhs) \
{ return toQString(lhs) op toQString(rhs); } \
/*end*/
#define MAKE_ALL(A1, A2) \
template <> constexpr bool is_fake_comparator_v<A1, A2> = true; \
MAKE_RELOP(==, A1, A2) \
MAKE_RELOP(!=, A1, A2) \
MAKE_RELOP(<, A1, A2) \
MAKE_RELOP(>, A1, A2) \
MAKE_RELOP(<=, A1, A2) \
MAKE_RELOP(>=, A1, A2) \
/*end*/
MAKE_ALL(char16_t, QByteArray)
MAKE_ALL(QByteArray, char16_t)
#undef MAKE_ALL
#undef MAKE_RELOP
// END FIXME
} // namespace
static constexpr int sign(int i) noexcept