From c61d9873e5e30723bc5558b509b3320f2abf1da7 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 26 Jun 2019 23:35:12 +0200 Subject: [PATCH] QPrivateSlotBase: add empty base class optimization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are few slots whose lambdas are empty; most will at least capture [this]. But there are a few in Qt examples that do, e.g. []{ qApp->quit(); }. Logging is also an example. So go the extra mile and optimize for empty functors by inheriting from them as opposed to storing them in a member variable. Change-Id: I3904f10db5ebe904ba889d29c08569edd804df3b Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Fabian Kosmale Reviewed-by: Lars Knoll Reviewed-by: Qt CI Bot Reviewed-by: Thiago Macieira --- src/corelib/kernel/qobject_p.h | 35 ++++++++++++++++--- .../corelib/kernel/qobject/tst_qobject.cpp | 2 +- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 539818ac1d..c119fdfe7e 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -467,10 +467,35 @@ inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) } namespace QtPrivate { -template class QPrivateSlotObject : public QSlotObjectBase + +template +struct FunctionStorageByValue +{ + Func f; + Func &func() noexcept { return f; } +}; + +template +struct FunctionStorageEmptyBaseClassOptimization : Func +{ + Func &func() noexcept { return *this; } + using Func::Func; +}; + +template +using FunctionStorage = typename std::conditional_t< + std::conjunction_v< + std::is_empty, + std::negation> + >, + FunctionStorageEmptyBaseClassOptimization, + FunctionStorageByValue + >; + +template +class QPrivateSlotObject : public QSlotObjectBase, private FunctionStorage { typedef QtPrivate::FunctionPointer FuncType; - Func function; static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) { switch (which) { @@ -478,17 +503,17 @@ template class QPrivateSlotObject : pu delete static_cast(this_); break; case Call: - FuncType::template call(static_cast(this_)->function, + FuncType::template call(static_cast(this_)->func(), static_cast(QObjectPrivate::get(r)), a); break; case Compare: - *ret = *reinterpret_cast(a) == static_cast(this_)->function; + *ret = *reinterpret_cast(a) == static_cast(this_)->func(); break; case NumOperations: ; } } public: - explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} + explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), FunctionStorage{std::move(f)} {} }; } //namespace QtPrivate diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 3d52478299..599f690ab2 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -5221,7 +5221,7 @@ namespace ManyArgumentNamespace { } }; - struct Funct6 { + struct Funct6 final { void operator()(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f);