QProperty: more micro optimization
- Provide an inline version of evaluateRecursive which does not fetch the status. - Provide an unsafe variant of setBindingToNotify which does not set the tag. This can be used in allocateDependencyObserver, as newly allocated observers already have the correct tag (this is checked via an assert). Pick-to: 6.2 Change-Id: I31aec6af4aef244efc6d0777e5bfaaa8f82f2046 Reviewed-by: Lars Knoll <lars.knoll@qt.io>bb10
parent
77d528f8d3
commit
f7eed15588
|
|
@ -285,44 +285,7 @@ void QPropertyBindingPrivate::unlinkAndDeref()
|
|||
|
||||
void QPropertyBindingPrivate::evaluateRecursive(QBindingStatus *status)
|
||||
{
|
||||
if (updating) {
|
||||
error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
|
||||
if (isQQmlPropertyBinding)
|
||||
errorCallBack(this);
|
||||
return;
|
||||
}
|
||||
|
||||
QScopedValueRollback<bool> updateGuard(updating, true);
|
||||
|
||||
/*
|
||||
* Evaluating the binding might lead to the binding being broken. This can
|
||||
* cause ref to reach zero at the end of the function. However, the
|
||||
* updateGuard's destructor will then still trigger, trying to set the
|
||||
* updating bool to its old value
|
||||
* To prevent this, we create a QPropertyBindingPrivatePtr which ensures
|
||||
* that the object is still alive when updateGuard's dtor runs.
|
||||
*/
|
||||
QPropertyBindingPrivatePtr keepAlive {this};
|
||||
|
||||
BindingEvaluationState evaluationFrame(this, status);
|
||||
|
||||
auto bindingFunctor = reinterpret_cast<std::byte *>(this) +
|
||||
QPropertyBindingPrivate::getSizeEnsuringAlignment();
|
||||
bool changed = false;
|
||||
if (hasBindingWrapper) {
|
||||
changed = staticBindingWrapper(metaType, propertyDataPtr,
|
||||
{vtable, bindingFunctor});
|
||||
} else {
|
||||
changed = vtable->call(metaType, propertyDataPtr, bindingFunctor);
|
||||
}
|
||||
// If there was a change, we must set pendingNotify.
|
||||
// If there was not, we must not clear it, as that only should happen in notifyRecursive
|
||||
pendingNotify = pendingNotify || changed;
|
||||
if (!changed || !firstObserver)
|
||||
return;
|
||||
|
||||
firstObserver.noSelfDependencies(this);
|
||||
firstObserver.evaluateBindings(status);
|
||||
return evaluateRecursive_inline(status);
|
||||
}
|
||||
|
||||
void QPropertyBindingPrivate::notifyRecursive()
|
||||
|
|
@ -539,7 +502,8 @@ void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding_helper(Binding
|
|||
QPropertyBindingDataPointer d{this};
|
||||
|
||||
QPropertyObserverPointer dependencyObserver = currentState->binding->allocateDependencyObserver();
|
||||
dependencyObserver.setBindingToNotify(currentState->binding);
|
||||
Q_ASSERT(QPropertyObserver::ObserverNotifiesBinding == 0);
|
||||
dependencyObserver.setBindingToNotify_unsafe(currentState->binding);
|
||||
d.addObserver(dependencyObserver.ptr);
|
||||
}
|
||||
|
||||
|
|
@ -663,6 +627,16 @@ void QPropertyObserverPointer::setBindingToNotify(QPropertyBindingPrivate *bindi
|
|||
ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
The same as as setBindingToNotify, but assumes that the tag is already correct.
|
||||
*/
|
||||
void QPropertyObserverPointer::setBindingToNotify_unsafe(QPropertyBindingPrivate *binding)
|
||||
{
|
||||
Q_ASSERT(ptr->next.tag() == QPropertyObserver::ObserverNotifiesBinding);
|
||||
ptr->binding = binding;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
QPropertyObserverNodeProtector is a RAII wrapper which takes care of the internal switching logic
|
||||
|
|
@ -775,7 +749,7 @@ void QPropertyObserverPointer::evaluateBindings(QBindingStatus *status)
|
|||
if (QPropertyObserver::ObserverTag(observer->next.tag()) == QPropertyObserver::ObserverNotifiesBinding) {
|
||||
auto bindingToEvaluate = observer->binding;
|
||||
QPropertyObserverNodeProtector protector(observer);
|
||||
bindingToEvaluate->evaluateRecursive(status);
|
||||
bindingToEvaluate->evaluateRecursive_inline(status);
|
||||
next = protector.next();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
#include <qproperty.h>
|
||||
|
||||
#include <qscopedpointer.h>
|
||||
#include <qscopedvaluerollback.h>
|
||||
#include <vector>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
@ -104,6 +105,7 @@ struct QPropertyObserverPointer
|
|||
void unlink();
|
||||
|
||||
void setBindingToNotify(QPropertyBindingPrivate *binding);
|
||||
void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
|
||||
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
|
||||
|
||||
void notify(QUntypedPropertyData *propertyDataPtr);
|
||||
|
|
@ -325,6 +327,8 @@ public:
|
|||
void unlinkAndDeref();
|
||||
|
||||
void evaluateRecursive(QBindingStatus *status = nullptr);
|
||||
void Q_ALWAYS_INLINE evaluateRecursive_inline(QBindingStatus *status = nullptr);
|
||||
|
||||
void notifyRecursive();
|
||||
|
||||
static QPropertyBindingPrivate *get(const QUntypedPropertyBinding &binding)
|
||||
|
|
@ -693,6 +697,48 @@ struct QUntypedBindablePrivate
|
|||
}
|
||||
};
|
||||
|
||||
inline void QPropertyBindingPrivate::evaluateRecursive_inline(QBindingStatus *status)
|
||||
{
|
||||
if (updating) {
|
||||
error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
|
||||
if (isQQmlPropertyBinding)
|
||||
errorCallBack(this);
|
||||
return;
|
||||
}
|
||||
|
||||
QScopedValueRollback<bool> updateGuard(updating, true);
|
||||
|
||||
/*
|
||||
* Evaluating the binding might lead to the binding being broken. This can
|
||||
* cause ref to reach zero at the end of the function. However, the
|
||||
* updateGuard's destructor will then still trigger, trying to set the
|
||||
* updating bool to its old value
|
||||
* To prevent this, we create a QPropertyBindingPrivatePtr which ensures
|
||||
* that the object is still alive when updateGuard's dtor runs.
|
||||
*/
|
||||
QPropertyBindingPrivatePtr keepAlive {this};
|
||||
|
||||
QtPrivate::BindingEvaluationState evaluationFrame(this, status);
|
||||
|
||||
auto bindingFunctor = reinterpret_cast<std::byte *>(this) +
|
||||
QPropertyBindingPrivate::getSizeEnsuringAlignment();
|
||||
bool changed = false;
|
||||
if (hasBindingWrapper) {
|
||||
changed = staticBindingWrapper(metaType, propertyDataPtr,
|
||||
{vtable, bindingFunctor});
|
||||
} else {
|
||||
changed = vtable->call(metaType, propertyDataPtr, bindingFunctor);
|
||||
}
|
||||
// If there was a change, we must set pendingNotify.
|
||||
// If there was not, we must not clear it, as that only should happen in notifyRecursive
|
||||
pendingNotify = pendingNotify || changed;
|
||||
if (!changed || !firstObserver)
|
||||
return;
|
||||
|
||||
firstObserver.noSelfDependencies(this);
|
||||
firstObserver.evaluateBindings(status);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QPROPERTY_P_H
|
||||
|
|
|
|||
Loading…
Reference in New Issue