From bbfecdee1e2952c401e9c5ac6e16adc2428fb2dc Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 8 Jul 2020 12:07:13 +0200 Subject: Significantly improve performance of binding evaluation Avoid any QVariant or type dependent code in the cpp files. Instead, let the binding wrapper determine if the value has changed and return true/false accordingly. This required also some reworking of the guard mechanism for notified properties, where the guard function wrapper now calls first the binding evaluation function and then passes the result to the guard. Change-Id: I350d07a508ccc0c5db7054a0efa4f270b6a78ec3 Reviewed-by: Fabian Kosmale --- src/corelib/kernel/qpropertyprivate.h | 44 +++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'src/corelib/kernel/qpropertyprivate.h') diff --git a/src/corelib/kernel/qpropertyprivate.h b/src/corelib/kernel/qpropertyprivate.h index 145f2c66b9..91d9204996 100644 --- a/src/corelib/kernel/qpropertyprivate.h +++ b/src/corelib/kernel/qpropertyprivate.h @@ -61,9 +61,17 @@ class QUntypedPropertyBinding; class QPropertyBindingPrivate; using QPropertyBindingPrivatePtr = QExplicitlySharedDataPointer; struct QPropertyBasePointer; +class QMetaType; namespace QtPrivate { +// writes binding result into dataPtr +using QPropertyBindingFunction = std::function; + +using QPropertyGuardFunction = bool(*)(const QMetaType &, void *dataPtr, + QPropertyBindingFunction, void *owner); +using QPropertyObserverCallback = void (*)(void *, void *); + class Q_CORE_EXPORT QPropertyBase { // Mutable because the address of the observer of the currently evaluating binding is stored here, for @@ -84,8 +92,8 @@ public: QUntypedPropertyBinding setBinding(const QUntypedPropertyBinding &newBinding, void *propertyDataPtr, void *staticObserver = nullptr, - void (*staticObserverCallback)(void *, void *) = nullptr, - bool (*guardCallback)(void *, void *) = nullptr); + QPropertyObserverCallback staticObserverCallback = nullptr, + QPropertyGuardFunction guardCallback = nullptr); QPropertyBindingPrivate *binding(); void evaluateIfDirty(); @@ -211,6 +219,38 @@ private: quintptr *d = nullptr; }; +namespace detail { + template + struct ExtractClassFromFunctionPointer; + + template + struct ExtractClassFromFunctionPointer { using Class = C; }; +} + +// type erased guard functions, casts its arguments to the correct types +template> +struct QPropertyGuardFunctionHelper +{ + static constexpr QPropertyGuardFunction guard = nullptr; +}; +template +struct QPropertyGuardFunctionHelper +{ + static auto guard(const QMetaType &metaType, void *dataPtr, + QPropertyBindingFunction eval, void *owner) -> bool + { + T t; + eval(metaType, &t); + if (!(static_cast(owner)->*Guard)(t)) + return false; + T *data = static_cast(dataPtr); + if (*data == t) + return false; + *data = std::move(t); + return true; + }; +}; + } // namespace QtPrivate QT_END_NAMESPACE -- cgit v1.2.3