From 6631444eb12b76608e5d945bc3d53e1678a6a36d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 30 Nov 2022 16:22:00 +0100 Subject: [PATCH] QString/QByteArray/QList: de-pessimize op+ [2/2]: overload on rvalue LHS The + operator is left-associative, so a + b + c is (a + b) + c. Apply the same trick C++20 applied to std::string's op+ and overload for rvalue left-hand sides. This means that a + b + c is now equivalent to [&] { auto tmp = a; tmp += b; tmp += c; return tmp; }() removing a ton of temporary buffers (not objects, because CoW makes it impossible for the compiler to track the single conceptual object passing through the chain) when not using QStringBuilder (which isn't available for QList). This is BC, because the operators are all inline free functions or at least inline members of non-exported classes. Use multi-\fn to document the new operators. No \since is needed, as this doesn't change the set of supported operations, just makes some of them faster. [ChangeLog][QtCore][QList/QString/QByteArray] Chained additions (a + b + c) now produce only one temporary buffer for the whole expression instead of one per addition. Using += or QStringBuilder is still faster, though. Change-Id: I87e837d8803e79dc29c9268f73e6df9fcc0b09a3 Reviewed-by: Qt CI Bot Reviewed-by: Thiago Macieira --- src/corelib/text/qbytearray.h | 6 ++++++ src/corelib/text/qstring.cpp | 1 + src/corelib/text/qstring.h | 8 ++++++++ src/corelib/tools/qlist.h | 8 ++++++-- src/corelib/tools/qlist.qdoc | 14 +++++--------- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index afe234d643..c2e456fc29 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -560,10 +560,16 @@ inline int QByteArray::compare(QByteArrayView a, Qt::CaseSensitivity cs) const n #if !defined(QT_USE_QSTRINGBUILDER) inline QByteArray operator+(const QByteArray &a1, const QByteArray &a2) { return QByteArray(a1) += a2; } +inline QByteArray operator+(QByteArray &&lhs, const QByteArray &rhs) +{ return std::move(lhs += rhs); } inline QByteArray operator+(const QByteArray &a1, const char *a2) { return QByteArray(a1) += a2; } +inline QByteArray operator+(QByteArray &&lhs, const char *rhs) +{ return std::move(lhs += rhs); } inline QByteArray operator+(const QByteArray &a1, char a2) { return QByteArray(a1) += a2; } +inline QByteArray operator+(QByteArray &&lhs, char rhs) +{ return std::move(lhs += rhs); } inline QByteArray operator+(const char *a1, const QByteArray &a2) { return QByteArray(a1) += a2; } inline QByteArray operator+(char a1, const QByteArray &a2) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 8eb6db84d5..ae2e38f1a3 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -6386,6 +6386,7 @@ QString& QString::fill(QChar ch, qsizetype size) /*! \fn QString operator+(const QString &s1, const QString &s2) + \fn QString operator+(QString &&s1, const QString &s2) \relates QString Returns a string which is the result of concatenating \a s1 and \a diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 81a7e492f1..5f54b198fb 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -1490,19 +1490,27 @@ inline bool QByteArray::operator>=(const QString &s) const #if !defined(QT_USE_FAST_OPERATOR_PLUS) && !defined(QT_USE_QSTRINGBUILDER) inline QString operator+(const QString &s1, const QString &s2) { QString t(s1); t += s2; return t; } +inline QString operator+(QString &&lhs, const QString &rhs) +{ return std::move(lhs += rhs); } inline QString operator+(const QString &s1, QChar s2) { QString t(s1); t += s2; return t; } +inline QString operator+(QString &&lhs, QChar rhs) +{ return std::move(lhs += rhs); } inline QString operator+(QChar s1, const QString &s2) { QString t(s1); t += s2; return t; } # if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) QT_ASCII_CAST_WARN inline QString operator+(const QString &s1, const char *s2) { QString t(s1); t += QString::fromUtf8(s2); return t; } +QT_ASCII_CAST_WARN inline QString operator+(QString &&lhs, const char *rhs) +{ QT_IGNORE_DEPRECATIONS(return std::move(lhs += rhs);) } QT_ASCII_CAST_WARN inline QString operator+(const char *s1, const QString &s2) { QString t = QString::fromUtf8(s1); t += s2; return t; } QT_ASCII_CAST_WARN inline QString operator+(const QByteArray &ba, const QString &s) { QString t = QString::fromUtf8(ba); t += s; return t; } QT_ASCII_CAST_WARN inline QString operator+(const QString &s, const QByteArray &ba) { QString t(s); t += QString::fromUtf8(ba); return t; } +QT_ASCII_CAST_WARN inline QString operator+(QString &&lhs, const QByteArray &rhs) +{ QT_IGNORE_DEPRECATIONS(return std::move(lhs += rhs);) } # endif // QT_NO_CAST_FROM_ASCII #endif // QT_USE_QSTRINGBUILDER diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 2856510d93..cc65039941 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -669,10 +669,14 @@ public: // comfort QList &operator+=(const QList &l) { append(l); return *this; } QList &operator+=(QList &&l) { append(std::move(l)); return *this; } - inline QList operator+(const QList &l) const + inline QList operator+(const QList &l) const & { QList n = *this; n += l; return n; } - inline QList operator+(QList &&l) const + QList operator+(const QList &l) && + { return std::move(*this += l); } + inline QList operator+(QList &&l) const & { QList n = *this; n += std::move(l); return n; } + QList operator+(QList &&l) && + { return std::move(*this += std::move(l)); } inline QList &operator+=(parameter_type t) { append(t); return *this; } inline QList &operator<< (parameter_type t) diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc index f3b501a0e9..28aa1f271f 100644 --- a/src/corelib/tools/qlist.qdoc +++ b/src/corelib/tools/qlist.qdoc @@ -1316,7 +1316,11 @@ \sa append(), operator<<() */ -/*! \fn template QList QList::operator+(const QList &other) const +/*! + \fn template QList QList::operator+(const QList &other) const & + \fn template QList QList::operator+(const QList &other) && + \fn template QList QList::operator+(QList &&other) const & + \fn template QList QList::operator+(QList &&other) && Returns a list that contains all the items in this list followed by all the items in the \a other list. @@ -1324,14 +1328,6 @@ \sa operator+=() */ -/*! \fn template QList QList::operator+(QList &&other) const - \since 6.0 - - \overload - - \sa operator+=() -*/ - /*! \fn template QList &QList::operator<<(parameter_type value) Appends \a value to the list and returns a reference to this list.