File indexing completed on 2026-08-29 09:18:31
0001
0002
0003
0004
0005 #ifndef QPROPERTYPRIVATE_H
0006 #define QPROPERTYPRIVATE_H
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <QtCore/qglobal.h>
0020 #include <QtCore/qtaggedpointer.h>
0021 #include <QtCore/qmetatype.h>
0022 #include <QtCore/qcontainerfwd.h>
0023 #include <QtCore/qttypetraits.h>
0024
0025 #include <functional>
0026
0027 QT_BEGIN_NAMESPACE
0028
0029 class QBindingStorage;
0030
0031 template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
0032 class QObjectCompatProperty;
0033
0034 class QPropertyBindingPrivatePtr;
0035 using PendingBindingObserverList = QVarLengthArray<QPropertyBindingPrivatePtr>;
0036
0037 namespace QtPrivate {
0038
0039
0040 struct RefCounted {
0041
0042 int refCount() const { return ref; }
0043 void addRef() { ++ref; }
0044 bool deref() { return --ref != 0; }
0045
0046 private:
0047 int ref = 0;
0048 };
0049 }
0050
0051 class QQmlPropertyBinding;
0052 class QPropertyBindingPrivate;
0053 class QPropertyBindingPrivatePtr
0054 {
0055 public:
0056 using T = QtPrivate::RefCounted;
0057 T &operator*() const { return *d; }
0058 T *operator->() noexcept { return d; }
0059 T *operator->() const noexcept { return d; }
0060 explicit operator T *() { return d; }
0061 explicit operator const T *() const noexcept { return d; }
0062 T *data() const noexcept { return d; }
0063 T *get() const noexcept { return d; }
0064 const T *constData() const noexcept { return d; }
0065 T *take() noexcept { T *x = d; d = nullptr; return x; }
0066
0067 QPropertyBindingPrivatePtr() noexcept : d(nullptr) { }
0068 ~QPropertyBindingPrivatePtr()
0069 {
0070 if (d && !d->deref())
0071 destroyAndFreeMemory();
0072 }
0073 Q_CORE_EXPORT void destroyAndFreeMemory();
0074
0075 explicit QPropertyBindingPrivatePtr(T *data) noexcept : d(data) { if (d) d->addRef(); }
0076 QPropertyBindingPrivatePtr(const QPropertyBindingPrivatePtr &o) noexcept
0077 : d(o.d) { if (d) d->addRef(); }
0078
0079 void reset(T *ptr = nullptr) noexcept;
0080
0081 QPropertyBindingPrivatePtr &operator=(const QPropertyBindingPrivatePtr &o) noexcept
0082 {
0083 reset(o.d);
0084 return *this;
0085 }
0086 QPropertyBindingPrivatePtr &operator=(T *o) noexcept
0087 {
0088 reset(o);
0089 return *this;
0090 }
0091 QPropertyBindingPrivatePtr(QPropertyBindingPrivatePtr &&o) noexcept : d(std::exchange(o.d, nullptr)) {}
0092 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QPropertyBindingPrivatePtr)
0093
0094 operator bool () const noexcept { return d != nullptr; }
0095 bool operator!() const noexcept { return d == nullptr; }
0096
0097 void swap(QPropertyBindingPrivatePtr &other) noexcept
0098 { qt_ptr_swap(d, other.d); }
0099
0100 private:
0101 friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
0102 const QPropertyBindingPrivatePtr &rhs) noexcept
0103 { return lhs.d == rhs.d; }
0104 Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr)
0105 friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
0106 const T *rhs) noexcept
0107 { return lhs.d == rhs; }
0108 Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr, T*)
0109 friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs,
0110 std::nullptr_t) noexcept
0111 { return !lhs; }
0112 Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr, std::nullptr_t)
0113
0114 QtPrivate::RefCounted *d;
0115 };
0116
0117 class QUntypedPropertyBinding;
0118 class QPropertyBindingPrivate;
0119 struct QPropertyBindingDataPointer;
0120 class QPropertyObserver;
0121 struct QPropertyObserverPointer;
0122
0123 class QUntypedPropertyData
0124 {
0125 };
0126
0127 namespace QtPrivate {
0128 template <typename T>
0129 using IsUntypedPropertyData = std::enable_if_t<std::is_base_of_v<QUntypedPropertyData, T>, bool>;
0130 }
0131
0132 template <typename T>
0133 class QPropertyData;
0134
0135
0136 namespace QtPrivate {
0137 class QPropertyBindingData;
0138 }
0139 struct QPropertyDelayedNotifications;
0140 struct QPropertyProxyBindingData
0141 {
0142
0143 quintptr d_ptr;
0144
0145
0146
0147
0148
0149 const QtPrivate::QPropertyBindingData *originalBindingData;
0150 QUntypedPropertyData *propertyData;
0151 };
0152
0153 namespace QtPrivate {
0154 struct BindingEvaluationState;
0155
0156
0157
0158
0159
0160 struct MSVCWorkAround {};
0161
0162 struct BindingFunctionVTable
0163 {
0164 using CallFn = bool(*)(QMetaType, QUntypedPropertyData *, void *);
0165 using DtorFn = void(*)(void *);
0166 using MoveCtrFn = void(*)(void *, void *);
0167 const CallFn call;
0168 const DtorFn destroy;
0169 const MoveCtrFn moveConstruct;
0170 const qsizetype size;
0171
0172 template<typename Callable, typename PropertyType=MSVCWorkAround>
0173 static constexpr BindingFunctionVTable createFor()
0174 {
0175 static_assert (alignof(Callable) <= alignof(std::max_align_t), "Bindings do not support overaligned functors!");
0176 return {
0177 [](QMetaType metaType, QUntypedPropertyData *dataPtr, void *f){
0178 if constexpr (!std::is_invocable_v<Callable>) {
0179
0180 static_assert (std::is_invocable_r_v<bool, Callable, QMetaType, QUntypedPropertyData *> );
0181 auto untypedEvaluationFunction = static_cast<Callable *>(f);
0182 return std::invoke(*untypedEvaluationFunction, metaType, dataPtr);
0183 } else if constexpr (!std::is_same_v<PropertyType, MSVCWorkAround>) {
0184 Q_UNUSED(metaType);
0185 QPropertyData<PropertyType> *propertyPtr = static_cast<QPropertyData<PropertyType> *>(dataPtr);
0186
0187 auto evaluationFunction = static_cast<Callable *>(f);
0188 PropertyType newValue = std::invoke(*evaluationFunction);
0189 if constexpr (QTypeTraits::has_operator_equal_v<PropertyType>) {
0190 if (newValue == propertyPtr->valueBypassingBindings())
0191 return false;
0192 }
0193 propertyPtr->setValueBypassingBindings(std::move(newValue));
0194 return true;
0195 } else {
0196
0197 Q_UNREACHABLE_RETURN(false);
0198 }
0199 },
0200 [](void *f){ static_cast<Callable *>(f)->~Callable(); },
0201 [](void *addr, void *other){
0202 new (addr) Callable(std::move(*static_cast<Callable *>(other)));
0203 },
0204 sizeof(Callable)
0205 };
0206 }
0207 };
0208
0209 template<typename Callable, typename PropertyType=MSVCWorkAround>
0210 inline constexpr BindingFunctionVTable bindingFunctionVTable = BindingFunctionVTable::createFor<Callable, PropertyType>();
0211
0212
0213
0214 struct QPropertyBindingFunction {
0215 const QtPrivate::BindingFunctionVTable *vtable;
0216 void *functor;
0217 };
0218
0219 using QPropertyObserverCallback = void (*)(QUntypedPropertyData *);
0220 using QPropertyBindingWrapper = bool(*)(QMetaType, QUntypedPropertyData *dataPtr, QPropertyBindingFunction);
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232 class Q_CORE_EXPORT QPropertyBindingData
0233 {
0234
0235
0236 mutable quintptr d_ptr = 0;
0237 friend struct QT_PREPEND_NAMESPACE(QPropertyBindingDataPointer);
0238 friend class QT_PREPEND_NAMESPACE(QQmlPropertyBinding);
0239 friend struct QT_PREPEND_NAMESPACE(QPropertyDelayedNotifications);
0240
0241 template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
0242 friend class QT_PREPEND_NAMESPACE(QObjectCompatProperty);
0243
0244 Q_DISABLE_COPY(QPropertyBindingData)
0245 public:
0246 QPropertyBindingData() = default;
0247 QPropertyBindingData(QPropertyBindingData &&other);
0248 QPropertyBindingData &operator=(QPropertyBindingData &&other) = delete;
0249 ~QPropertyBindingData();
0250
0251
0252 static inline constexpr quintptr BindingBit = 0x1;
0253
0254 static inline constexpr quintptr DelayedNotificationBit = 0x2;
0255
0256 bool hasBinding() const { return d_ptr & BindingBit; }
0257 bool isNotificationDelayed() const { return d_ptr & DelayedNotificationBit; }
0258
0259 QUntypedPropertyBinding setBinding(const QUntypedPropertyBinding &newBinding,
0260 QUntypedPropertyData *propertyDataPtr,
0261 QPropertyObserverCallback staticObserverCallback = nullptr,
0262 QPropertyBindingWrapper bindingWrapper = nullptr);
0263
0264 QPropertyBindingPrivate *binding() const
0265 {
0266 quintptr dd = d();
0267 if (dd & BindingBit)
0268 return reinterpret_cast<QPropertyBindingPrivate*>(dd - BindingBit);
0269 return nullptr;
0270
0271 }
0272
0273 void evaluateIfDirty(const QUntypedPropertyData *) const;
0274
0275 void removeBinding()
0276 {
0277 if (hasBinding())
0278 removeBinding_helper();
0279 }
0280
0281 void registerWithCurrentlyEvaluatingBinding(QtPrivate::BindingEvaluationState *currentBinding) const
0282 {
0283 if (!currentBinding)
0284 return;
0285 registerWithCurrentlyEvaluatingBinding_helper(currentBinding);
0286 }
0287 void registerWithCurrentlyEvaluatingBinding() const;
0288 void notifyObservers(QUntypedPropertyData *propertyDataPtr) const;
0289 void notifyObservers(QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage) const;
0290 private:
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302 quintptr &d_ref() const
0303 {
0304 quintptr &d = d_ptr;
0305 if (isNotificationDelayed())
0306 return proxyData()->d_ptr;
0307 return d;
0308 }
0309 quintptr d() const { return d_ref(); }
0310 QPropertyProxyBindingData *proxyData() const
0311 {
0312 Q_ASSERT(isNotificationDelayed());
0313 return reinterpret_cast<QPropertyProxyBindingData *>(d_ptr & ~(BindingBit|DelayedNotificationBit));
0314 }
0315 void registerWithCurrentlyEvaluatingBinding_helper(BindingEvaluationState *currentBinding) const;
0316 void removeBinding_helper();
0317
0318 enum NotificationResult { Delayed, Evaluated };
0319 NotificationResult notifyObserver_helper(
0320 QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage,
0321 QPropertyObserverPointer observer,
0322 PendingBindingObserverList &bindingObservers) const;
0323 };
0324
0325 template <typename T, typename Tag>
0326 class QTagPreservingPointerToPointer
0327 {
0328 public:
0329 constexpr QTagPreservingPointerToPointer() = default;
0330
0331 QTagPreservingPointerToPointer(T **ptr)
0332 : d(reinterpret_cast<quintptr*>(ptr))
0333 {}
0334
0335 QTagPreservingPointerToPointer<T, Tag> &operator=(T **ptr)
0336 {
0337 d = reinterpret_cast<quintptr *>(ptr);
0338 return *this;
0339 }
0340
0341 QTagPreservingPointerToPointer<T, Tag> &operator=(QTaggedPointer<T, Tag> *ptr)
0342 {
0343 d = reinterpret_cast<quintptr *>(ptr);
0344 return *this;
0345 }
0346
0347 void clear()
0348 {
0349 d = nullptr;
0350 }
0351
0352 void setPointer(T *ptr)
0353 {
0354 *d = reinterpret_cast<quintptr>(ptr) | (*d & QTaggedPointer<T, Tag>::tagMask());
0355 }
0356
0357 T *get() const
0358 {
0359 return reinterpret_cast<T*>(*d & QTaggedPointer<T, Tag>::pointerMask());
0360 }
0361
0362 explicit operator bool() const
0363 {
0364 return d != nullptr;
0365 }
0366
0367 private:
0368 quintptr *d = nullptr;
0369 };
0370
0371 namespace detail {
0372 template <typename F>
0373 struct ExtractClassFromFunctionPointer;
0374
0375 template<typename T, typename C>
0376 struct ExtractClassFromFunctionPointer<T C::*> { using Class = C; };
0377
0378 constexpr size_t getOffset(size_t o)
0379 {
0380 return o;
0381 }
0382 constexpr size_t getOffset(size_t (*offsetFn)())
0383 {
0384 return offsetFn();
0385 }
0386 }
0387
0388 }
0389
0390 QT_END_NAMESPACE
0391
0392 #endif