Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-15 08:27:15

0001 // Copyright (C) 2020 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QPROPERTY_H
0005 #define QPROPERTY_H
0006 
0007 #include <QtCore/qglobal.h>
0008 #include <QtCore/qshareddata.h>
0009 #include <QtCore/qstring.h>
0010 #include <QtCore/qttypetraits.h>
0011 #include <QtCore/qbindingstorage.h>
0012 
0013 #include <type_traits>
0014 
0015 #include <QtCore/qpropertyprivate.h>
0016 
0017 #if __has_include(<source_location>) && __cplusplus >= 202002L && !defined(Q_QDOC)
0018 #include <source_location>
0019 #if defined(__cpp_lib_source_location)
0020 #define QT_SOURCE_LOCATION_NAMESPACE std
0021 #define QT_PROPERTY_COLLECT_BINDING_LOCATION
0022 #if defined(Q_CC_MSVC)
0023 /* MSVC runs into an issue with constexpr with source location (error C7595)
0024    so use the factory function as a workaround */
0025 #  define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation::fromStdSourceLocation(std::source_location::current())
0026 #else
0027 /* some versions of gcc in turn run into
0028    expression ‘std::source_location::current()’ is not a constant expression
0029    so don't use the workaround there */
0030 #  define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::source_location::current())
0031 #endif
0032 #endif
0033 #endif
0034 
0035 #if __has_include(<experimental/source_location>) && !defined(Q_QDOC)
0036 #include <experimental/source_location>
0037 #if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION)
0038 #if defined(__cpp_lib_experimental_source_location)
0039 #define QT_SOURCE_LOCATION_NAMESPACE std::experimental
0040 #define QT_PROPERTY_COLLECT_BINDING_LOCATION
0041 #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::experimental::source_location::current())
0042 #endif // defined(__cpp_lib_experimental_source_location)
0043 #endif
0044 #endif
0045 
0046 #if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION)
0047 #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation()
0048 #endif
0049 
0050 QT_BEGIN_NAMESPACE
0051 
0052 namespace Qt {
0053 Q_CORE_EXPORT void beginPropertyUpdateGroup();
0054 Q_CORE_EXPORT void endPropertyUpdateGroup();
0055 }
0056 
0057 class QScopedPropertyUpdateGroup
0058 {
0059     Q_DISABLE_COPY_MOVE(QScopedPropertyUpdateGroup)
0060 public:
0061     Q_NODISCARD_CTOR
0062     QScopedPropertyUpdateGroup()
0063     { Qt::beginPropertyUpdateGroup(); }
0064     ~QScopedPropertyUpdateGroup() noexcept(false)
0065     { Qt::endPropertyUpdateGroup(); }
0066 };
0067 
0068 template <typename T>
0069 class QPropertyData : public QUntypedPropertyData
0070 {
0071 protected:
0072     mutable T val = T();
0073 private:
0074     class DisableRValueRefs {};
0075 protected:
0076     static constexpr bool UseReferences = !(std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_pointer_v<T>);
0077 public:
0078     using value_type = T;
0079     using parameter_type = std::conditional_t<UseReferences, const T &, T>;
0080     using rvalue_ref = typename std::conditional_t<UseReferences, T &&, DisableRValueRefs>;
0081     using arrow_operator_result = std::conditional_t<std::is_pointer_v<T>, const T &,
0082                                         std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, const T &, void>>;
0083 
0084     QPropertyData() = default;
0085     QPropertyData(parameter_type t) : val(t) {}
0086     QPropertyData(rvalue_ref t) : val(std::move(t)) {}
0087     ~QPropertyData() = default;
0088 
0089     parameter_type valueBypassingBindings() const { return val; }
0090     void setValueBypassingBindings(parameter_type v) { val = v; }
0091     void setValueBypassingBindings(rvalue_ref v) { val = std::move(v); }
0092 };
0093 
0094 // ### Qt 7: un-export
0095 struct Q_CORE_EXPORT QPropertyBindingSourceLocation
0096 {
0097     const char *fileName = nullptr;
0098     const char *functionName = nullptr;
0099     quint32 line = 0;
0100     quint32 column = 0;
0101     QPropertyBindingSourceLocation() = default;
0102 #ifdef __cpp_lib_source_location
0103     constexpr QPropertyBindingSourceLocation(const std::source_location &cppLocation)
0104     {
0105         fileName = cppLocation.file_name();
0106         functionName = cppLocation.function_name();
0107         line = cppLocation.line();
0108         column = cppLocation.column();
0109     }
0110     QT_POST_CXX17_API_IN_EXPORTED_CLASS
0111     static consteval QPropertyBindingSourceLocation
0112     fromStdSourceLocation(const std::source_location &cppLocation)
0113     {
0114         return cppLocation;
0115     }
0116 #endif
0117 #ifdef __cpp_lib_experimental_source_location
0118     constexpr QPropertyBindingSourceLocation(const std::experimental::source_location &cppLocation)
0119     {
0120         fileName = cppLocation.file_name();
0121         functionName = cppLocation.function_name();
0122         line = cppLocation.line();
0123         column = cppLocation.column();
0124     }
0125 #endif
0126 };
0127 
0128 template <typename Functor> class QPropertyChangeHandler;
0129 class QPropertyBindingErrorPrivate;
0130 
0131 class Q_CORE_EXPORT QPropertyBindingError
0132 {
0133 public:
0134     enum Type {
0135         NoError,
0136         BindingLoop,
0137         EvaluationError,
0138         UnknownError
0139     };
0140 
0141     QPropertyBindingError();
0142     QPropertyBindingError(Type type, const QString &description = QString());
0143 
0144     QPropertyBindingError(const QPropertyBindingError &other);
0145     QPropertyBindingError &operator=(const QPropertyBindingError &other);
0146     QPropertyBindingError(QPropertyBindingError &&other);
0147     QPropertyBindingError &operator=(QPropertyBindingError &&other);
0148     ~QPropertyBindingError();
0149 
0150     bool hasError() const { return d.get() != nullptr; }
0151     Type type() const;
0152     QString description() const;
0153 
0154 private:
0155     QSharedDataPointer<QPropertyBindingErrorPrivate> d;
0156 };
0157 
0158 class Q_CORE_EXPORT QUntypedPropertyBinding
0159 {
0160 public:
0161     // writes binding result into dataPtr
0162     using BindingFunctionVTable = QtPrivate::BindingFunctionVTable;
0163 
0164     QUntypedPropertyBinding();
0165     QUntypedPropertyBinding(QMetaType metaType, const BindingFunctionVTable *vtable, void *function, const QPropertyBindingSourceLocation &location);
0166 
0167     template<typename Functor>
0168     QUntypedPropertyBinding(QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location)
0169         : QUntypedPropertyBinding(metaType, &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>>, &f, location)
0170     {}
0171 
0172     QUntypedPropertyBinding(QUntypedPropertyBinding &&other);
0173     QUntypedPropertyBinding(const QUntypedPropertyBinding &other);
0174     QUntypedPropertyBinding &operator=(const QUntypedPropertyBinding &other);
0175     QUntypedPropertyBinding &operator=(QUntypedPropertyBinding &&other);
0176     ~QUntypedPropertyBinding();
0177 
0178     bool isNull() const;
0179 
0180     QPropertyBindingError error() const;
0181 
0182     QMetaType valueMetaType() const;
0183 
0184     explicit QUntypedPropertyBinding(QPropertyBindingPrivate *priv);
0185 private:
0186     friend class QtPrivate::QPropertyBindingData;
0187     friend class QPropertyBindingPrivate;
0188     template <typename> friend class QPropertyBinding;
0189     QPropertyBindingPrivatePtr d;
0190 };
0191 
0192 template <typename PropertyType>
0193 class QPropertyBinding : public QUntypedPropertyBinding
0194 {
0195 
0196 public:
0197     QPropertyBinding() = default;
0198 
0199     template<typename Functor>
0200     QPropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location)
0201         : QUntypedPropertyBinding(QMetaType::fromType<PropertyType>(), &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>, PropertyType>, &f, location)
0202     {}
0203 
0204 
0205     // Internal
0206     explicit QPropertyBinding(const QUntypedPropertyBinding &binding)
0207         : QUntypedPropertyBinding(binding)
0208     {}
0209 };
0210 
0211 namespace Qt {
0212     template <typename Functor>
0213     auto makePropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0214                              std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0215     {
0216         return QPropertyBinding<std::invoke_result_t<Functor>>(std::forward<Functor>(f), location);
0217     }
0218 }
0219 
0220 struct QPropertyObserverPrivate;
0221 struct QPropertyObserverPointer;
0222 class QPropertyObserver;
0223 
0224 class QPropertyObserverBase
0225 {
0226 public:
0227     // Internal
0228     enum ObserverTag {
0229         ObserverNotifiesBinding, // observer was installed to notify bindings that obsverved property changed
0230         ObserverNotifiesChangeHandler, // observer is a change handler, which runs on every change
0231         ObserverIsPlaceholder,  // the observer before this one is currently evaluated in QPropertyObserver::notifyObservers.
0232 #if QT_DEPRECATED_SINCE(6, 6)
0233         ObserverIsAlias QT_DEPRECATED_VERSION_X_6_6("Use QProperty and add a binding to the target.")
0234 #endif
0235     };
0236 protected:
0237     using ChangeHandler = void (*)(QPropertyObserver*, QUntypedPropertyData *);
0238 
0239 private:
0240     friend struct QPropertyDelayedNotifications;
0241     friend struct QPropertyObserverNodeProtector;
0242     friend class QPropertyObserver;
0243     friend struct QPropertyObserverPointer;
0244     friend struct QPropertyBindingDataPointer;
0245     friend class QPropertyBindingPrivate;
0246 
0247     QTaggedPointer<QPropertyObserver, ObserverTag> next;
0248     // prev is a pointer to the "next" element within the previous node, or to the "firstObserverPtr" if it is the
0249     // first node.
0250     QtPrivate::QTagPreservingPointerToPointer<QPropertyObserver, ObserverTag> prev;
0251 
0252     union {
0253         QPropertyBindingPrivate *binding = nullptr;
0254         ChangeHandler changeHandler;
0255         QUntypedPropertyData *aliasData;
0256     };
0257 };
0258 
0259 class Q_CORE_EXPORT QPropertyObserver : public QPropertyObserverBase
0260 {
0261 public:
0262     constexpr QPropertyObserver() = default;
0263     QPropertyObserver(QPropertyObserver &&other) noexcept;
0264     QPropertyObserver &operator=(QPropertyObserver &&other) noexcept;
0265     ~QPropertyObserver();
0266 
0267     template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
0268     void setSource(const Property &property)
0269     { setSource(property.bindingData()); }
0270     void setSource(const QtPrivate::QPropertyBindingData &property);
0271 
0272 protected:
0273     QPropertyObserver(ChangeHandler changeHandler);
0274 #if QT_DEPRECATED_SINCE(6, 6)
0275     QT_DEPRECATED_VERSION_X_6_6("This constructor was only meant for internal use. Use QProperty and add a binding to the target.")
0276     QPropertyObserver(QUntypedPropertyData *aliasedPropertyPtr);
0277 #endif
0278 
0279     QUntypedPropertyData *aliasedProperty() const
0280     {
0281         return aliasData;
0282     }
0283 
0284 private:
0285 
0286     QPropertyObserver(const QPropertyObserver &) = delete;
0287     QPropertyObserver &operator=(const QPropertyObserver &) = delete;
0288 
0289 };
0290 
0291 template <typename Functor>
0292 class QPropertyChangeHandler : public QPropertyObserver
0293 {
0294     Functor m_handler;
0295 public:
0296     Q_NODISCARD_CTOR
0297     QPropertyChangeHandler(Functor handler)
0298         : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
0299               auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
0300               This->m_handler();
0301           })
0302         , m_handler(std::move(handler))
0303     {
0304     }
0305 
0306     template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
0307     Q_NODISCARD_CTOR
0308     QPropertyChangeHandler(const Property &property, Functor handler)
0309         : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
0310               auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
0311               This->m_handler();
0312           })
0313         , m_handler(std::move(handler))
0314     {
0315         setSource(property);
0316     }
0317 };
0318 
0319 class QPropertyNotifier : public QPropertyObserver
0320 {
0321     std::function<void()> m_handler;
0322 public:
0323     Q_NODISCARD_CTOR
0324     QPropertyNotifier() = default;
0325     template<typename Functor>
0326     Q_NODISCARD_CTOR
0327     QPropertyNotifier(Functor handler)
0328         : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
0329             auto This = static_cast<QPropertyNotifier *>(self);
0330             This->m_handler();
0331         })
0332         , m_handler(std::move(handler))
0333     {
0334     }
0335 
0336     template <typename Functor, typename Property,
0337               QtPrivate::IsUntypedPropertyData<Property> = true>
0338     Q_NODISCARD_CTOR
0339     QPropertyNotifier(const Property &property, Functor handler)
0340         : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
0341             auto This = static_cast<QPropertyNotifier *>(self);
0342             This->m_handler();
0343         })
0344         , m_handler(std::move(handler))
0345     {
0346         setSource(property);
0347     }
0348 };
0349 
0350 template <typename T>
0351 class QProperty : public QPropertyData<T>
0352 {
0353     QtPrivate::QPropertyBindingData d;
0354     bool is_equal(const T &v)
0355     {
0356         if constexpr (QTypeTraits::has_operator_equal_v<T>) {
0357             if (v == this->val)
0358                 return true;
0359         }
0360         return false;
0361     }
0362 
0363     template <typename U, typename = void>
0364     struct has_operator_equal_to : std::false_type{};
0365 
0366     template <typename U>
0367     struct has_operator_equal_to<U, std::void_t<decltype(bool(std::declval<const T&>() == std::declval<const U&>()))>>
0368         : std::true_type{};
0369 
0370     template <typename U>
0371     static constexpr bool has_operator_equal_to_v =
0372             !std::is_same_v<U, T> && has_operator_equal_to<U>::value;
0373 
0374 public:
0375     using value_type = typename QPropertyData<T>::value_type;
0376     using parameter_type = typename QPropertyData<T>::parameter_type;
0377     using rvalue_ref = typename QPropertyData<T>::rvalue_ref;
0378     using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;
0379 
0380     QProperty() = default;
0381     explicit QProperty(parameter_type initialValue) : QPropertyData<T>(initialValue) {}
0382     explicit QProperty(rvalue_ref initialValue) : QPropertyData<T>(std::move(initialValue)) {}
0383     explicit QProperty(const QPropertyBinding<T> &binding)
0384         : QProperty()
0385     { setBinding(binding); }
0386 #ifndef Q_QDOC
0387     template <typename Functor>
0388     explicit QProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0389                        typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr)
0390         : QProperty(QPropertyBinding<T>(std::forward<Functor>(f), location))
0391     {}
0392 #else
0393     template <typename Functor>
0394     explicit QProperty(Functor &&f);
0395 #endif
0396     ~QProperty() = default;
0397 
0398     QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, QProperty, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
0399     QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, T, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
0400     QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QProperty, T, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
0401 
0402     QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, U, /* non-constexpr */, noexcept(false), template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>)
0403     QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QProperty, U, /* non-constexpr */, noexcept(false), template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>)
0404 
0405     // Explicitly delete op==(QProperty<T>, QProperty<U>) for different T & U.
0406     // We do not want implicit conversions here!
0407     // However, GCC complains about using a default template argument in a
0408     // friend declaration, while Clang and MSVC are fine. So, skip GCC here.
0409 #if !defined(Q_CC_GNU) || defined(Q_CC_CLANG)
0410 #define QPROPERTY_DECL_DELETED_EQ_OP \
0411     Q_DECL_EQ_DELETE_X("Call .value() on one of the properties explicitly.")
0412     template <typename U, std::enable_if_t<!std::is_same_v<T, U>>* = nullptr>
0413     friend void operator==(const QProperty &, const QProperty<U> &) QPROPERTY_DECL_DELETED_EQ_OP;
0414     template <typename U, std::enable_if_t<!std::is_same_v<T, U>>* = nullptr>
0415     friend void operator!=(const QProperty &, const QProperty<U> &) QPROPERTY_DECL_DELETED_EQ_OP;
0416 #undef QPROPERTY_DECL_DELETED_EQ_OP
0417 #endif // !defined(Q_CC_GNU) || defined(Q_CC_CLANG)
0418 
0419     parameter_type value() const
0420     {
0421         d.registerWithCurrentlyEvaluatingBinding();
0422         return this->val;
0423     }
0424 
0425     arrow_operator_result operator->() const
0426     {
0427         if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
0428             return value();
0429         } else if constexpr (std::is_pointer_v<T>) {
0430             value();
0431             return this->val;
0432         } else {
0433             return;
0434         }
0435     }
0436 
0437     parameter_type operator*() const
0438     {
0439         return value();
0440     }
0441 
0442     operator parameter_type() const
0443     {
0444         return value();
0445     }
0446 
0447     void setValue(rvalue_ref newValue)
0448     {
0449         d.removeBinding();
0450         if (is_equal(newValue))
0451             return;
0452         this->val = std::move(newValue);
0453         notify();
0454     }
0455 
0456     void setValue(parameter_type newValue)
0457     {
0458         d.removeBinding();
0459         if (is_equal(newValue))
0460             return;
0461         this->val = newValue;
0462         notify();
0463     }
0464 
0465     QProperty<T> &operator=(rvalue_ref newValue)
0466     {
0467         setValue(std::move(newValue));
0468         return *this;
0469     }
0470 
0471     QProperty<T> &operator=(parameter_type newValue)
0472     {
0473         setValue(newValue);
0474         return *this;
0475     }
0476 
0477     QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
0478     {
0479         return QPropertyBinding<T>(d.setBinding(newBinding, this));
0480     }
0481 
0482     bool setBinding(const QUntypedPropertyBinding &newBinding)
0483     {
0484         if (!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId<T>())
0485             return false;
0486         setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
0487         return true;
0488     }
0489 
0490 #ifndef Q_QDOC
0491     template <typename Functor>
0492     QPropertyBinding<T> setBinding(Functor &&f,
0493                                    const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0494                                    std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0495     {
0496         return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
0497     }
0498 #else
0499     template <typename Functor>
0500     QPropertyBinding<T> setBinding(Functor f);
0501 #endif
0502 
0503     bool hasBinding() const { return d.hasBinding(); }
0504 
0505     QPropertyBinding<T> binding() const
0506     {
0507         return QPropertyBinding<T>(QUntypedPropertyBinding(d.binding()));
0508     }
0509 
0510     QPropertyBinding<T> takeBinding()
0511     {
0512         return QPropertyBinding<T>(d.setBinding(QUntypedPropertyBinding(), this));
0513     }
0514 
0515     template<typename Functor>
0516     QPropertyChangeHandler<Functor> onValueChanged(Functor f)
0517     {
0518         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0519         return QPropertyChangeHandler<Functor>(*this, std::move(f));
0520     }
0521 
0522     template<typename Functor>
0523     QPropertyChangeHandler<Functor> subscribe(Functor f)
0524     {
0525         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0526         f();
0527         return onValueChanged(std::move(f));
0528     }
0529 
0530     template<typename Functor>
0531     QPropertyNotifier addNotifier(Functor f)
0532     {
0533         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0534         return QPropertyNotifier(*this, std::move(f));
0535     }
0536 
0537     const QtPrivate::QPropertyBindingData &bindingData() const { return d; }
0538 private:
0539     template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
0540     friend bool comparesEqual(const QProperty &lhs, const QProperty &rhs)
0541     {
0542         return lhs.value() == rhs.value();
0543     }
0544 
0545     template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
0546     friend bool comparesEqual(const QProperty &lhs, const T &rhs)
0547     {
0548         return lhs.value() == rhs;
0549     }
0550 
0551     template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>
0552     friend bool comparesEqual(const QProperty &lhs, const U &rhs)
0553     {
0554         return lhs.value() == rhs;
0555     }
0556 
0557     void notify()
0558     {
0559         d.notifyObservers(this);
0560     }
0561 
0562     Q_DISABLE_COPY_MOVE(QProperty)
0563 };
0564 
0565 namespace Qt {
0566     template <typename PropertyType>
0567     QPropertyBinding<PropertyType> makePropertyBinding(const QProperty<PropertyType> &otherProperty,
0568                                                        const QPropertyBindingSourceLocation &location =
0569                                                        QT_PROPERTY_DEFAULT_BINDING_LOCATION)
0570     {
0571         return Qt::makePropertyBinding([&otherProperty]() -> PropertyType { return otherProperty; }, location);
0572     }
0573 }
0574 
0575 
0576 namespace QtPrivate
0577 {
0578 
0579 struct QBindableInterface
0580 {
0581     using Getter = void (*)(const QUntypedPropertyData *d, void *value);
0582     using Setter = void (*)(QUntypedPropertyData *d, const void *value);
0583     using BindingGetter = QUntypedPropertyBinding (*)(const QUntypedPropertyData *d);
0584     using BindingSetter = QUntypedPropertyBinding (*)(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding);
0585     using MakeBinding = QUntypedPropertyBinding (*)(const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location);
0586     using SetObserver = void (*)(const QUntypedPropertyData *d, QPropertyObserver *observer);
0587     using GetMetaType = QMetaType (*)();
0588     Getter getter;
0589     Setter setter;
0590     BindingGetter getBinding;
0591     BindingSetter setBinding;
0592     MakeBinding makeBinding;
0593     SetObserver setObserver;
0594     GetMetaType metaType;
0595 
0596     static constexpr quintptr MetaTypeAccessorFlag = 0x1;
0597 };
0598 
0599 template<typename Property, typename = void>
0600 class QBindableInterfaceForProperty
0601 {
0602     using T = typename Property::value_type;
0603 public:
0604     // interface for computed properties. Those do not have a binding()/setBinding() method, but one can
0605     // install observers on them.
0606     static constexpr QBindableInterface iface = {
0607         [](const QUntypedPropertyData *d, void *value) -> void
0608         { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0609         nullptr,
0610         nullptr,
0611         nullptr,
0612         [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0613         { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0614         [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0615         { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0616         []() { return QMetaType::fromType<T>(); }
0617     };
0618 };
0619 
0620 template<typename Property>
0621 class QBindableInterfaceForProperty<const Property, std::void_t<decltype(std::declval<Property>().binding())>>
0622 {
0623     using T = typename Property::value_type;
0624 public:
0625     // A bindable created from a const property results in a read-only interface, too.
0626     static constexpr QBindableInterface iface = {
0627 
0628         [](const QUntypedPropertyData *d, void *value) -> void
0629         { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0630         /*setter=*/nullptr,
0631         [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding
0632         { return static_cast<const Property *>(d)->binding(); },
0633         /*setBinding=*/nullptr,
0634         [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0635         { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0636         [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0637         { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0638         []() { return QMetaType::fromType<T>(); }
0639     };
0640 };
0641 
0642 template<typename Property>
0643 class QBindableInterfaceForProperty<Property, std::void_t<decltype(std::declval<Property>().binding())>>
0644 {
0645     using T = typename Property::value_type;
0646 public:
0647     static constexpr QBindableInterface iface = {
0648         [](const QUntypedPropertyData *d, void *value) -> void
0649         { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0650         [](QUntypedPropertyData *d, const void *value) -> void
0651         { static_cast<Property *>(d)->setValue(*static_cast<const T*>(value)); },
0652         [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding
0653         { return static_cast<const Property *>(d)->binding(); },
0654         [](QUntypedPropertyData *d, const QUntypedPropertyBinding &binding) -> QUntypedPropertyBinding
0655         { return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); },
0656         [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0657         { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0658         [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0659         { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0660         []() { return QMetaType::fromType<T>(); }
0661     };
0662 };
0663 
0664 }
0665 
0666 namespace QtPrivate {
0667 // used in Q(Untyped)Bindable to print warnings about various binding errors
0668 namespace BindableWarnings {
0669 enum Reason { InvalidInterface, NonBindableInterface, ReadOnlyInterface };
0670 Q_CORE_EXPORT void printUnsuitableBindableWarning(QAnyStringView prefix, Reason reason);
0671 Q_CORE_EXPORT void printMetaTypeMismatch(QMetaType actual, QMetaType expected);
0672 }
0673 
0674 namespace PropertyAdaptorSlotObjectHelpers {
0675 Q_CORE_EXPORT void getter(const QUntypedPropertyData *d, void *value);
0676 Q_CORE_EXPORT void setter(QUntypedPropertyData *d, const void *value);
0677 Q_CORE_EXPORT QUntypedPropertyBinding getBinding(const QUntypedPropertyData *d);
0678 Q_CORE_EXPORT bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
0679                                   QtPrivate::QPropertyBindingFunction binding,
0680                                   QUntypedPropertyData *temp, void *value);
0681 Q_CORE_EXPORT QUntypedPropertyBinding setBinding(QUntypedPropertyData *d,
0682                                                  const QUntypedPropertyBinding &binding,
0683                                                  QPropertyBindingWrapper wrapper);
0684 Q_CORE_EXPORT void setObserver(const QUntypedPropertyData *d, QPropertyObserver *observer);
0685 
0686 template<typename T>
0687 bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
0688                     QtPrivate::QPropertyBindingFunction binding)
0689 {
0690     struct Data : QPropertyData<T>
0691     {
0692         void *data() { return &this->val; }
0693     } temp;
0694     return bindingWrapper(type, d, binding, &temp, temp.data());
0695 }
0696 
0697 template<typename T>
0698 QUntypedPropertyBinding setBinding(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding)
0699 {
0700     return setBinding(d, binding, &bindingWrapper<T>);
0701 }
0702 
0703 template<typename T>
0704 QUntypedPropertyBinding makeBinding(const QUntypedPropertyData *d,
0705                                     const QPropertyBindingSourceLocation &location)
0706 {
0707     return Qt::makePropertyBinding(
0708             [d]() -> T {
0709                 T r;
0710                 getter(d, &r);
0711                 return r;
0712             },
0713             location);
0714 }
0715 
0716 template<class T>
0717 inline constexpr QBindableInterface iface = {
0718     &getter,
0719     &setter,
0720     &getBinding,
0721     &setBinding<T>,
0722     &makeBinding<T>,
0723     &setObserver,
0724     &QMetaType::fromType<T>,
0725 };
0726 }
0727 }
0728 
0729 class QUntypedBindable
0730 {
0731     friend struct QUntypedBindablePrivate; // allows access to internal data
0732 protected:
0733     QUntypedPropertyData *data = nullptr;
0734     const QtPrivate::QBindableInterface *iface = nullptr;
0735     constexpr QUntypedBindable(QUntypedPropertyData *d, const QtPrivate::QBindableInterface *i)
0736         : data(d), iface(i)
0737     {}
0738 
0739     Q_CORE_EXPORT explicit QUntypedBindable(QObject* obj, const QMetaProperty &property, const QtPrivate::QBindableInterface *i);
0740     Q_CORE_EXPORT explicit QUntypedBindable(QObject* obj, const char* property, const QtPrivate::QBindableInterface *i);
0741 
0742 public:
0743     constexpr QUntypedBindable() = default;
0744     template<typename Property>
0745     QUntypedBindable(Property *p)
0746         : data(const_cast<std::remove_cv_t<Property> *>(p)),
0747           iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
0748     { Q_ASSERT(data && iface); }
0749 
0750     bool isValid() const { return data != nullptr; }
0751     bool isBindable() const { return iface && iface->getBinding; }
0752     bool isReadOnly() const { return !(iface && iface->setBinding && iface->setObserver); }
0753 
0754     QUntypedPropertyBinding makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) const
0755     {
0756         return iface ? iface->makeBinding(data, location) : QUntypedPropertyBinding();
0757     }
0758 
0759     QUntypedPropertyBinding takeBinding()
0760     {
0761         if (!iface)
0762             return QUntypedPropertyBinding {};
0763         // We do not have a dedicated takeBinding function pointer in the interface
0764         // therefore we synthesize takeBinding by retrieving the binding with binding
0765         // and calling setBinding with a default constructed QUntypedPropertyBinding
0766         // afterwards.
0767         if (!(iface->getBinding && iface->setBinding))
0768             return QUntypedPropertyBinding {};
0769         QUntypedPropertyBinding binding = iface->getBinding(data);
0770         iface->setBinding(data, QUntypedPropertyBinding{});
0771         return binding;
0772     }
0773 
0774     void observe(QPropertyObserver *observer) const
0775     {
0776         if (iface)
0777             iface->setObserver(data, observer);
0778 #ifndef QT_NO_DEBUG
0779         else
0780             QtPrivate::BindableWarnings::printUnsuitableBindableWarning("observe:",
0781                                                                         QtPrivate::BindableWarnings::InvalidInterface);
0782 #endif
0783     }
0784 
0785     template<typename Functor>
0786     QPropertyChangeHandler<Functor> onValueChanged(Functor f) const
0787     {
0788         QPropertyChangeHandler<Functor> handler(std::move(f));
0789         observe(&handler);
0790         return handler;
0791     }
0792 
0793     template<typename Functor>
0794     QPropertyChangeHandler<Functor> subscribe(Functor f) const
0795     {
0796         f();
0797         return onValueChanged(std::move(f));
0798     }
0799 
0800     template<typename Functor>
0801     QPropertyNotifier addNotifier(Functor f)
0802     {
0803         QPropertyNotifier handler(std::move(f));
0804         observe(&handler);
0805         return handler;
0806     }
0807 
0808     QUntypedPropertyBinding binding() const
0809     {
0810         if (!isBindable()) {
0811 #ifndef QT_NO_DEBUG
0812             QtPrivate::BindableWarnings::printUnsuitableBindableWarning("binding: ",
0813                                                                         QtPrivate::BindableWarnings::NonBindableInterface);
0814 #endif
0815             return QUntypedPropertyBinding();
0816         }
0817         return iface->getBinding(data);
0818     }
0819     bool setBinding(const QUntypedPropertyBinding &binding)
0820     {
0821         if (isReadOnly()) {
0822 #ifndef QT_NO_DEBUG
0823             const auto errorType = iface ? QtPrivate::BindableWarnings::ReadOnlyInterface :
0824                                            QtPrivate::BindableWarnings::InvalidInterface;
0825             QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", errorType);
0826 #endif
0827             return false;
0828         }
0829         if (!binding.isNull() && binding.valueMetaType() != metaType()) {
0830 #ifndef QT_NO_DEBUG
0831             QtPrivate::BindableWarnings::printMetaTypeMismatch(metaType(), binding.valueMetaType());
0832 #endif
0833             return false;
0834         }
0835         iface->setBinding(data, binding);
0836         return true;
0837     }
0838     bool hasBinding() const
0839     {
0840         return !binding().isNull();
0841     }
0842 
0843     QMetaType metaType() const
0844     {
0845         if (!(iface && data))
0846             return QMetaType();
0847         if (iface->metaType)
0848             return iface->metaType();
0849         // ### Qt 7: Change the metatype function to take data as its argument
0850         // special casing for QML's proxy bindable: allow multiplexing in the getter
0851         // function to retrieve the metatype from data
0852         Q_ASSERT(iface->getter);
0853         QMetaType result;
0854         iface->getter(data, reinterpret_cast<void *>(quintptr(&result) | QtPrivate::QBindableInterface::MetaTypeAccessorFlag));
0855         return result;
0856     }
0857 
0858 };
0859 
0860 template<typename T>
0861 class QBindable : public QUntypedBindable
0862 {
0863     template<typename U>
0864     friend class QPropertyAlias;
0865     constexpr QBindable(QUntypedPropertyData *d, const QtPrivate::QBindableInterface *i)
0866         : QUntypedBindable(d, i)
0867     {}
0868 public:
0869     using QUntypedBindable::QUntypedBindable;
0870     explicit QBindable(const QUntypedBindable &b) : QUntypedBindable(b)
0871     {
0872         if (iface && metaType() != QMetaType::fromType<T>()) {
0873             data = nullptr;
0874             iface = nullptr;
0875         }
0876     }
0877 
0878     explicit QBindable(QObject *obj, const QMetaProperty &property)
0879         : QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}
0880 
0881     explicit QBindable(QObject *obj, const char *property)
0882         : QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}
0883 
0884     QPropertyBinding<T> makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) const
0885     {
0886         return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::makeBinding(location));
0887     }
0888     QPropertyBinding<T> binding() const
0889     {
0890         return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::binding());
0891     }
0892 
0893     QPropertyBinding<T> takeBinding()
0894     {
0895         return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::takeBinding());
0896     }
0897 
0898     using QUntypedBindable::setBinding;
0899     QPropertyBinding<T> setBinding(const QPropertyBinding<T> &binding)
0900     {
0901         Q_ASSERT(!iface || binding.isNull() || binding.valueMetaType() == metaType());
0902 
0903         if (iface && iface->setBinding)
0904             return static_cast<QPropertyBinding<T> &&>(iface->setBinding(data, binding));
0905 #ifndef QT_NO_DEBUG
0906         if (!iface)
0907             QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding", QtPrivate::BindableWarnings::InvalidInterface);
0908         else
0909             QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", QtPrivate::BindableWarnings::ReadOnlyInterface);
0910 #endif
0911         return QPropertyBinding<T>();
0912     }
0913 #ifndef Q_QDOC
0914     template <typename Functor>
0915     QPropertyBinding<T> setBinding(Functor &&f,
0916                                    const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0917                                    std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0918     {
0919         return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
0920     }
0921 #else
0922     template <typename Functor>
0923     QPropertyBinding<T> setBinding(Functor f);
0924 #endif
0925 
0926     T value() const
0927     {
0928         if (iface) {
0929             T result;
0930             iface->getter(data, &result);
0931             return result;
0932         }
0933         return T{};
0934     }
0935 
0936     void setValue(const T &value)
0937     {
0938         if (iface && iface->setter)
0939             iface->setter(data, &value);
0940     }
0941 };
0942 
0943 #if QT_DEPRECATED_SINCE(6, 6)
0944 template<typename T>
0945 class QT_DEPRECATED_VERSION_X_6_6("Class was only meant for internal use, use a QProperty and add a binding to the target")
0946 QPropertyAlias : public QPropertyObserver
0947 {
0948     Q_DISABLE_COPY_MOVE(QPropertyAlias)
0949     const QtPrivate::QBindableInterface *iface = nullptr;
0950 
0951 public:
0952     QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
0953     QPropertyAlias(QProperty<T> *property)
0954         : QPropertyObserver(property),
0955           iface(&QtPrivate::QBindableInterfaceForProperty<QProperty<T>>::iface)
0956     {
0957         if (iface)
0958             iface->setObserver(aliasedProperty(), this);
0959     }
0960 
0961     template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
0962     QPropertyAlias(Property *property)
0963         : QPropertyObserver(property),
0964           iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
0965     {
0966         if (iface)
0967             iface->setObserver(aliasedProperty(), this);
0968     }
0969 
0970     QPropertyAlias(QPropertyAlias<T> *alias)
0971         : QPropertyObserver(alias->aliasedProperty()),
0972           iface(alias->iface)
0973     {
0974         if (iface)
0975             iface->setObserver(aliasedProperty(), this);
0976     }
0977 
0978     QPropertyAlias(const QBindable<T> &property)
0979         : QPropertyObserver(property.data),
0980           iface(property.iface)
0981     {
0982         if (iface)
0983             iface->setObserver(aliasedProperty(), this);
0984     }
0985 
0986     T value() const
0987     {
0988         T t = T();
0989         if (auto *p = aliasedProperty())
0990             iface->getter(p, &t);
0991         return t;
0992     }
0993 
0994     operator T() const { return value(); }
0995 
0996     void setValue(const T &newValue)
0997     {
0998         if (auto *p = aliasedProperty())
0999             iface->setter(p, &newValue);
1000     }
1001 
1002     QPropertyAlias<T> &operator=(const T &newValue)
1003     {
1004         setValue(newValue);
1005         return *this;
1006     }
1007 
1008     QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
1009     {
1010         return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);
1011     }
1012 
1013     bool setBinding(const QUntypedPropertyBinding &newBinding)
1014     {
1015         return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);
1016     }
1017 
1018 #ifndef Q_QDOC
1019     template <typename Functor>
1020     QPropertyBinding<T> setBinding(Functor &&f,
1021                                    const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
1022                                    std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
1023     {
1024         return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
1025     }
1026 #else
1027     template <typename Functor>
1028     QPropertyBinding<T> setBinding(Functor f);
1029 #endif
1030 
1031     bool hasBinding() const
1032     {
1033         return QBindable<T>(aliasedProperty(), iface).hasBinding();
1034     }
1035 
1036     QPropertyBinding<T> binding() const
1037     {
1038         return QBindable<T>(aliasedProperty(), iface).binding();
1039     }
1040 
1041     QPropertyBinding<T> takeBinding()
1042     {
1043         return QBindable<T>(aliasedProperty(), iface).takeBinding();
1044     }
1045 
1046     template<typename Functor>
1047     QPropertyChangeHandler<Functor> onValueChanged(Functor f)
1048     {
1049         return QBindable<T>(aliasedProperty(), iface).onValueChanged(std::move(f));
1050     }
1051 
1052     template<typename Functor>
1053     QPropertyChangeHandler<Functor> subscribe(Functor f)
1054     {
1055         return QBindable<T>(aliasedProperty(), iface).subscribe(std::move(f));
1056     }
1057 
1058     template<typename Functor>
1059     QPropertyNotifier addNotifier(Functor f)
1060     {
1061         return QBindable<T>(aliasedProperty(), iface).addNotifier(std::move(f));
1062     }
1063 
1064     bool isValid() const
1065     {
1066         return aliasedProperty() != nullptr;
1067     }
1068     QT_WARNING_POP
1069 };
1070 #endif // QT_DEPRECATED_SINCE(6, 6)
1071 
1072 template<typename Class, typename T, auto Offset, auto Signal = nullptr>
1073 class QObjectBindableProperty : public QPropertyData<T>
1074 {
1075     using ThisType = QObjectBindableProperty<Class, T, Offset, Signal>;
1076     static bool constexpr HasSignal = !std::is_same_v<decltype(Signal), std::nullptr_t>;
1077     using SignalTakesValue = std::is_invocable<decltype(Signal), Class, T>;
1078     Class *owner()
1079     {
1080         char *that = reinterpret_cast<char *>(this);
1081         return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1082     }
1083     const Class *owner() const
1084     {
1085         char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
1086         return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1087     }
1088     static void signalCallBack(QUntypedPropertyData *o)
1089     {
1090         QObjectBindableProperty *that = static_cast<QObjectBindableProperty *>(o);
1091         if constexpr (HasSignal) {
1092             if constexpr (SignalTakesValue::value)
1093                 (that->owner()->*Signal)(that->valueBypassingBindings());
1094             else
1095                 (that->owner()->*Signal)();
1096         }
1097     }
1098 public:
1099     using value_type = typename QPropertyData<T>::value_type;
1100     using parameter_type = typename QPropertyData<T>::parameter_type;
1101     using rvalue_ref = typename QPropertyData<T>::rvalue_ref;
1102     using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;
1103 
1104     QObjectBindableProperty() = default;
1105     explicit QObjectBindableProperty(const T &initialValue) : QPropertyData<T>(initialValue) {}
1106     explicit QObjectBindableProperty(T &&initialValue) : QPropertyData<T>(std::move(initialValue)) {}
1107     explicit QObjectBindableProperty(const QPropertyBinding<T> &binding)
1108         : QObjectBindableProperty()
1109     { setBinding(binding); }
1110 #ifndef Q_QDOC
1111     template <typename Functor>
1112     explicit QObjectBindableProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
1113                        typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr)
1114         : QObjectBindableProperty(QPropertyBinding<T>(std::forward<Functor>(f), location))
1115     {}
1116 #else
1117     template <typename Functor>
1118     explicit QObjectBindableProperty(Functor &&f);
1119 #endif
1120 
1121     QT_DECLARE_EQUALITY_OPERATORS_HELPER(QObjectBindableProperty, QObjectBindableProperty, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
1122     QT_DECLARE_EQUALITY_OPERATORS_HELPER(QObjectBindableProperty, T, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
1123     QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QObjectBindableProperty, T, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
1124 
1125     parameter_type value() const
1126     {
1127         qGetBindingStorage(owner())->registerDependency(this);
1128         return this->val;
1129     }
1130 
1131     arrow_operator_result operator->() const
1132     {
1133         if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
1134             return value();
1135         } else if constexpr (std::is_pointer_v<T>) {
1136             value();
1137             return this->val;
1138         } else {
1139             return;
1140         }
1141     }
1142 
1143     parameter_type operator*() const
1144     {
1145         return value();
1146     }
1147 
1148     operator parameter_type() const
1149     {
1150         return value();
1151     }
1152 
1153     void setValue(parameter_type t)
1154     {
1155         auto *bd = qGetBindingStorage(owner())->bindingData(this);
1156         if (bd)
1157             bd->removeBinding();
1158         if (this->val == t)
1159             return;
1160         this->val = t;
1161         notify(bd);
1162     }
1163 
1164     void notify() {
1165         auto *bd = qGetBindingStorage(owner())->bindingData(this);
1166         notify(bd);
1167     }
1168 
1169     void setValue(rvalue_ref t)
1170     {
1171         auto *bd = qGetBindingStorage(owner())->bindingData(this);
1172         if (bd)
1173             bd->removeBinding();
1174         if (this->val == t)
1175             return;
1176         this->val = std::move(t);
1177         notify(bd);
1178     }
1179 
1180     QObjectBindableProperty &operator=(rvalue_ref newValue)
1181     {
1182         setValue(std::move(newValue));
1183         return *this;
1184     }
1185 
1186     QObjectBindableProperty &operator=(parameter_type newValue)
1187     {
1188         setValue(newValue);
1189         return *this;
1190     }
1191 
1192     QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
1193     {
1194         QtPrivate::QPropertyBindingData *bd = qGetBindingStorage(owner())->bindingData(this, true);
1195         QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, HasSignal ? &signalCallBack : nullptr));
1196         return static_cast<QPropertyBinding<T> &>(oldBinding);
1197     }
1198 
1199     bool setBinding(const QUntypedPropertyBinding &newBinding)
1200     {
1201         if (!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId<T>())
1202             return false;
1203         setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
1204         return true;
1205     }
1206 
1207 #ifndef Q_QDOC
1208     template <typename Functor>
1209     QPropertyBinding<T> setBinding(Functor &&f,
1210                                    const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
1211                                    std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
1212     {
1213         return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
1214     }
1215 #else
1216     template <typename Functor>
1217     QPropertyBinding<T> setBinding(Functor f);
1218 #endif
1219 
1220     bool hasBinding() const
1221     {
1222         auto *bd = qGetBindingStorage(owner())->bindingData(this);
1223         return bd && bd->binding() != nullptr;
1224     }
1225 
1226     QPropertyBinding<T> binding() const
1227     {
1228         auto *bd = qGetBindingStorage(owner())->bindingData(this);
1229         return static_cast<QPropertyBinding<T> &&>(QUntypedPropertyBinding(bd ? bd->binding() : nullptr));
1230     }
1231 
1232     QPropertyBinding<T> takeBinding()
1233     {
1234         return setBinding(QPropertyBinding<T>());
1235     }
1236 
1237     template<typename Functor>
1238     QPropertyChangeHandler<Functor> onValueChanged(Functor f)
1239     {
1240         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1241         return QPropertyChangeHandler<Functor>(*this, std::move(f));
1242     }
1243 
1244     template<typename Functor>
1245     QPropertyChangeHandler<Functor> subscribe(Functor f)
1246     {
1247         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1248         f();
1249         return onValueChanged(std::move(f));
1250     }
1251 
1252     template<typename Functor>
1253     QPropertyNotifier addNotifier(Functor f)
1254     {
1255         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1256         return QPropertyNotifier(*this, std::move(f));
1257     }
1258 
1259     const QtPrivate::QPropertyBindingData &bindingData() const
1260     {
1261         auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1262         return *storage->bindingData(const_cast<ThisType *>(this), true);
1263     }
1264 private:
1265     template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
1266     friend bool comparesEqual(const QObjectBindableProperty &lhs, const QObjectBindableProperty &rhs)
1267     {
1268         return lhs.value() == rhs.value();
1269     }
1270 
1271     template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
1272     friend bool comparesEqual(const QObjectBindableProperty &lhs, const T &rhs)
1273     {
1274         return lhs.value() == rhs;
1275     }
1276 
1277     void notify(const QtPrivate::QPropertyBindingData *binding)
1278     {
1279         if (binding)
1280             binding->notifyObservers(this, qGetBindingStorage(owner()));
1281         if constexpr (HasSignal) {
1282             if constexpr (SignalTakesValue::value)
1283                 (owner()->*Signal)(this->valueBypassingBindings());
1284             else
1285                 (owner()->*Signal)();
1286         }
1287     }
1288 };
1289 
1290 #define QT_OBJECT_BINDABLE_PROPERTY_3(Class, Type, name) \
1291     static constexpr size_t _qt_property_##name##_offset() { \
1292         QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1293         return offsetof(Class, name); \
1294         QT_WARNING_POP \
1295     } \
1296     QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name;
1297 
1298 #define QT_OBJECT_BINDABLE_PROPERTY_4(Class, Type, name, Signal) \
1299     static constexpr size_t _qt_property_##name##_offset() { \
1300         QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1301         return offsetof(Class, name); \
1302         QT_WARNING_POP \
1303     } \
1304     QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name;
1305 
1306 #define Q_OBJECT_BINDABLE_PROPERTY(...) \
1307     QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1308     QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY, __VA_ARGS__) \
1309     QT_WARNING_POP
1310 
1311 #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_4(Class, Type, name, value)                          \
1312     static constexpr size_t _qt_property_##name##_offset()                                         \
1313     {                                                                                              \
1314         QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF                                        \
1315         return offsetof(Class, name);                                                              \
1316         QT_WARNING_POP                                                                             \
1317     }                                                                                              \
1318     QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name =      \
1319             QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr>(    \
1320                     value);
1321 
1322 #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_5(Class, Type, name, value, Signal)                  \
1323     static constexpr size_t _qt_property_##name##_offset()                                         \
1324     {                                                                                              \
1325         QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF                                        \
1326         return offsetof(Class, name);                                                              \
1327         QT_WARNING_POP                                                                             \
1328     }                                                                                              \
1329     QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name =       \
1330             QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal>(     \
1331                     value);
1332 
1333 #define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...)                                                  \
1334     QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1335     QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, __VA_ARGS__) \
1336     QT_WARNING_POP
1337 
1338 template<typename Class, typename T, auto Offset, auto Getter>
1339 class QObjectComputedProperty : public QUntypedPropertyData
1340 {
1341     Class *owner()
1342     {
1343         char *that = reinterpret_cast<char *>(this);
1344         return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1345     }
1346     const Class *owner() const
1347     {
1348         char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
1349         return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1350     }
1351 
1352 public:
1353     using value_type = T;
1354     using parameter_type = T;
1355 
1356     QObjectComputedProperty() = default;
1357 
1358     parameter_type value() const
1359     {
1360         qGetBindingStorage(owner())->registerDependency(this);
1361         return (owner()->*Getter)();
1362     }
1363 
1364     std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, parameter_type, void>
1365     operator->() const
1366     {
1367         if constexpr (QTypeTraits::is_dereferenceable_v<T>)
1368             return value();
1369         else
1370             return;
1371     }
1372 
1373     parameter_type operator*() const
1374     {
1375         return value();
1376     }
1377 
1378     operator parameter_type() const
1379     {
1380         return value();
1381     }
1382 
1383     constexpr bool hasBinding() const { return false; }
1384 
1385     template<typename Functor>
1386     QPropertyChangeHandler<Functor> onValueChanged(Functor f)
1387     {
1388         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1389         return QPropertyChangeHandler<Functor>(*this, std::move(f));
1390     }
1391 
1392     template<typename Functor>
1393     QPropertyChangeHandler<Functor> subscribe(Functor f)
1394     {
1395         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1396         f();
1397         return onValueChanged(std::move(f));
1398     }
1399 
1400     template<typename Functor>
1401     QPropertyNotifier addNotifier(Functor f)
1402     {
1403         static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1404         return QPropertyNotifier(*this, std::move(f));
1405     }
1406 
1407     QtPrivate::QPropertyBindingData &bindingData() const
1408     {
1409         auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1410         return *storage->bindingData(const_cast<QObjectComputedProperty *>(this), true);
1411     }
1412 
1413     void notify() {
1414         // computed property can't store a binding, so there's nothing to mark
1415         auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1416         auto bd = storage->bindingData(const_cast<QObjectComputedProperty *>(this), false);
1417         if (bd)
1418             bd->notifyObservers(this, qGetBindingStorage(owner()));
1419     }
1420 };
1421 
1422 #define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name,  ...) \
1423     static constexpr size_t _qt_property_##name##_offset() { \
1424         QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1425         return offsetof(Class, name); \
1426         QT_WARNING_POP \
1427     } \
1428     QObjectComputedProperty<Class, Type, Class::_qt_property_##name##_offset, __VA_ARGS__> name;
1429 
1430 #undef QT_SOURCE_LOCATION_NAMESPACE
1431 
1432 QT_END_NAMESPACE
1433 
1434 #endif // QPROPERTY_H