diff options
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r-- | src/corelib/kernel/kernel.pri | 4 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty.cpp | 208 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty_p.h | 165 | ||||
-rw-r--r-- | src/corelib/kernel/qpropertybinding.cpp | 192 | ||||
-rw-r--r-- | src/corelib/kernel/qpropertybinding_p.h | 194 | ||||
-rw-r--r-- | src/corelib/kernel/qpropertyprivate.h | 2 |
6 files changed, 325 insertions, 440 deletions
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index fc48ef430e..a493260c50 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -46,8 +46,7 @@ HEADERS += \ kernel/qtestsupport_core.h \ kernel/qproperty.h \ kernel/qpropertyprivate.h \ - kernel/qproperty_p.h \ - kernel/qpropertybinding_p.h + kernel/qproperty_p.h SOURCES += \ kernel/qabstracteventdispatcher.cpp \ @@ -77,7 +76,6 @@ SOURCES += \ kernel/qsystemerror.cpp \ kernel/qtestsupport_core.cpp \ kernel/qproperty.cpp \ - kernel/qpropertybinding.cpp win32 { SOURCES += \ diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index 9374ce3a74..3bac73909a 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -39,7 +39,6 @@ #include "qproperty.h" #include "qproperty_p.h" -#include "qpropertybinding_p.h" #include <qscopedvaluerollback.h> @@ -47,6 +46,166 @@ QT_BEGIN_NAMESPACE using namespace QtPrivate; +void QPropertyBasePointer::addObserver(QPropertyObserver *observer) +{ + if (auto *binding = bindingPtr()) { + observer->prev = &binding->firstObserver.ptr; + observer->next = binding->firstObserver.ptr; + if (observer->next) + observer->next->prev = &observer->next; + binding->firstObserver.ptr = observer; + } else { + auto firstObserver = reinterpret_cast<QPropertyObserver*>(ptr->d_ptr & ~QPropertyBase::FlagMask); + observer->prev = reinterpret_cast<QPropertyObserver**>(&ptr->d_ptr); + observer->next = firstObserver; + if (observer->next) + observer->next->prev = &observer->next; + } + setFirstObserver(observer); +} + +QPropertyBindingPrivate::~QPropertyBindingPrivate() +{ + if (firstObserver) + firstObserver.unlink(); + if (!hasStaticObserver) + inlineDependencyObservers.~ObserverArray(); // Explicit because of union. +} + +void QPropertyBindingPrivate::unlinkAndDeref() +{ + propertyDataPtr = nullptr; + if (!ref.deref()) + delete this; +} + +void QPropertyBindingPrivate::markDirtyAndNotifyObservers() +{ + if (dirty) + return; + dirty = true; + if (firstObserver) + firstObserver.notify(this, propertyDataPtr); + if (hasStaticObserver) { + if (isBool) { + auto propertyPtr = reinterpret_cast<QPropertyBase *>(propertyDataPtr); + bool oldValue = propertyPtr->extraBit(); + staticObserverCallback(staticObserver, &oldValue); + } else { + staticObserverCallback(staticObserver, propertyDataPtr); + } + } +} + +bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged() +{ + if (!dirty) + return false; + + if (updating) { + error = QPropertyBindingError(QPropertyBindingError::BindingLoop); + return false; + } + + /* + * 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}; + QScopedValueRollback<bool> updateGuard(updating, true); + + BindingEvaluationState evaluationFrame(this); + + bool changed = false; + + if (hasStaticObserver && staticGuardCallback) { + if (isBool) { + auto propertyPtr = reinterpret_cast<QPropertyBase *>(propertyDataPtr); + bool newValue = propertyPtr->extraBit(); + changed = staticGuardCallback(metaType, &newValue, evaluationFunction, staticObserver); + if (changed && !error.hasError()) + propertyPtr->setExtraBit(newValue); + } else { + changed = staticGuardCallback(metaType, propertyDataPtr, evaluationFunction, staticObserver); + } + } else { + if (isBool) { + auto propertyPtr = reinterpret_cast<QPropertyBase *>(propertyDataPtr); + bool newValue = propertyPtr->extraBit(); + changed = evaluationFunction(metaType, &newValue); + if (changed && !error.hasError()) + propertyPtr->setExtraBit(newValue); + } else { + changed = evaluationFunction(metaType, propertyDataPtr); + } + } + + dirty = false; + return changed; +} + +QUntypedPropertyBinding::QUntypedPropertyBinding() = default; + +QUntypedPropertyBinding::QUntypedPropertyBinding(const QMetaType &metaType, QUntypedPropertyBinding::BindingEvaluationFunction function, + const QPropertyBindingSourceLocation &location) +{ + d = new QPropertyBindingPrivate(metaType, std::move(function), std::move(location)); +} + +QUntypedPropertyBinding::QUntypedPropertyBinding(QUntypedPropertyBinding &&other) + : d(std::move(other.d)) +{ +} + +QUntypedPropertyBinding::QUntypedPropertyBinding(const QUntypedPropertyBinding &other) + : d(other.d) +{ +} + +QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(const QUntypedPropertyBinding &other) +{ + d = other.d; + return *this; +} + +QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(QUntypedPropertyBinding &&other) +{ + d = std::move(other.d); + return *this; +} + +QUntypedPropertyBinding::QUntypedPropertyBinding(QPropertyBindingPrivate *priv) + : d(priv) +{ +} + +QUntypedPropertyBinding::~QUntypedPropertyBinding() +{ +} + +bool QUntypedPropertyBinding::isNull() const +{ + return !d; +} + +QPropertyBindingError QUntypedPropertyBinding::error() const +{ + if (!d) + return QPropertyBindingError(); + return d->bindingError(); +} + +QMetaType QUntypedPropertyBinding::valueMetaType() const +{ + if (!d) + return QMetaType(); + return d->valueMetaType(); +} + QPropertyBase::QPropertyBase(QPropertyBase &&other, void *propertyDataPtr) { std::swap(d_ptr, other.d_ptr); @@ -141,53 +300,6 @@ QPropertyBindingPrivate *QPropertyBase::binding() return nullptr; } -QPropertyBindingPrivate *QPropertyBasePointer::bindingPtr() const -{ - if (ptr->d_ptr & QPropertyBase::BindingBit) - return reinterpret_cast<QPropertyBindingPrivate*>(ptr->d_ptr & ~QPropertyBase::FlagMask); - return nullptr; -} - -void QPropertyBasePointer::setObservers(QPropertyObserver *observer) -{ - observer->prev = reinterpret_cast<QPropertyObserver**>(&(ptr->d_ptr)); - ptr->d_ptr = (reinterpret_cast<quintptr>(observer) & ~QPropertyBase::FlagMask); -} - -void QPropertyBasePointer::addObserver(QPropertyObserver *observer) -{ - if (auto *binding = bindingPtr()) { - observer->prev = &binding->firstObserver.ptr; - observer->next = binding->firstObserver.ptr; - if (observer->next) - observer->next->prev = &observer->next; - binding->firstObserver.ptr = observer; - } else { - auto firstObserver = reinterpret_cast<QPropertyObserver*>(ptr->d_ptr & ~QPropertyBase::FlagMask); - observer->prev = reinterpret_cast<QPropertyObserver**>(&ptr->d_ptr); - observer->next = firstObserver; - if (observer->next) - observer->next->prev = &observer->next; - } - setFirstObserver(observer); -} - -void QPropertyBasePointer::setFirstObserver(QPropertyObserver *observer) -{ - if (auto *binding = bindingPtr()) { - binding->firstObserver.ptr = observer; - return; - } - ptr->d_ptr = reinterpret_cast<quintptr>(observer) | (ptr->d_ptr & QPropertyBase::FlagMask); -} - -QPropertyObserverPointer QPropertyBasePointer::firstObserver() const -{ - if (auto *binding = bindingPtr()) - return binding->firstObserver; - return {reinterpret_cast<QPropertyObserver*>(ptr->d_ptr & ~QPropertyBase::FlagMask)}; -} - static thread_local BindingEvaluationState *currentBindingEvaluationState = nullptr; BindingEvaluationState::BindingEvaluationState(QPropertyBindingPrivate *binding) diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index 7b9d7c207f..159c652657 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -52,20 +52,35 @@ // #include <qglobal.h> +#include <qproperty.h> + #include <qvarlengtharray.h> +#include <qscopedpointer.h> +#include <vector> -#include "qproperty.h" QT_BEGIN_NAMESPACE +// 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. + // This is a helper "namespace" struct Q_AUTOTEST_EXPORT QPropertyBasePointer { const QtPrivate::QPropertyBase *ptr = nullptr; - QPropertyBindingPrivate *bindingPtr() const; + QPropertyBindingPrivate *bindingPtr() const + { + if (ptr->d_ptr & QtPrivate::QPropertyBase::BindingBit) + return reinterpret_cast<QPropertyBindingPrivate*>(ptr->d_ptr & ~QtPrivate::QPropertyBase::FlagMask); + return nullptr; + } - void setObservers(QPropertyObserver *observer); + void setObservers(QPropertyObserver *observer) + { + observer->prev = reinterpret_cast<QPropertyObserver**>(&(ptr->d_ptr)); + ptr->d_ptr = (reinterpret_cast<quintptr>(observer) & ~QtPrivate::QPropertyBase::FlagMask); + } void addObserver(QPropertyObserver *observer); void setFirstObserver(QPropertyObserver *observer); QPropertyObserverPointer firstObserver() const; @@ -114,6 +129,150 @@ struct BindingEvaluationState BindingEvaluationState **currentState = nullptr; }; +class Q_CORE_EXPORT QPropertyBindingPrivate : public QSharedData +{ +private: + friend struct QPropertyBasePointer; + + using ObserverArray = std::array<QPropertyObserver, 4>; + + // QSharedData is 4 bytes. Use the padding for the bools as we need 8 byte alignment below. + bool dirty = false; + bool updating = false; + bool hasStaticObserver = false; + bool isBool = false; + + QUntypedPropertyBinding::BindingEvaluationFunction evaluationFunction; + + QPropertyObserverPointer firstObserver; + union { + ObserverArray inlineDependencyObservers; + struct { + void *staticObserver; + QtPrivate::QPropertyObserverCallback staticObserverCallback; + QtPrivate::QPropertyGuardFunction staticGuardCallback; + }; + }; + QScopedPointer<std::vector<QPropertyObserver>> heapObservers; + + void *propertyDataPtr = nullptr; + + QPropertyBindingSourceLocation location; + QPropertyBindingError error; + + QMetaType metaType; + +public: + // public because the auto-tests access it, too. + size_t dependencyObserverCount = 0; + + QPropertyBindingPrivate(const QMetaType &metaType, QUntypedPropertyBinding::BindingEvaluationFunction evaluationFunction, + const QPropertyBindingSourceLocation &location) + : isBool(metaType.id() == QMetaType::Bool) + , evaluationFunction(std::move(evaluationFunction)) + , inlineDependencyObservers() // Explicit initialization required because of union + , location(location) + , metaType(metaType) + {} + virtual ~QPropertyBindingPrivate(); + + void setDirty(bool d) { dirty = d; } + void setProperty(void *propertyPtr) { propertyDataPtr = propertyPtr; } + void setStaticObserver(void *observer, QtPrivate::QPropertyObserverCallback callback, + QtPrivate::QPropertyGuardFunction guardCallback) + { + if (observer) { + if (!hasStaticObserver) { + if (dependencyObserverCount > 0) { + if (!heapObservers) + heapObservers.reset(new std::vector<QPropertyObserver>()); + for (size_t i = 0, end = qMin(dependencyObserverCount, inlineDependencyObservers.size()); i < end; ++i) + heapObservers->push_back(std::move(inlineDependencyObservers[i])); + } + inlineDependencyObservers.~ObserverArray(); + } + + hasStaticObserver = true; + staticObserver = observer; + staticObserverCallback = callback; + staticGuardCallback = guardCallback; + } else if (hasStaticObserver) { + hasStaticObserver = false; + new (&inlineDependencyObservers) ObserverArray(); + for (size_t i = 0, end = qMin(dependencyObserverCount, inlineDependencyObservers.size()); i < end; ++i) { + inlineDependencyObservers[i] = std::move(heapObservers->back()); + heapObservers->pop_back(); + } + } + } + void prependObserver(QPropertyObserverPointer observer) { + observer.ptr->prev = const_cast<QPropertyObserver **>(&firstObserver.ptr); + firstObserver = observer; + } + + QPropertyObserverPointer takeObservers() + { + auto observers = firstObserver; + firstObserver.ptr = nullptr; + return observers; + } + + void clearDependencyObservers() { + if (!hasStaticObserver) { + for (size_t i = 0; i < qMin(dependencyObserverCount, inlineDependencyObservers.size()); ++i) { + QPropertyObserverPointer p{&inlineDependencyObservers[i]}; + p.unlink(); + } + } + if (heapObservers) + heapObservers->clear(); + dependencyObserverCount = 0; + } + QPropertyObserverPointer allocateDependencyObserver() { + if (!hasStaticObserver && dependencyObserverCount < inlineDependencyObservers.size()) { + ++dependencyObserverCount; + return {&inlineDependencyObservers[dependencyObserverCount - 1]}; + } + ++dependencyObserverCount; + if (!heapObservers) + heapObservers.reset(new std::vector<QPropertyObserver>()); + return {&heapObservers->emplace_back()}; + } + + QPropertyBindingSourceLocation sourceLocation() const { return location; } + QPropertyBindingError bindingError() const { return error; } + QMetaType valueMetaType() const { return metaType; } + + void unlinkAndDeref(); + + void markDirtyAndNotifyObservers(); + bool evaluateIfDirtyAndReturnTrueIfValueChanged(); + + static QPropertyBindingPrivate *get(const QUntypedPropertyBinding &binding) + { return binding.d.data(); } + + void setError(QPropertyBindingError &&e) + { error = std::move(e); } + + static QPropertyBindingPrivate *currentlyEvaluatingBinding(); +}; + +inline void QPropertyBasePointer::setFirstObserver(QPropertyObserver *observer) +{ + if (auto *binding = bindingPtr()) { + binding->firstObserver.ptr = observer; + return; + } + ptr->d_ptr = reinterpret_cast<quintptr>(observer) | (ptr->d_ptr & QtPrivate::QPropertyBase::FlagMask); +} + +inline QPropertyObserverPointer QPropertyBasePointer::firstObserver() const +{ + if (auto *binding = bindingPtr()) + return binding->firstObserver; + return {reinterpret_cast<QPropertyObserver*>(ptr->d_ptr & ~QtPrivate::QPropertyBase::FlagMask)}; +} + QT_END_NAMESPACE #endif // QPROPERTY_P_H diff --git a/src/corelib/kernel/qpropertybinding.cpp b/src/corelib/kernel/qpropertybinding.cpp deleted file mode 100644 index 63800c4f7d..0000000000 --- a/src/corelib/kernel/qpropertybinding.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpropertybinding_p.h" -#include "qproperty_p.h" - -#include <QScopedValueRollback> -#include <QVariant> - -QT_BEGIN_NAMESPACE - -using namespace QtPrivate; - -QPropertyBindingPrivate::~QPropertyBindingPrivate() -{ - if (firstObserver) - firstObserver.unlink(); - if (!hasStaticObserver) - inlineDependencyObservers.~ObserverArray(); // Explicit because of union. -} - -void QPropertyBindingPrivate::unlinkAndDeref() -{ - propertyDataPtr = nullptr; - if (!ref.deref()) - delete this; -} - -void QPropertyBindingPrivate::markDirtyAndNotifyObservers() -{ - if (dirty) - return; - dirty = true; - if (firstObserver) - firstObserver.notify(this, propertyDataPtr); - if (hasStaticObserver) { - if (isBool) { - auto propertyPtr = reinterpret_cast<QPropertyBase *>(propertyDataPtr); - bool oldValue = propertyPtr->extraBit(); - staticObserverCallback(staticObserver, &oldValue); - } else { - staticObserverCallback(staticObserver, propertyDataPtr); - } - } -} - -bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged() -{ - if (!dirty) - return false; - - if (updating) { - error = QPropertyBindingError(QPropertyBindingError::BindingLoop); - return false; - } - - /* - * 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}; - QScopedValueRollback<bool> updateGuard(updating, true); - - BindingEvaluationState evaluationFrame(this); - - bool changed = false; - - if (hasStaticObserver && staticGuardCallback) { - if (isBool) { - auto propertyPtr = reinterpret_cast<QPropertyBase *>(propertyDataPtr); - bool newValue = propertyPtr->extraBit(); - changed = staticGuardCallback(metaType, &newValue, evaluationFunction, staticObserver); - if (changed && !error.hasError()) - propertyPtr->setExtraBit(newValue); - } else { - changed = staticGuardCallback(metaType, propertyDataPtr, evaluationFunction, staticObserver); - } - } else { - if (isBool) { - auto propertyPtr = reinterpret_cast<QPropertyBase *>(propertyDataPtr); - bool newValue = propertyPtr->extraBit(); - changed = evaluationFunction(metaType, &newValue); - if (changed && !error.hasError()) - propertyPtr->setExtraBit(newValue); - } else { - changed = evaluationFunction(metaType, propertyDataPtr); - } - } - - dirty = false; - return changed; -} - -QUntypedPropertyBinding::QUntypedPropertyBinding() = default; - -QUntypedPropertyBinding::QUntypedPropertyBinding(const QMetaType &metaType, QUntypedPropertyBinding::BindingEvaluationFunction function, - const QPropertyBindingSourceLocation &location) -{ - d = new QPropertyBindingPrivate(metaType, std::move(function), std::move(location)); -} - -QUntypedPropertyBinding::QUntypedPropertyBinding(QUntypedPropertyBinding &&other) - : d(std::move(other.d)) -{ -} - -QUntypedPropertyBinding::QUntypedPropertyBinding(const QUntypedPropertyBinding &other) - : d(other.d) -{ -} - -QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(const QUntypedPropertyBinding &other) -{ - d = other.d; - return *this; -} - -QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(QUntypedPropertyBinding &&other) -{ - d = std::move(other.d); - return *this; -} - -QUntypedPropertyBinding::QUntypedPropertyBinding(QPropertyBindingPrivate *priv) - : d(priv) -{ -} - -QUntypedPropertyBinding::~QUntypedPropertyBinding() -{ -} - -bool QUntypedPropertyBinding::isNull() const -{ - return !d; -} - -QPropertyBindingError QUntypedPropertyBinding::error() const -{ - if (!d) - return QPropertyBindingError(); - return d->bindingError(); -} - -QMetaType QUntypedPropertyBinding::valueMetaType() const -{ - if (!d) - return QMetaType(); - return d->valueMetaType(); -} - -QT_END_NAMESPACE diff --git a/src/corelib/kernel/qpropertybinding_p.h b/src/corelib/kernel/qpropertybinding_p.h deleted file mode 100644 index 1aa2cd864c..0000000000 --- a/src/corelib/kernel/qpropertybinding_p.h +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPROPERTYBINDING_P_H -#define QPROPERTYBINDING_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header -// file may change from version to version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qglobal.h> -#include <QtCore/qshareddata.h> -#include <QtCore/qscopedpointer.h> -#include <vector> -#include <functional> - -#include "qproperty_p.h" - -QT_BEGIN_NAMESPACE - -class Q_CORE_EXPORT QPropertyBindingPrivate : public QSharedData -{ -private: - friend struct QPropertyBasePointer; - - using ObserverArray = std::array<QPropertyObserver, 4>; - - // QSharedData is 4 bytes. Use the padding for the bools as we need 8 byte alignment below. - bool dirty = false; - bool updating = false; - bool hasStaticObserver = false; - bool isBool = false; - - QUntypedPropertyBinding::BindingEvaluationFunction evaluationFunction; - - QPropertyObserverPointer firstObserver; - union { - ObserverArray inlineDependencyObservers; - struct { - void *staticObserver; - QtPrivate::QPropertyObserverCallback staticObserverCallback; - QtPrivate::QPropertyGuardFunction staticGuardCallback; - }; - }; - QScopedPointer<std::vector<QPropertyObserver>> heapObservers; - - void *propertyDataPtr = nullptr; - - QPropertyBindingSourceLocation location; - QPropertyBindingError error; - - QMetaType metaType; - -public: - // public because the auto-tests access it, too. - size_t dependencyObserverCount = 0; - - QPropertyBindingPrivate(const QMetaType &metaType, QUntypedPropertyBinding::BindingEvaluationFunction evaluationFunction, - const QPropertyBindingSourceLocation &location) - : isBool(metaType.id() == QMetaType::Bool) - , evaluationFunction(std::move(evaluationFunction)) - , inlineDependencyObservers() // Explicit initialization required because of union - , location(location) - , metaType(metaType) - {} - virtual ~QPropertyBindingPrivate(); - - void setDirty(bool d) { dirty = d; } - void setProperty(void *propertyPtr) { propertyDataPtr = propertyPtr; } - void setStaticObserver(void *observer, QtPrivate::QPropertyObserverCallback callback, - QtPrivate::QPropertyGuardFunction guardCallback) - { - if (observer) { - if (!hasStaticObserver) { - if (dependencyObserverCount > 0) { - if (!heapObservers) - heapObservers.reset(new std::vector<QPropertyObserver>()); - for (int i = 0, end = qMin(dependencyObserverCount, inlineDependencyObservers.size()); i < end; ++i) - heapObservers->push_back(std::move(inlineDependencyObservers[i])); - } - inlineDependencyObservers.~ObserverArray(); - } - - hasStaticObserver = true; - staticObserver = observer; - staticObserverCallback = callback; - staticGuardCallback = guardCallback; - } else if (hasStaticObserver) { - hasStaticObserver = false; - new (&inlineDependencyObservers) ObserverArray(); - for (int i = 0, end = qMin(dependencyObserverCount, inlineDependencyObservers.size()); i < end; ++i) { - inlineDependencyObservers[i] = std::move(heapObservers->back()); - heapObservers->pop_back(); - } - } - } - void prependObserver(QPropertyObserverPointer observer) { - observer.ptr->prev = const_cast<QPropertyObserver **>(&firstObserver.ptr); - firstObserver = observer; - } - - QPropertyObserverPointer takeObservers() - { - auto observers = firstObserver; - firstObserver.ptr = nullptr; - return observers; - } - - void clearDependencyObservers() { - if (!hasStaticObserver) { - for (size_t i = 0; i < qMin(dependencyObserverCount, inlineDependencyObservers.size()); ++i) { - QPropertyObserverPointer p{&inlineDependencyObservers[i]}; - p.unlink(); - } - } - if (heapObservers) - heapObservers->clear(); - dependencyObserverCount = 0; - } - QPropertyObserverPointer allocateDependencyObserver() { - if (!hasStaticObserver && dependencyObserverCount < inlineDependencyObservers.size()) { - ++dependencyObserverCount; - return {&inlineDependencyObservers[dependencyObserverCount - 1]}; - } - ++dependencyObserverCount; - if (!heapObservers) - heapObservers.reset(new std::vector<QPropertyObserver>()); - return {&heapObservers->emplace_back()}; - } - - QPropertyBindingSourceLocation sourceLocation() const { return location; } - QPropertyBindingError bindingError() const { return error; } - QMetaType valueMetaType() const { return metaType; } - - void unlinkAndDeref(); - - void markDirtyAndNotifyObservers(); - bool evaluateIfDirtyAndReturnTrueIfValueChanged(); - - static QPropertyBindingPrivate *get(const QUntypedPropertyBinding &binding) - { return binding.d.data(); } - - void setError(QPropertyBindingError &&e) - { error = std::move(e); } - - static QPropertyBindingPrivate *currentlyEvaluatingBinding(); -}; - -QT_END_NAMESPACE - -#endif // QPROPERTYBINDING_P_H diff --git a/src/corelib/kernel/qpropertyprivate.h b/src/corelib/kernel/qpropertyprivate.h index 91d9204996..ad5ed59e88 100644 --- a/src/corelib/kernel/qpropertyprivate.h +++ b/src/corelib/kernel/qpropertyprivate.h @@ -55,6 +55,8 @@ #include <QtCore/QExplicitlySharedDataPointer> #include <QtCore/qtaggedpointer.h> +#include <functional> + QT_BEGIN_NAMESPACE class QUntypedPropertyBinding; |