Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-13 09:22:40

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