File indexing completed on 2025-09-18 09:26:42
0001
0002
0003
0004 #ifndef QPROPERTYPRIVATE_H
0005 #define QPROPERTYPRIVATE_H
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
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
0038
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
0135 namespace QtPrivate {
0136 class QPropertyBindingData;
0137 }
0138 struct QPropertyDelayedNotifications;
0139 struct QPropertyProxyBindingData
0140 {
0141
0142 quintptr d_ptr;
0143
0144
0145
0146
0147
0148 const QtPrivate::QPropertyBindingData *originalBindingData;
0149 QUntypedPropertyData *propertyData;
0150 };
0151
0152 namespace QtPrivate {
0153 struct BindingEvaluationState;
0154
0155
0156
0157
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 [](QMetaType metaType, QUntypedPropertyData *dataPtr, void *f){
0177 if constexpr (!std::is_invocable_v<Callable>) {
0178
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
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
0196 Q_UNREACHABLE_RETURN(false);
0197 }
0198 },
0199 [](void *f){ static_cast<Callable *>(f)->~Callable(); },
0200 [](void *addr, void *other){
0201 new (addr) Callable(std::move(*static_cast<Callable *>(other)));
0202 },
0203 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
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
0223
0224
0225
0226
0227
0228
0229
0230
0231 class Q_CORE_EXPORT QPropertyBindingData
0232 {
0233
0234
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
0251 static inline constexpr quintptr BindingBit = 0x1;
0252
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;
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
0292
0293
0294
0295
0296
0297
0298
0299
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 }
0388
0389 QT_END_NAMESPACE
0390
0391 #endif