QtCore: replace qSwap with std::swap/member-swap where possible

qSwap() is a monster that looks for ADL overloads of swap() and also
detects the noexcept of the wrapped swap() function, so it should only
be used when the argument type is unknown. In the vast majority of
cases, the type is known to be efficiently std::swap()able or to have
a member-swap. Call either of these.

For the common case of pointer types, circumvent the expensive trait
checks on std::swap() by providing a hand-rolled qt_ptr_swap()
template, the advantage being that it can be unconditionally noexcept,
removing all type traits instantiations. Don't document it, otherwise
we'd be unable to pick it to 6.2.

Effects on Clang -ftime-trace of a PCH'ed libQt6Gui.so build:

before:

  **** Template sets that took longest to instantiate:
   [...]
   27766 ms: qSwap<$> (9073 times, avg 3 ms)
   [...]
    2806 ms: std::swap<$> (1229 times, avg 2 ms)

   (30572ms)

after:

  **** Template sets that took longest to instantiate:
   [...]
   5047 ms: qSwap<$> (641 times, avg 7 ms)
   [...]
   3371 ms: std::swap<$> (1376 times, avg 2 ms)
   [qt_ptr_swap<$> does not appear in the top 400, so < 905ms]

   (< 9323ms)

As a drive-by, remove superfluous inline keywords and template
ornaments.

Task-number: QTBUG-97601
Pick-to: 6.3 6.2
Change-Id: I88f9b4e3cbece268c4a1238b6d50e5712a1bab5a
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Marc Mutz 2022-01-19 01:47:35 +01:00
parent b083c27d0a
commit b1b0c2970e
43 changed files with 74 additions and 60 deletions

View File

@ -1174,6 +1174,15 @@ constexpr void qSwap(T &value1, T &value2)
swap(value1, value2);
}
// pure compile-time micro-optimization for our own headers, so not documented:
template <typename T>
constexpr inline void qt_ptr_swap(T* &lhs, T* &rhs) noexcept
{
T *tmp = lhs;
lhs = rhs;
rhs = tmp;
}
QT_WARNING_POP
Q_CORE_EXPORT void *qMallocAligned(size_t size, size_t alignment) Q_ALLOC_SIZE(1);

View File

@ -105,7 +105,7 @@ public:
inline QDebug &operator=(const QDebug &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QDebug)
~QDebug();
inline void swap(QDebug &other) noexcept { qSwap(stream, other.stream); }
void swap(QDebug &other) noexcept { qt_ptr_swap(stream, other.stream); }
QDebug &resetFormat();

View File

@ -124,7 +124,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QDir)
void swap(QDir &other) noexcept
{ qSwap(d_ptr, other.d_ptr); }
{ d_ptr.swap(other.d_ptr); }
void setPath(const QString &path);
#ifdef Q_CLANG_QDOC

View File

@ -91,7 +91,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QFileInfo)
void swap(QFileInfo &other) noexcept
{ qSwap(d_ptr, other.d_ptr); }
{ d_ptr.swap(other.d_ptr); }
bool operator==(const QFileInfo &fileinfo) const;
inline bool operator!=(const QFileInfo &fileinfo) const { return !(operator==(fileinfo)); }

View File

@ -74,7 +74,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QProcessEnvironment)
QProcessEnvironment &operator=(const QProcessEnvironment &other);
void swap(QProcessEnvironment &other) noexcept { qSwap(d, other.d); }
void swap(QProcessEnvironment &other) noexcept { d.swap(other.d); }
bool operator==(const QProcessEnvironment &other) const;
inline bool operator!=(const QProcessEnvironment &other) const

View File

@ -65,7 +65,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QStorageInfo)
inline void swap(QStorageInfo &other) noexcept
{ qSwap(d, other.d); }
{ d.swap(other.d); }
void setPath(const QString &path);

View File

@ -192,7 +192,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QUrl)
~QUrl();
inline void swap(QUrl &other) noexcept { qSwap(d, other.d); }
void swap(QUrl &other) noexcept { qt_ptr_swap(d, other.d); }
void setUrl(const QString &url, ParsingMode mode = TolerantMode);
QString url(FormattingOptions options = FormattingOptions(PrettyDecoded)) const;

View File

@ -74,7 +74,7 @@ public:
bool operator!=(const QUrlQuery &other) const
{ return !(*this == other); }
void swap(QUrlQuery &other) noexcept { qSwap(d, other.d); }
void swap(QUrlQuery &other) noexcept { d.swap(other.d); }
bool isEmpty() const;
bool isDetached() const;

View File

@ -222,7 +222,7 @@ public:
inline QPersistentModelIndex(QPersistentModelIndex &&other) noexcept
: d(qExchange(other.d, nullptr)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPersistentModelIndex)
inline void swap(QPersistentModelIndex &other) noexcept { qSwap(d, other.d); }
void swap(QPersistentModelIndex &other) noexcept { qt_ptr_swap(d, other.d); }
bool operator==(const QModelIndex &other) const;
bool operator!=(const QModelIndex &other) const;
QPersistentModelIndex &operator=(const QModelIndex &other);

View File

@ -60,8 +60,8 @@ public:
void swap(QItemSelectionRange &other) noexcept
{
qSwap(tl, other.tl);
qSwap(br, other.br);
tl.swap(other.tl);
br.swap(other.br);
}
inline int top() const { return tl.row(); }

View File

@ -63,7 +63,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QBasicTimer)
void swap(QBasicTimer &other) noexcept { qSwap(id, other.id); }
void swap(QBasicTimer &other) noexcept { std::swap(id, other.id); }
bool isActive() const noexcept { return id != 0; }
int timerId() const noexcept { return id; }

View File

@ -70,7 +70,7 @@ public:
explicit QDeadlineTimer(qint64 msecs, Qt::TimerType type = Qt::CoarseTimer) noexcept;
void swap(QDeadlineTimer &other) noexcept
{ qSwap(t1, other.t1); qSwap(t2, other.t2); qSwap(type, other.type); }
{ std::swap(t1, other.t1); std::swap(t2, other.t2); std::swap(type, other.type); }
constexpr bool isForever() const noexcept
{ return t1 == (std::numeric_limits<qint64>::max)(); }

View File

@ -463,7 +463,7 @@ public:
Connection(Connection &&other) noexcept : d_ptr(qExchange(other.d_ptr, nullptr)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Connection)
void swap(Connection &other) noexcept { qSwap(d_ptr, other.d_ptr); }
void swap(Connection &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); }
};
inline void swap(QMetaObject::Connection &lhs, QMetaObject::Connection &rhs) noexcept

View File

@ -121,7 +121,7 @@ public:
bool operator!() const noexcept { return d == nullptr; }
void swap(QPropertyBindingPrivatePtr &other) noexcept
{ qSwap(d, other.d); }
{ qt_ptr_swap(d, other.d); }
friend bool operator==(const QPropertyBindingPrivatePtr &p1, const QPropertyBindingPrivatePtr &p2) noexcept
{ return p1.d == p2.d; }

View File

@ -81,7 +81,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QMimeType)
void swap(QMimeType &other) noexcept
{
qSwap(d, other.d);
d.swap(other.d);
}
explicit QMimeType(const QMimeTypePrivate &dd);
~QMimeType();

View File

@ -176,7 +176,7 @@ public:
void swap(QCborArray &other) noexcept
{
qSwap(d, other.d);
d.swap(other.d);
}
QCborValue toCborValue() const { return *this; }

View File

@ -178,7 +178,7 @@ public:
void swap(QCborMap &other) noexcept
{
qSwap(d, other.d);
d.swap(other.d);
}
QCborValue toCborValue() const { return *this; }

View File

@ -187,9 +187,9 @@ public:
void swap(QCborValue &other) noexcept
{
qSwap(n, other.n);
qSwap(container, other.container);
qSwap(t, other.t);
std::swap(n, other.n);
qt_ptr_swap(container, other.container);
std::swap(t, other.t);
}
Type type() const { return t; }

View File

@ -101,7 +101,7 @@ public:
void swap(QJsonArray &other) noexcept
{
qSwap(a, other.a);
a.swap(other.a);
}
class const_iterator;

View File

@ -74,7 +74,7 @@ public:
void swap(QJsonObject &other) noexcept
{
qSwap(o, other.o);
o.swap(other.o);
}
static QJsonObject fromVariantMap(const QVariantMap &map);

View File

@ -58,12 +58,12 @@ public:
QXmlString(QStringPrivate &&d) : m_string(std::move(d)) {}
QXmlString(const QString &s) : m_string(s.data_ptr()) {}
QXmlString & operator=(const QString &s) { m_string = s.data_ptr(); return *this; }
QXmlString & operator=(QString &&s) { qSwap(m_string, s.data_ptr()); return *this; }
QXmlString & operator=(QString &&s) { m_string.swap(s.data_ptr()); return *this; }
inline constexpr QXmlString() {}
void swap(QXmlString &other) noexcept
{
qSwap(m_string, other.m_string);
m_string.swap(other.m_string);
}
inline operator QStringView() const { return QStringView(m_string.data(), m_string.size); }

View File

@ -124,7 +124,7 @@ public:
{ qSwap(d, other.d); }
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QByteArray)
inline void swap(QByteArray &other) noexcept
{ qSwap(d, other.d); }
{ d.swap(other.d); }
bool isEmpty() const noexcept { return size() == 0; }
void resize(qsizetype size);
@ -629,8 +629,8 @@ public:
void swap(QByteArray::FromBase64Result &other) noexcept
{
qSwap(decoded, other.decoded);
qSwap(decodingStatus, other.decodingStatus);
decoded.swap(other.decoded);
std::swap(decodingStatus, other.decodingStatus);
}
explicit operator bool() const noexcept { return decodingStatus == QByteArray::Base64DecodingStatus::Ok; }

View File

@ -87,7 +87,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QCollator)
void swap(QCollator &other) noexcept
{ qSwap(d, other.d); }
{ qt_ptr_swap(d, other.d); }
void setLocale(const QLocale &locale);
QLocale locale() const;

View File

@ -938,7 +938,7 @@ public:
QLocale &operator=(const QLocale &other);
~QLocale();
void swap(QLocale &other) noexcept { qSwap(d, other.d); }
void swap(QLocale &other) noexcept { d.swap(other.d); }
Language language() const;
Script script() const;

View File

@ -423,7 +423,7 @@ public:
inline QString(QString &&other) noexcept
{ qSwap(d, other.d); }
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QString)
inline void swap(QString &other) noexcept { qSwap(d, other.d); }
void swap(QString &other) noexcept { d.swap(other.d); }
inline qsizetype size() const { return d.size; }
inline qsizetype count() const { return d.size; }
inline qsizetype length() const { return d.size; }

View File

@ -72,7 +72,7 @@ public:
QUnhandledException(QUnhandledException &&other) noexcept;
QUnhandledException(const QUnhandledException &other) noexcept;
void swap(QUnhandledException &other) noexcept { qSwap(d, other.d); }
void swap(QUnhandledException &other) noexcept { d.swap(other.d); }
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QUnhandledException)
QUnhandledException &operator=(const QUnhandledException &other) noexcept;

View File

@ -106,7 +106,7 @@ public:
void swap(QPromise<T> &other) noexcept
{
qSwap(this->d, other.d);
d.swap(other.d);
}
#if defined(Q_CLANG_QDOC) // documentation-only simplified signatures

View File

@ -109,8 +109,8 @@ public:
void swap(QSemaphoreReleaser &other) noexcept
{
qSwap(m_sem, other.m_sem);
qSwap(m_n, other.m_n);
qt_ptr_swap(m_sem, other.m_sem);
std::swap(m_n, other.m_n);
}
QSemaphore *semaphore() const noexcept

View File

@ -149,9 +149,9 @@ public:
void swap(QArrayDataPointer &other) noexcept
{
qSwap(d, other.d);
qSwap(ptr, other.ptr);
qSwap(size, other.size);
qt_ptr_swap(d, other.d);
qt_ptr_swap(ptr, other.ptr);
std::swap(size, other.size);
}
void clear() noexcept(std::is_nothrow_destructible<T>::value)

View File

@ -62,7 +62,7 @@ public:
inline QBitArray(QBitArray &&other) noexcept : d(std::move(other.d)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QBitArray)
inline void swap(QBitArray &other) noexcept { qSwap(d, other.d); }
void swap(QBitArray &other) noexcept { d.swap(other.d); }
inline qsizetype size() const { return (d.size() << 3) - *d.constData(); }
inline qsizetype count() const { return (d.size() << 3) - *d.constData(); }

View File

@ -64,8 +64,8 @@ class QCache
}
Value &operator=(Value &&other) noexcept
{
qSwap(t, other.t);
qSwap(cost, other.cost);
qt_ptr_swap(t, other.t);
std::swap(cost, other.cost);
return *this;
}
~Value() { delete t; }

View File

@ -75,7 +75,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QCommandLineOption)
void swap(QCommandLineOption &other) noexcept
{ qSwap(d, other.d); }
{ d.swap(other.d); }
QStringList names() const;

View File

@ -97,7 +97,7 @@ public:
QContiguousCache<T> &operator=(const QContiguousCache<T> &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QContiguousCache)
inline void swap(QContiguousCache<T> &other) noexcept { qSwap(d, other.d); }
void swap(QContiguousCache &other) noexcept { qt_ptr_swap(d, other.d); }
#ifndef Q_CLANG_QDOC
template <typename U = T>

View File

@ -81,7 +81,7 @@ public:
QEasingCurve(QEasingCurve &&other) noexcept : d_ptr(other.d_ptr) { other.d_ptr = nullptr; }
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QEasingCurve)
void swap(QEasingCurve &other) noexcept { qSwap(d_ptr, other.d_ptr); }
void swap(QEasingCurve &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); }
bool operator==(const QEasingCurve &other) const;
inline bool operator!=(const QEasingCurve &other) const

View File

@ -911,7 +911,7 @@ public:
insert(f->first, f->second);
}
#endif
void swap(QHash &other) noexcept { qSwap(d, other.d); }
void swap(QHash &other) noexcept { qt_ptr_swap(d, other.d); }
#ifndef Q_CLANG_QDOC
template <typename AKey = Key, typename AT = T>
@ -1446,7 +1446,12 @@ public:
{
unite(std::move(other));
}
void swap(QMultiHash &other) noexcept { qSwap(d, other.d); qSwap(m_size, other.m_size); }
void swap(QMultiHash &other) noexcept
{
qt_ptr_swap(d, other.d);
std::swap(m_size, other.m_size);
}
#ifndef Q_CLANG_QDOC
template <typename AKey = Key, typename AT = T>

View File

@ -351,7 +351,7 @@ public:
// compiler-generated special member functions are fine!
void swap(QList<T> &other) noexcept { qSwap(d, other.d); }
void swap(QList &other) noexcept { d.swap(other.d); }
#ifndef Q_CLANG_QDOC
template <typename U = T>

View File

@ -238,7 +238,7 @@ public:
void swap(QMap<Key, T> &other) noexcept
{
qSwap(d, other.d);
d.swap(other.d);
}
QMap(std::initializer_list<std::pair<Key, T>> list)
@ -849,7 +849,7 @@ public:
void swap(QMultiMap<Key, T> &other) noexcept
{
qSwap(d, other.d);
d.swap(other.d);
}
explicit QMultiMap(const QMap<Key, T> &other)

View File

@ -173,7 +173,7 @@ public:
QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedPointer.")
void swap(QScopedPointer<T, Cleanup> &other) noexcept
{
qSwap(d, other.d);
qt_ptr_swap(d, other.d);
}
#endif

View File

@ -125,7 +125,7 @@ public:
bool operator!() const noexcept { return d == nullptr; }
void swap(QSharedDataPointer &other) noexcept
{ qSwap(d, other.d); }
{ qt_ptr_swap(d, other.d); }
#define DECLARE_COMPARE_SET(T1, A1, T2, A2) \
friend bool operator<(T1, T2) noexcept \
@ -222,7 +222,7 @@ public:
bool operator!() const noexcept { return d == nullptr; }
void swap(QExplicitlySharedDataPointer &other) noexcept
{ qSwap(d, other.d); }
{ qt_ptr_swap(d, other.d); }
DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const QExplicitlySharedDataPointer &p2, p2.d)
DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const T *ptr, ptr)

View File

@ -138,7 +138,7 @@ public:
constexpr void swap(QExplicitlySharedDataPointerV2 &other) noexcept
{
qSwap(d, other.d);
qt_ptr_swap(d, other.d);
}
// important change from QExplicitlySharedDataPointer: deep const

View File

@ -508,8 +508,8 @@ private:
void internalSwap(QSharedPointer &other) noexcept
{
qSwap(d, other.d);
qSwap(this->value, other.value);
qt_ptr_swap(d, other.d);
qt_ptr_swap(this->value, other.value);
}
template <class X> friend class QSharedPointer;
@ -538,8 +538,8 @@ private:
}
}
qSwap(d, o);
qSwap(this->value, actual);
qt_ptr_swap(d, o);
qt_ptr_swap(this->value, actual);
if (!d || d->strongref.loadRelaxed() == 0)
this->value = nullptr;
@ -609,8 +609,8 @@ public:
void swap(QWeakPointer &other) noexcept
{
qSwap(this->d, other.d);
qSwap(this->value, other.value);
qt_ptr_swap(this->d, other.d);
qt_ptr_swap(this->value, other.value);
}
inline QWeakPointer(const QSharedPointer<T> &o) : d(o.d), value(o.data())

View File

@ -144,7 +144,7 @@ public:
void swap(QTaggedPointer &other) noexcept
{
qSwap(d, other.d);
std::swap(d, other.d);
}
friend inline bool operator==(QTaggedPointer lhs, QTaggedPointer rhs) noexcept

View File

@ -131,7 +131,7 @@ class QVersionNumber
void swap(SegmentStorage &other) noexcept
{
qSwap(dummy, other.dummy);
std::swap(dummy, other.dummy);
}
explicit SegmentStorage(QList<int> &&seg)