QChar: optimize comparison with QString{,Ref}

Instead of relying on the QString relational operators to
implicitly convert the QChar to a QString, add relational
operator overloads that compare the QChar without first
turning it into a QString, saving one memory allocation
per comparison, and allowing to mark the operation as
nothrow.

Consequently, in tst_QStringBinOps, verify now that all
relational operations are noexcept.

The added overloads make QChar ==/!= int comparisons
ambiguous. De-ambiguate by providing a constrained
template that matches int and nothing but int (otherwise,
the QChar and the int versions would compete for a
QChar::SpecialCharacter argument, and end up creating
new ambiguities). This solution may not be perfect, but
it can be easily extended should more ambiguities crop up.
The existing overload deals with all patterns found in
qtbase.

Change-Id: I4156d918e9b9134c1da684b8b69e0ee526ad24e3
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
This commit is contained in:
Marc Mutz 2015-12-13 03:43:00 +01:00
parent 96678806d6
commit e0ea0f6178
3 changed files with 47 additions and 0 deletions

View File

@ -578,6 +578,18 @@ Q_DECL_CONSTEXPR inline bool operator>=(QChar c1, QChar c2) Q_DECL_NOTHROW { ret
Q_DECL_CONSTEXPR inline bool operator> (QChar c1, QChar c2) Q_DECL_NOTHROW { return operator< (c2, c1); }
Q_DECL_CONSTEXPR inline bool operator<=(QChar c1, QChar c2) Q_DECL_NOTHROW { return !operator< (c2, c1); }
// disambiguate QChar == int (but only that, so constrain template to exactly 'int'):
template <typename T>
Q_DECL_DEPRECATED_X("don't compare ints to QChars, compare them to QChar::unicode() instead")
Q_DECL_CONSTEXPR inline
typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, int>::value, bool>::type
operator==(QChar lhs, T rhs) Q_DECL_NOEXCEPT { return lhs == QChar(rhs); }
template <typename T>
Q_DECL_DEPRECATED_X("don't compare ints to QChars, compare them to QChar::unicode() instead")
Q_DECL_CONSTEXPR inline
typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, int>::value, bool>::type
operator!=(QChar lhs, T rhs) Q_DECL_NOEXCEPT { return lhs != QChar(rhs); }
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QChar);
Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QChar &);

View File

@ -814,6 +814,10 @@ private:
Data *d;
friend inline bool operator==(QChar, const QString &) Q_DECL_NOTHROW;
friend inline bool operator< (QChar, const QString &) Q_DECL_NOTHROW;
friend inline bool operator> (QChar, const QString &) Q_DECL_NOTHROW;
friend inline bool operator==(QChar, const QStringRef &) Q_DECL_NOTHROW;
friend inline bool operator< (QChar, const QStringRef &) Q_DECL_NOTHROW;
friend inline bool operator> (QChar, const QStringRef &) Q_DECL_NOTHROW;
friend inline bool operator==(QChar, QLatin1String) Q_DECL_NOTHROW;
@ -1589,15 +1593,39 @@ inline bool operator> (const QStringRef &lhs, QLatin1String rhs) Q_DECL_NOTHROW
inline bool operator<=(const QStringRef &lhs, QLatin1String rhs) Q_DECL_NOTHROW { return rhs >= lhs; }
inline bool operator>=(const QStringRef &lhs, QLatin1String rhs) Q_DECL_NOTHROW { return rhs <= lhs; }
// QChar <> QString
inline bool operator==(QChar lhs, const QString &rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) == 0; }
inline bool operator< (QChar lhs, const QString &rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) < 0; }
inline bool operator> (QChar lhs, const QString &rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) > 0; }
inline bool operator!=(QChar lhs, const QString &rhs) Q_DECL_NOTHROW { return !(lhs == rhs); }
inline bool operator<=(QChar lhs, const QString &rhs) Q_DECL_NOTHROW { return !(lhs > rhs); }
inline bool operator>=(QChar lhs, const QString &rhs) Q_DECL_NOTHROW { return !(lhs < rhs); }
inline bool operator==(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs == lhs; }
inline bool operator!=(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs == lhs); }
inline bool operator< (const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs > lhs; }
inline bool operator> (const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs < lhs; }
inline bool operator<=(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs < lhs); }
inline bool operator>=(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs > lhs); }
// QChar <> QStringRef
inline bool operator==(QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) == 0; }
inline bool operator< (QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) < 0; }
inline bool operator> (QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW
{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) > 0; }
inline bool operator!=(QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW { return !(lhs == rhs); }
inline bool operator<=(QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW { return !(lhs > rhs); }
inline bool operator>=(QChar lhs, const QStringRef &rhs) Q_DECL_NOTHROW { return !(lhs < rhs); }
inline bool operator==(const QStringRef &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs == lhs; }
inline bool operator!=(const QStringRef &lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs == lhs); }
inline bool operator< (const QStringRef &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs > lhs; }
inline bool operator> (const QStringRef &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs < lhs; }
inline bool operator<=(const QStringRef &lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs < lhs); }

View File

@ -148,7 +148,14 @@ void tst_QStringApiSymmetry::compare_impl() const
const LHS lhs = make<LHS>(lhsUnicode, lhsLatin1);
const RHS rhs = make<RHS>(rhsUnicode, rhsLatin1);
#ifdef Q_COMPILER_NOEXCEPT
# define QVERIFY_NOEXCEPT(expr) QVERIFY(noexcept(expr))
#else
# define QVERIFY_NOEXCEPT(expr)
#endif
#define CHECK(op) \
QVERIFY_NOEXCEPT(lhs op rhs); \
do { if (caseSensitiveCompareResult op 0) { \
QVERIFY(lhs op rhs); \
} else { \