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 QPROPERTYPRIVATE_H
0005 #define QPROPERTYPRIVATE_H
0006 
0007 //
0008 //  W A R N I N G
0009 //  -------------
0010 //
0011 // This file is not part of the Qt API.  It exists purely as an
0012 // implementation detail.  This header file may change from version to
0013 // version without notice, or even be removed.
0014 //
0015 // We mean it.
0016 //
0017 
0018 #include <QtCore/qglobal.h>
0019 #include <QtCore/qtaggedpointer.h>
0020 #include <QtCore/qmetatype.h>
0021 #include <QtCore/qcontainerfwd.h>
0022 #include <QtCore/qttypetraits.h>
0023 
0024 #include <functional>
0025 
0026 QT_BEGIN_NAMESPACE
0027 
0028 class QBindingStorage;
0029 
0030 template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
0031 class QObjectCompatProperty;
0032 
0033 class QPropertyBindingPrivatePtr;
0034 using PendingBindingObserverList = QVarLengthArray<QPropertyBindingPrivatePtr>;
0035 
0036 namespace QtPrivate {
0037 // QPropertyBindingPrivatePtr operates on a RefCountingMixin solely so that we can inline
0038 // the constructor and copy constructor
0039 struct RefCounted {
0040 
0041     int refCount() const { return ref; }
0042     void addRef() { ++ref; }
0043     bool deref() { return --ref != 0; }
0044 
0045 private:
0046     int ref = 0;
0047 };
0048 }
0049 
0050 class QQmlPropertyBinding;
0051 class QPropertyBindingPrivate;
0052 class QPropertyBindingPrivatePtr
0053 {
0054 public:
0055     using T = QtPrivate::RefCounted;
0056     T &operator*() const { return *d; }
0057     T *operator->() noexcept { return d; }
0058     T *operator->() const noexcept { return d; }
0059     explicit operator T *() { return d; }
0060     explicit operator const T *() const noexcept { return d; }
0061     T *data() const noexcept { return d; }
0062     T *get() const noexcept { return d; }
0063     const T *constData() const noexcept { return d; }
0064     T *take() noexcept { T *x = d; d = nullptr; return x; }
0065 
0066     QPropertyBindingPrivatePtr() noexcept : d(nullptr) { }
0067     ~QPropertyBindingPrivatePtr()
0068     {
0069         if (d && !d->deref())
0070             destroyAndFreeMemory();
0071     }
0072     Q_CORE_EXPORT void destroyAndFreeMemory();
0073 
0074     explicit QPropertyBindingPrivatePtr(T *data) noexcept : d(data) { if (d) d->addRef(); }
0075     QPropertyBindingPrivatePtr(const QPropertyBindingPrivatePtr &o) noexcept
0076         : d(o.d) { if (d) d->addRef(); }
0077 
0078     void reset(T *ptr = nullptr) noexcept;
0079 
0080     QPropertyBindingPrivatePtr &operator=(const QPropertyBindingPrivatePtr &o) noexcept
0081     {
0082         reset(o.d);
0083         return *this;
0084     }
0085     QPropertyBindingPrivatePtr &operator=(T *o) noexcept
0086     {
0087         reset(o);
0088         return *this;
0089     }
0090     QPropertyBindingPrivatePtr(QPropertyBindingPrivatePtr &&o) noexcept : d(std::exchange(o.d, nullptr)) {}
0091     QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QPropertyBindingPrivatePtr)
0092 
0093     operator bool () const noexcept { return d != nullptr; }
0094     bool operator!() const noexcept { return d == nullptr; }
0095 
0096     void swap(QPropertyBindingPrivatePtr &other) noexcept
0097     { qt_ptr_swap(d, other.d); }
0098 
0099 private:
0100     friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
0101                               const QPropertyBindingPrivatePtr &rhs) noexcept
0102     { return lhs.d == rhs.d; }
0103     Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr)
0104     friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
0105                               const T *rhs) noexcept
0106     { return lhs.d == rhs; }
0107     Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr, T*)
0108     friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
0109                               std::nullptr_t) noexcept
0110     { return !lhs; }
0111     Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr, std::nullptr_t)
0112 
0113     QtPrivate::RefCounted *d;
0114 };
0115 
0116 class QUntypedPropertyBinding;
0117 class QPropertyBindingPrivate;
0118 struct QPropertyBindingDataPointer;
0119 class QPropertyObserver;
0120 struct QPropertyObserverPointer;
0121 
0122 class QUntypedPropertyData
0123 {
0124 };
0125 
0126 namespace QtPrivate {
0127 template <typename T>
0128 using IsUntypedPropertyData = std::enable_if_t<std::is_base_of_v<QUntypedPropertyData, T>, bool>;
0129 }
0130 
0131 template <typename T>
0132 class QPropertyData;
0133 
0134 // Used for grouped property evaluations
0135 namespace QtPrivate {
0136 class QPropertyBindingData;
0137 }
0138 struct QPropertyDelayedNotifications;
0139 struct QPropertyProxyBindingData
0140 {
0141     // acts as QPropertyBindingData::d_ptr
0142     quintptr d_ptr;
0143     /*
0144         The two members below store the original binding data and property
0145         data pointer of the property which gets proxied.
0146         They are set in QPropertyDelayedNotifications::addProperty
0147     */
0148     const QtPrivate::QPropertyBindingData *originalBindingData;
0149     QUntypedPropertyData *propertyData;
0150 };
0151 
0152 namespace QtPrivate {
0153 struct BindingEvaluationState;
0154 
0155 /*  used in BindingFunctionVTable::createFor; on all other compilers, void would work, but on
0156     MSVC this causes C2182 when compiling in C++20 mode. As we only need to provide some default
0157     value which gets ignored, we introduce this dummy type.
0158 */
0159 struct MSVCWorkAround {};
0160 
0161 struct BindingFunctionVTable
0162 {
0163     using CallFn = bool(*)(QMetaType, QUntypedPropertyData *, void *);
0164     using DtorFn = void(*)(void *);
0165     using MoveCtrFn = void(*)(void *, void *);
0166     const CallFn call;
0167     const DtorFn destroy;
0168     const MoveCtrFn moveConstruct;
0169     const qsizetype size;
0170 
0171     template<typename Callable, typename PropertyType=MSVCWorkAround>
0172     static constexpr BindingFunctionVTable createFor()
0173     {
0174         static_assert (alignof(Callable) <= alignof(std::max_align_t), "Bindings do not support overaligned functors!");
0175         return {
0176             /*call=*/[](QMetaType metaType, QUntypedPropertyData *dataPtr, void *f){
0177                 if constexpr (!std::is_invocable_v<Callable>) {
0178                     // we got an untyped callable
0179                     static_assert (std::is_invocable_r_v<bool, Callable, QMetaType, QUntypedPropertyData *> );
0180                     auto untypedEvaluationFunction = static_cast<Callable *>(f);
0181                     return std::invoke(*untypedEvaluationFunction, metaType, dataPtr);
0182                 } else if constexpr (!std::is_same_v<PropertyType, MSVCWorkAround>) {
0183                     Q_UNUSED(metaType);
0184                     QPropertyData<PropertyType> *propertyPtr = static_cast<QPropertyData<PropertyType> *>(dataPtr);
0185                     // That is allowed by POSIX even if Callable is a function pointer
0186                     auto evaluationFunction = static_cast<Callable *>(f);
0187                     PropertyType newValue = std::invoke(*evaluationFunction);
0188                     if constexpr (QTypeTraits::has_operator_equal_v<PropertyType>) {
0189                         if (newValue == propertyPtr->valueBypassingBindings())
0190                             return false;
0191                     }
0192                     propertyPtr->setValueBypassingBindings(std::move(newValue));
0193                     return true;
0194                 } else {
0195                     // Our code will never instantiate this
0196                     Q_UNREACHABLE_RETURN(false);
0197                 }
0198             },
0199             /*destroy*/[](void *f){ static_cast<Callable *>(f)->~Callable(); },
0200             /*moveConstruct*/[](void *addr, void *other){
0201                 new (addr) Callable(std::move(*static_cast<Callable *>(other)));
0202             },
0203             /*size*/sizeof(Callable)
0204         };
0205     }
0206 };
0207 
0208 template<typename Callable, typename PropertyType=MSVCWorkAround>
0209 inline constexpr BindingFunctionVTable bindingFunctionVTable = BindingFunctionVTable::createFor<Callable, PropertyType>();
0210 
0211 
0212 // writes binding result into dataPtr
0213 struct QPropertyBindingFunction {
0214     const QtPrivate::BindingFunctionVTable *vtable;
0215     void *functor;
0216 };
0217 
0218 using QPropertyObserverCallback = void (*)(QUntypedPropertyData *);
0219 using QPropertyBindingWrapper = bool(*)(QMetaType, QUntypedPropertyData *dataPtr, QPropertyBindingFunction);
0220 
0221 /*!
0222     \internal
0223     A property normally consists of the actual property value and metadata for the binding system.
0224     QPropertyBindingData is the latter part. It stores a pointer to either
0225     - a (potentially empty) linked list of notifiers, in case there is no binding set,
0226     - an actual QUntypedPropertyBinding when the property has a binding,
0227     - or a pointer to QPropertyProxyBindingData when notifications occur inside a grouped update.
0228 
0229     \sa QPropertyDelayedNotifications, beginPropertyUpdateGroup
0230  */
0231 class Q_CORE_EXPORT QPropertyBindingData
0232 {
0233     // Mutable because the address of the observer of the currently evaluating binding is stored here, for
0234     // notification later when the value changes.
0235     mutable quintptr d_ptr = 0;
0236     friend struct QT_PREPEND_NAMESPACE(QPropertyBindingDataPointer);
0237     friend class QT_PREPEND_NAMESPACE(QQmlPropertyBinding);
0238     friend struct QT_PREPEND_NAMESPACE(QPropertyDelayedNotifications);
0239 
0240     template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
0241     friend class QT_PREPEND_NAMESPACE(QObjectCompatProperty);
0242 
0243     Q_DISABLE_COPY(QPropertyBindingData)
0244 public:
0245     QPropertyBindingData() = default;
0246     QPropertyBindingData(QPropertyBindingData &&other);
0247     QPropertyBindingData &operator=(QPropertyBindingData &&other) = delete;
0248     ~QPropertyBindingData();
0249 
0250     // Is d_ptr pointing to a binding (1) or list of notifiers (0)?
0251     static inline constexpr quintptr BindingBit = 0x1;
0252     // Is d_ptr pointing to QPropertyProxyBindingData (1) or to an actual binding/list of notifiers?
0253     static inline constexpr quintptr DelayedNotificationBit = 0x2;
0254 
0255     bool hasBinding() const { return d_ptr & BindingBit; }
0256     bool isNotificationDelayed() const { return d_ptr & DelayedNotificationBit; }
0257 
0258     QUntypedPropertyBinding setBinding(const QUntypedPropertyBinding &newBinding,
0259                                        QUntypedPropertyData *propertyDataPtr,
0260                                        QPropertyObserverCallback staticObserverCallback = nullptr,
0261                                        QPropertyBindingWrapper bindingWrapper = nullptr);
0262 
0263     QPropertyBindingPrivate *binding() const
0264     {
0265         quintptr dd = d();
0266         if (dd & BindingBit)
0267             return reinterpret_cast<QPropertyBindingPrivate*>(dd - BindingBit);
0268         return nullptr;
0269 
0270     }
0271 
0272     void evaluateIfDirty(const QUntypedPropertyData *) const; // ### Kept for BC reasons, unused
0273 
0274     void removeBinding()
0275     {
0276         if (hasBinding())
0277             removeBinding_helper();
0278     }
0279 
0280     void registerWithCurrentlyEvaluatingBinding(QtPrivate::BindingEvaluationState *currentBinding) const
0281     {
0282         if (!currentBinding)
0283             return;
0284         registerWithCurrentlyEvaluatingBinding_helper(currentBinding);
0285     }
0286     void registerWithCurrentlyEvaluatingBinding() const;
0287     void notifyObservers(QUntypedPropertyData *propertyDataPtr) const;
0288     void notifyObservers(QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage) const;
0289 private:
0290     /*!
0291         \internal
0292         Returns a reference to d_ptr, except when d_ptr points to a proxy.
0293         In that case, a reference to proxy->d_ptr is returned instead.
0294 
0295         To properly support proxying, direct access to d_ptr only occurs when
0296         - a function actually deals with proxying (e.g.
0297           QPropertyDelayedNotifications::addProperty),
0298         - only the tag value is accessed (e.g. hasBinding) or
0299         - inside a constructor.
0300      */
0301     quintptr &d_ref() const
0302     {
0303         quintptr &d = d_ptr;
0304         if (isNotificationDelayed())
0305             return proxyData()->d_ptr;
0306         return d;
0307     }
0308     quintptr d() const { return d_ref(); }
0309     QPropertyProxyBindingData *proxyData() const
0310     {
0311         Q_ASSERT(isNotificationDelayed());
0312         return reinterpret_cast<QPropertyProxyBindingData *>(d_ptr & ~(BindingBit|DelayedNotificationBit));
0313     }
0314     void registerWithCurrentlyEvaluatingBinding_helper(BindingEvaluationState *currentBinding) const;
0315     void removeBinding_helper();
0316 
0317     enum NotificationResult { Delayed, Evaluated };
0318     NotificationResult notifyObserver_helper(
0319             QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage,
0320             QPropertyObserverPointer observer,
0321             PendingBindingObserverList &bindingObservers) const;
0322 };
0323 
0324 template <typename T, typename Tag>
0325 class QTagPreservingPointerToPointer
0326 {
0327 public:
0328     constexpr QTagPreservingPointerToPointer() = default;
0329 
0330     QTagPreservingPointerToPointer(T **ptr)
0331         : d(reinterpret_cast<quintptr*>(ptr))
0332     {}
0333 
0334     QTagPreservingPointerToPointer<T, Tag> &operator=(T **ptr)
0335     {
0336         d = reinterpret_cast<quintptr *>(ptr);
0337         return *this;
0338     }
0339 
0340     QTagPreservingPointerToPointer<T, Tag> &operator=(QTaggedPointer<T, Tag> *ptr)
0341     {
0342         d = reinterpret_cast<quintptr *>(ptr);
0343         return *this;
0344     }
0345 
0346     void clear()
0347     {
0348         d = nullptr;
0349     }
0350 
0351     void setPointer(T *ptr)
0352     {
0353         *d = reinterpret_cast<quintptr>(ptr) | (*d & QTaggedPointer<T, Tag>::tagMask());
0354     }
0355 
0356     T *get() const
0357     {
0358         return reinterpret_cast<T*>(*d & QTaggedPointer<T, Tag>::pointerMask());
0359     }
0360 
0361     explicit operator bool() const
0362     {
0363         return d != nullptr;
0364     }
0365 
0366 private:
0367     quintptr *d = nullptr;
0368 };
0369 
0370 namespace detail {
0371     template <typename F>
0372     struct ExtractClassFromFunctionPointer;
0373 
0374     template<typename T, typename C>
0375     struct ExtractClassFromFunctionPointer<T C::*> { using Class = C; };
0376 
0377     constexpr size_t getOffset(size_t o)
0378     {
0379         return o;
0380     }
0381     constexpr size_t getOffset(size_t (*offsetFn)())
0382     {
0383         return offsetFn();
0384     }
0385 }
0386 
0387 } // namespace QtPrivate
0388 
0389 QT_END_NAMESPACE
0390 
0391 #endif // QPROPERTYPRIVATE_H