Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:07:34

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