diff options
author | Lars Knoll <lars.knoll@qt.io> | 2020-08-14 09:48:56 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2020-09-02 22:44:27 +0200 |
commit | e3ea8768fc3bfed088f70b5d7308e3dd94e93c32 (patch) | |
tree | f0d7d1effb8479b5b6e5b47e1dd73108773549e0 /src/corelib/kernel/qproperty.h | |
parent | e6988d4d0bef2c3f474576250cb305a2f00a688b (diff) |
Introduce a common base class for all QProperty types
Add an empty QUntypedPropertyData class. This allows making
a couple of places where the system is currently using a
void * more type safe.
Also add a QPropertyData<T> as an intermediate class between
QUntypedPropertyData and QProperty. This class will get used
in a future commit to simplify storing property data separately
from the possible binding data.
Also simplify the static observer handling a bit by always
passing it a pointer to the QUntypedPropertyData instead of
some other void * that could point to anything.
Change-Id: I1f8144ea717815b1bc6f034d1ac883c13af5aaf8
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/corelib/kernel/qproperty.h')
-rw-r--r-- | src/corelib/kernel/qproperty.h | 91 |
1 files changed, 56 insertions, 35 deletions
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index ff2a5c883f..7b63a46665 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -63,6 +63,32 @@ QT_BEGIN_NAMESPACE +template <typename T> +class QPropertyData : public QUntypedPropertyData +{ +protected: + T val = T(); +private: + class DisableRValueRefs {}; +protected: + static constexpr bool UseReferences = !(std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_pointer_v<T>); +public: + using value_type = T; + using parameter_type = std::conditional_t<UseReferences, const T &, T>; + using rvalue_ref = typename std::conditional_t<UseReferences, T &&, DisableRValueRefs>; + using arrow_operator_result = std::conditional_t<std::is_pointer_v<T>, const T &, + std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, const T &, void>>; + + QPropertyData() = default; + QPropertyData(parameter_type t) : val(t) {} + QPropertyData(rvalue_ref t) : val(std::move(t)) {} + ~QPropertyData() = default; + + parameter_type valueBypassingBindings() const { return val; } + void setValueBypassingBindings(parameter_type v) { val = v; } + void setValueBypassingBindings(rvalue_ref v) { val = std::move(v); } +}; + struct Q_CORE_EXPORT QPropertyBindingSourceLocation { const char *fileName = nullptr; @@ -146,15 +172,15 @@ class QPropertyBinding : public QUntypedPropertyBinding struct BindingAdaptor { Functor impl; - bool operator()(QMetaType /*metaType*/, void *dataPtr) + bool operator()(QMetaType /*metaType*/, QUntypedPropertyData *dataPtr) { - PropertyType *propertyPtr = static_cast<PropertyType *>(dataPtr); + QPropertyData<PropertyType> *propertyPtr = static_cast<QPropertyData<PropertyType> *>(dataPtr); PropertyType newValue = impl(); if constexpr (QTypeTraits::has_operator_equal_v<PropertyType>) { - if (newValue == *propertyPtr) + if (newValue == propertyPtr->valueBypassingBindings()) return false; } - *propertyPtr = std::move(newValue); + propertyPtr->setValueBypassingBindings(std::move(newValue)); return true; } }; @@ -167,7 +193,7 @@ public: : QUntypedPropertyBinding(QMetaType::fromType<PropertyType>(), BindingAdaptor<Functor>{std::forward<Functor>(f)}, location) {} - template<typename Property, typename = std::void_t<decltype(&Property::bindingData)>> + template<typename Property, typename = typename Property::InheritsQUntypedPropertyData> QPropertyBinding(const Property &property) : QUntypedPropertyBinding(property.bindingData().binding()) {} @@ -187,36 +213,30 @@ namespace Qt { } } -struct QPropertyBindingDataPointer; - template <typename T> -class QProperty +class QProperty : public QPropertyData<T> { - T val = T(); QtPrivate::QPropertyBindingData d; bool is_equal(const T &v) { if constexpr (QTypeTraits::has_operator_equal_v<T>) { - if (v == val) + if (v == this->val) return true; } return false; } - class DisableRValueRefs {}; - static constexpr bool UseReferences = !(std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_pointer_v<T>); public: - using value_type = T; - using parameter_type = std::conditional_t<UseReferences, const T &, T>; - using rvalue_ref = typename std::conditional_t<UseReferences, T &&, DisableRValueRefs>; - using arrow_operator_result = std::conditional_t<std::is_pointer_v<T>, const T &, - std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, const T &, void>>; + using value_type = typename QPropertyData<T>::value_type; + using parameter_type = typename QPropertyData<T>::parameter_type; + using rvalue_ref = typename QPropertyData<T>::rvalue_ref; + using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result; QProperty() = default; - explicit QProperty(const T &initialValue) : val(initialValue) {} - explicit QProperty(T &&initialValue) : val(std::move(initialValue)) {} - QProperty(QProperty &&other) : val(std::move(other.val)), d(std::move(other.d), &val) { notify(); } - QProperty &operator=(QProperty &&other) { val = std::move(other.val); d.moveAssign(std::move(other.d), &val); notify(); return *this; } + explicit QProperty(parameter_type initialValue) : QPropertyData<T>(initialValue) {} + explicit QProperty(rvalue_ref initialValue) : QPropertyData<T>(std::move(initialValue)) {} + QProperty(QProperty &&other) : QPropertyData<T>(std::move(other.val)), d(std::move(other.d), this) { notify(); } + QProperty &operator=(QProperty &&other) { this->val = std::move(other.val); d.moveAssign(std::move(other.d), this); notify(); return *this; } QProperty(const QPropertyBinding<T> &binding) : QProperty() { operator=(binding); } @@ -240,7 +260,7 @@ public: if (d.hasBinding()) d.evaluateIfDirty(); d.registerWithCurrentlyEvaluatingBinding(); - return val; + return this->val; } arrow_operator_result operator->() const @@ -270,7 +290,7 @@ public: d.removeBinding(); if (is_equal(newValue)) return; - val = std::move(newValue); + this->val = std::move(newValue); notify(); } @@ -279,7 +299,7 @@ public: d.removeBinding(); if (is_equal(newValue)) return; - val = newValue; + this->val = newValue; notify(); } @@ -303,7 +323,7 @@ public: QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding) { - QPropertyBinding<T> oldBinding(d.setBinding(newBinding, &val)); + QPropertyBinding<T> oldBinding(d.setBinding(newBinding, this)); notify(); return oldBinding; } @@ -338,7 +358,7 @@ public: QPropertyBinding<T> takeBinding() { - return QPropertyBinding<T>(d.setBinding(QUntypedPropertyBinding(), &d)); + return QPropertyBinding<T>(d.setBinding(QUntypedPropertyBinding(), this)); } template<typename Functor> @@ -350,7 +370,7 @@ public: private: void notify() { - d.notifyObservers(&d); + d.notifyObservers(this); } Q_DISABLE_COPY(QProperty) @@ -389,13 +409,14 @@ public: { setSource(property.bindingData()); } protected: - QPropertyObserver(void (*callback)(QPropertyObserver*, void *)); - QPropertyObserver(void *aliasedPropertyPtr); + using ChangeHandler = void (*)(QPropertyObserver*, QUntypedPropertyData *); + QPropertyObserver(ChangeHandler changeHandler); + QPropertyObserver(QUntypedPropertyData *aliasedPropertyPtr); template<typename PropertyType> QProperty<PropertyType> *aliasedProperty() const { - return reinterpret_cast<QProperty<PropertyType> *>(aliasedPropertyPtr); + return static_cast<QProperty<PropertyType> *>(aliasedPropertyData); } private: @@ -408,8 +429,8 @@ private: union { QPropertyBindingPrivate *bindingToMarkDirty = nullptr; - void (*changeHandler)(QPropertyObserver*, void *); - quintptr aliasedPropertyPtr; + ChangeHandler changeHandler; + QUntypedPropertyData *aliasedPropertyData; }; QPropertyObserver(const QPropertyObserver &) = delete; @@ -426,7 +447,7 @@ class QPropertyChangeHandler : public QPropertyObserver Functor m_handler; public: QPropertyChangeHandler(Functor handler) - : QPropertyObserver([](QPropertyObserver *self, void *) { + : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) { auto This = static_cast<QPropertyChangeHandler<Functor>*>(self); This->m_handler(); }) @@ -434,9 +455,9 @@ public: { } - template<typename Property, typename = std::void_t<decltype(&Property::bindingData)>> + template<typename Property, typename = typename Property::InheritsQUntypedPropertyData> QPropertyChangeHandler(const Property &property, Functor handler) - : QPropertyObserver([](QPropertyObserver *self, void *) { + : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) { auto This = static_cast<QPropertyChangeHandler<Functor>*>(self); This->m_handler(); }) |