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 <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Marc Mutz 2022-11-30 16:22:00 +01:00
parent e7e3e4cf25
commit 6631444eb1
5 changed files with 26 additions and 11 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -669,10 +669,14 @@ public:
// comfort
QList<T> &operator+=(const QList<T> &l) { append(l); return *this; }
QList<T> &operator+=(QList<T> &&l) { append(std::move(l)); return *this; }
inline QList<T> operator+(const QList<T> &l) const
inline QList<T> operator+(const QList<T> &l) const &
{ QList n = *this; n += l; return n; }
inline QList<T> operator+(QList<T> &&l) const
QList<T> operator+(const QList<T> &l) &&
{ return std::move(*this += l); }
inline QList<T> operator+(QList<T> &&l) const &
{ QList n = *this; n += std::move(l); return n; }
QList<T> operator+(QList<T> &&l) &&
{ return std::move(*this += std::move(l)); }
inline QList<T> &operator+=(parameter_type t)
{ append(t); return *this; }
inline QList<T> &operator<< (parameter_type t)

View File

@ -1316,7 +1316,11 @@
\sa append(), operator<<()
*/
/*! \fn template <typename T> QList<T> QList<T>::operator+(const QList<T> &other) const
/*!
\fn template <typename T> QList<T> QList<T>::operator+(const QList<T> &other) const &
\fn template <typename T> QList<T> QList<T>::operator+(const QList<T> &other) &&
\fn template <typename T> QList<T> QList<T>::operator+(QList<T> &&other) const &
\fn template <typename T> QList<T> QList<T>::operator+(QList<T> &&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 <typename T> QList<T> QList<T>::operator+(QList<T> &&other) const
\since 6.0
\overload
\sa operator+=()
*/
/*! \fn template <typename T> QList<T> &QList<T>::operator<<(parameter_type value)
Appends \a value to the list and returns a reference to this list.