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