diff options
-rw-r--r-- | src/corelib/kernel/qproperty.cpp | 43 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty.h | 6 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty_p.h | 3 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp | 17 |
4 files changed, 57 insertions, 12 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index 3123858d83..942abfe6ba 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -558,9 +558,10 @@ QPropertyObserver::QPropertyObserver(ChangeHandler changeHandler) d.setChangeHandler(changeHandler); } -QPropertyObserver::QPropertyObserver(QUntypedPropertyData *) +QPropertyObserver::QPropertyObserver(QUntypedPropertyData *data) { - // ### Qt 7: Remove, currently left for binary compatibility + aliasData = data; + next.setTag(ObserverIsAlias); } /*! \internal @@ -609,16 +610,38 @@ QPropertyObserver &QPropertyObserver::operator=(QPropertyObserver &&other) noexc return *this; } +#define UNLINK_COMMON \ + if (ptr->next) \ + ptr->next->prev = ptr->prev; \ + if (ptr->prev) \ + ptr->prev.setPointer(ptr->next.data()); \ + ptr->next = nullptr; \ + ptr->prev.clear(); + +/*! + \internal + Unlinks + */ void QPropertyObserverPointer::unlink() { - if (ptr->next) - ptr->next->prev = ptr->prev; - if (ptr->prev) - ptr->prev.setPointer(ptr->next.data()); - ptr->next = nullptr; - ptr->prev.clear(); + UNLINK_COMMON + if (ptr->next.tag() == QPropertyObserver::ObserverIsAlias) + ptr->aliasData = nullptr; } +/*! + \internal + Like unlink, but does not handle ObserverIsAlias. + Must only be called in places where we know that we are not dealing + with such an observer. + */ +void QPropertyObserverPointer::unlink_fast() +{ + Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsAlias); + UNLINK_COMMON +} +#undef UNLINK_COMMON + void QPropertyObserverPointer::setChangeHandler(QPropertyObserver::ChangeHandler changeHandler) { Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsPlaceholder); @@ -666,7 +689,7 @@ struct [[nodiscard]] QPropertyObserverNodeProtector { ~QPropertyObserverNodeProtector() { QPropertyObserverPointer d{static_cast<QPropertyObserver *>(&m_placeHolder)}; - d.unlink(); + d.unlink_fast(); } }; @@ -721,6 +744,8 @@ void QPropertyObserverPointer::notify(QUntypedPropertyData *propertyDataPtr) case QPropertyObserver::ObserverIsPlaceholder: // recursion is already properly handled somewhere else break; + case QPropertyObserver::ObserverIsAlias: + break; default: Q_UNREACHABLE(); } observer = next; diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index 133c7a7e14..356eb43cd3 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -223,7 +223,8 @@ public: enum ObserverTag { ObserverNotifiesBinding, // observer was installed to notify bindings that obsverved property changed ObserverNotifiesChangeHandler, // observer is a change handler, which runs on every change - ObserverIsPlaceholder // the observer before this one is currently evaluated in QPropertyObserver::notifyObservers. + ObserverIsPlaceholder, // the observer before this one is currently evaluated in QPropertyObserver::notifyObservers. + ObserverIsAlias }; protected: using ChangeHandler = void (*)(QPropertyObserver*, QUntypedPropertyData *); @@ -244,6 +245,7 @@ private: union { QPropertyBindingPrivate *binding = nullptr; ChangeHandler changeHandler; + QUntypedPropertyData *aliasData; }; }; @@ -266,7 +268,7 @@ protected: QUntypedPropertyData *aliasedProperty() const { - return nullptr; + return aliasData; } private: diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index e77bc4d834..55f0dc032c 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -103,6 +103,7 @@ struct QPropertyObserverPointer QPropertyObserver *ptr = nullptr; void unlink(); + void unlink_fast(); void setBindingToNotify(QPropertyBindingPrivate *binding); void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding); @@ -289,7 +290,7 @@ public: void clearDependencyObservers() { for (size_t i = 0; i < qMin(dependencyObserverCount, inlineDependencyObservers.size()); ++i) { QPropertyObserverPointer p{&inlineDependencyObservers[i]}; - p.unlink(); + p.unlink_fast(); } if (heapObservers) heapObservers->clear(); diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp index 214512f20d..3cfdcfc7b0 100644 --- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp +++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp @@ -115,6 +115,8 @@ private slots: void bindableInterfaceOfCompatPropertyUsesSetter(); void selfBindingShouldNotCrash(); + + void qpropertyAlias(); }; void tst_QProperty::functorBinding() @@ -1856,6 +1858,21 @@ void tst_QProperty::selfBindingShouldNotCrash() QVERIFY(i.binding().error().hasError()); } +void tst_QProperty::qpropertyAlias() +{ + std::unique_ptr<QProperty<int>> i {new QProperty<int>}; + QPropertyAlias<int> alias(i.get()); + QVERIFY(alias.isValid()); + alias.setValue(42); + QCOMPARE(i->value(), 42); + QProperty<int> j; + i->setBinding([&]() -> int { return j; }); + j.setValue(42); + QCOMPARE(alias.value(), 42); + i.reset(); + QVERIFY(!alias.isValid()); +} + QTEST_MAIN(tst_QProperty); #undef QT_SOURCE_LOCATION_NAMESPACE |