Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:26:42

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