QProperty: Add private isAnyBindingEvaluating function

To optimize certain operations, it can be useful to know whether we are
currently evaluating a binding. For instance, we have properties whose
storage is only alloctaed on-demand when they are set. However, we would
also allocate them if they are used in a binding context, as we would
otherwise not properly track the dependency. Using
isAnyBindingEvaluating in the getter, we can detect this
situation, and avoid the allocation if it returns false.

This API is private for now, as it exposes some internals of the
property system and should be used with care. As it needs to access the
TLS variable, it also has a non-negligible cost.

Change-Id: I373aabee644fe7020b2ffba7d6a0ad9a1e1b4ec0
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Fabian Kosmale 2021-01-20 10:26:24 +01:00
parent 150660887f
commit 3861ec735e
3 changed files with 28 additions and 0 deletions

View File

@ -1667,4 +1667,19 @@ void restoreBindingStatus(BindingEvaluationState *status)
bindingStatus.currentlyEvaluatingBinding = status;
}
namespace QtPrivate {
/*!
\internal
This function can be used to detect whether we are currently
evaluating a binding. This can e.g. be used to defer the allocation
of extra data for a QPropertyBindingStorage in a getter.
Note that this function accesses TLS storage, and is therefore soemwhat
costly to call.
*/
bool isAnyBindingEvaluating()
{
return bindingStatus.currentlyEvaluatingBinding != nullptr;
}
} // namespace QtPrivate end
QT_END_NAMESPACE

View File

@ -59,6 +59,10 @@
QT_BEGIN_NAMESPACE
namespace QtPrivate {
Q_CORE_EXPORT bool isAnyBindingEvaluating();
}
// Keep all classes related to QProperty in one compilation unit. Performance of this code is crucial and
// we need to allow the compiler to inline where it makes sense.

View File

@ -1140,6 +1140,15 @@ void tst_QProperty::testNewStuff()
QCOMPARE(object.bindableFoo().value(), 111);
object.bindableFoo().setValue(24);
QCOMPARE(object.foo(), 24);
auto isCurrentlyEvaluatingBinding = []() {
return QtPrivate::isAnyBindingEvaluating();
};
QVERIFY(!isCurrentlyEvaluatingBinding());
QProperty<bool> evaluationDetector {false};
evaluationDetector.setBinding(isCurrentlyEvaluatingBinding);
QVERIFY(evaluationDetector.value());
QVERIFY(!isCurrentlyEvaluatingBinding());
}
void tst_QProperty::qobjectObservers()