summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qproperty_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qproperty_p.h')
-rw-r--r--src/corelib/kernel/qproperty_p.h113
1 files changed, 99 insertions, 14 deletions
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index a569c172c5..8e747b4f64 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -21,6 +21,7 @@
#include <qscopedpointer.h>
#include <qscopedvaluerollback.h>
#include <vector>
+#include <QtCore/QVarLengthArray>
QT_BEGIN_NAMESPACE
@@ -29,6 +30,34 @@ namespace QtPrivate {
struct QBindingStatusAccessToken {};
}
+
+/*!
+ \internal
+ Similar to \c QPropertyBindingPrivatePtr, but stores a
+ \c QPropertyObserver * linking to the QPropertyBindingPrivate*
+ instead of the QPropertyBindingPrivate* itself
+ */
+struct QBindingObserverPtr
+{
+private:
+ QPropertyObserver *d = nullptr;
+public:
+ QBindingObserverPtr() = default;
+ Q_DISABLE_COPY(QBindingObserverPtr);
+ void swap(QBindingObserverPtr &other) noexcept
+ { qt_ptr_swap(d, other.d); }
+ QBindingObserverPtr(QBindingObserverPtr &&other) : d(std::exchange(other.d, nullptr)) {}
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QBindingObserverPtr);
+
+
+ inline QBindingObserverPtr(QPropertyObserver *observer);
+ inline ~QBindingObserverPtr();
+ inline QPropertyBindingPrivate *binding() const;
+ inline QPropertyObserver *operator ->();
+};
+
+using PendingBindingObserverList = QVarLengthArray<QBindingObserverPtr>;
+
// 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.
@@ -52,6 +81,7 @@ struct QPropertyBindingDataPointer
void Q_ALWAYS_INLINE addObserver(QPropertyObserver *observer);
inline void setFirstObserver(QPropertyObserver *observer);
inline QPropertyObserverPointer firstObserver() const;
+ static QPropertyProxyBindingData *proxyData(QtPrivate::QPropertyBindingData *ptr);
inline int observerCount() const;
@@ -106,19 +136,29 @@ struct QPropertyObserverPointer
void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
+ enum class Notify {Everything, OnlyChangeHandlers};
+
+ template<Notify notifyPolicy = Notify::Everything>
void notify(QUntypedPropertyData *propertyDataPtr);
+ void notifyOnlyChangeHandler(QUntypedPropertyData *propertyDataPtr);
#ifndef QT_NO_DEBUG
void noSelfDependencies(QPropertyBindingPrivate *binding);
#else
void noSelfDependencies(QPropertyBindingPrivate *) {}
#endif
- void evaluateBindings(QBindingStatus *status);
+ void evaluateBindings(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
void observeProperty(QPropertyBindingDataPointer property);
explicit operator bool() const { return ptr != nullptr; }
QPropertyObserverPointer nextObserver() const { return {ptr->next.data()}; }
+ QPropertyBindingPrivate *binding() const
+ {
+ Q_ASSERT(ptr->next.tag() == QPropertyObserver::ObserverNotifiesBinding);
+ return ptr->binding;
+ };
+
private:
void unlink_common()
{
@@ -321,10 +361,21 @@ public:
void unlinkAndDeref();
- void evaluateRecursive(QBindingStatus *status = nullptr);
- void Q_ALWAYS_INLINE evaluateRecursive_inline(QBindingStatus *status);
+ void evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status = nullptr);
+
+ // ### TODO: remove as soon as declarative no longer needs this overload
+ void evaluateRecursive()
+ {
+ PendingBindingObserverList bindingObservers;
+ evaluateRecursive(bindingObservers);
+ }
+
+ void Q_ALWAYS_INLINE evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
void notifyRecursive();
+ void notifyNonRecursive(const PendingBindingObserverList &bindingObservers);
+ enum NotificationState : bool { Delayed, Sent };
+ NotificationState notifyNonRecursive();
static QPropertyBindingPrivate *get(const QUntypedPropertyBinding &binding)
{ return static_cast<QPropertyBindingPrivate *>(binding.d.data()); }
@@ -373,9 +424,9 @@ inline void QPropertyBindingDataPointer::fixupAfterMove(QtPrivate::QPropertyBind
{
auto &d = ptr->d_ref();
if (ptr->isNotificationDelayed()) {
- QPropertyProxyBindingData *proxyData
- = reinterpret_cast<QPropertyProxyBindingData*>(d & ~QtPrivate::QPropertyBindingData::BindingBit);
- proxyData->originalBindingData = ptr;
+ QPropertyProxyBindingData *proxy = ptr->proxyData();
+ Q_ASSERT(proxy);
+ proxy->originalBindingData = ptr;
}
// If QPropertyBindingData has been moved, and it has an observer
// we have to adjust the firstObserver's prev pointer to point to
@@ -393,6 +444,17 @@ inline QPropertyObserverPointer QPropertyBindingDataPointer::firstObserver() con
return { reinterpret_cast<QPropertyObserver *>(ptr->d()) };
}
+/*!
+ \internal
+ Returns the proxy data of \a ptr, or \c nullptr if \a ptr has no delayed notification
+ */
+inline QPropertyProxyBindingData *QPropertyBindingDataPointer::proxyData(QtPrivate::QPropertyBindingData *ptr)
+{
+ if (!ptr->isNotificationDelayed())
+ return nullptr;
+ return ptr->proxyData();
+}
+
inline int QPropertyBindingDataPointer::observerCount() const
{
int count = 0;
@@ -566,11 +628,14 @@ public:
QPropertyBindingDataPointer d{bd};
if (QPropertyObserverPointer observer = d.firstObserver()) {
if (!inBindingWrapper(storage)) {
- if (bd->notifyObserver_helper(this, observer, storage)
+ PendingBindingObserverList bindingObservers;
+ if (bd->notifyObserver_helper(this, storage, observer, bindingObservers)
== QtPrivate::QPropertyBindingData::Evaluated) {
// evaluateBindings() can trash the observers. We need to re-fetch here.
if (QPropertyObserverPointer observer = d.firstObserver())
- observer.notify(this);
+ observer.notifyOnlyChangeHandler(this);
+ for (auto&& bindingObserver: bindingObservers)
+ bindingObserver.binding()->notifyNonRecursive();
}
}
}
@@ -727,7 +792,7 @@ struct QUntypedBindablePrivate
}
};
-inline void QPropertyBindingPrivate::evaluateRecursive_inline(QBindingStatus *status)
+inline void QPropertyBindingPrivate::evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
{
if (updating) {
error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
@@ -766,9 +831,10 @@ inline void QPropertyBindingPrivate::evaluateRecursive_inline(QBindingStatus *st
return;
firstObserver.noSelfDependencies(this);
- firstObserver.evaluateBindings(status);
+ firstObserver.evaluateBindings(bindingObservers, status);
}
+template<QPropertyObserverPointer::Notify notifyPolicy>
inline void QPropertyObserverPointer::notify(QUntypedPropertyData *propertyDataPtr)
{
auto observer = const_cast<QPropertyObserver*>(ptr);
@@ -808,10 +874,12 @@ inline void QPropertyObserverPointer::notify(QUntypedPropertyData *propertyDataP
}
case QPropertyObserver::ObserverNotifiesBinding:
{
- auto bindingToNotify = observer->binding;
- QPropertyObserverNodeProtector protector(observer);
- bindingToNotify->notifyRecursive();
- next = protector.next();
+ if constexpr (notifyPolicy == Notify::Everything) {
+ auto bindingToNotify = observer->binding;
+ QPropertyObserverNodeProtector protector(observer);
+ bindingToNotify->notifyRecursive();
+ next = protector.next();
+ }
break;
}
case QPropertyObserver::ObserverIsPlaceholder:
@@ -825,12 +893,29 @@ inline void QPropertyObserverPointer::notify(QUntypedPropertyData *propertyDataP
}
}
+inline void QPropertyObserverPointer::notifyOnlyChangeHandler(QUntypedPropertyData *propertyDataPtr)
+{
+ notify<Notify::OnlyChangeHandlers>(propertyDataPtr);
+}
+
inline QPropertyObserverNodeProtector::~QPropertyObserverNodeProtector()
{
QPropertyObserverPointer d{static_cast<QPropertyObserver *>(&m_placeHolder)};
d.unlink_fast();
}
+QBindingObserverPtr::QBindingObserverPtr(QPropertyObserver *observer) : d(observer)
+{
+ Q_ASSERT(d);
+ QPropertyObserverPointer{d}.binding()->addRef();
+}
+
+QBindingObserverPtr::~QBindingObserverPtr() { if (d) QPropertyObserverPointer{d}.binding()->deref(); }
+
+QPropertyBindingPrivate *QBindingObserverPtr::binding() const { return QPropertyObserverPointer{d}.binding(); }
+
+QPropertyObserver *QBindingObserverPtr::operator->() { return d; }
+
QT_END_NAMESPACE
#endif // QPROPERTY_P_H