File indexing completed on 2025-01-18 10:07:34
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
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
0037
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
0138 namespace QtPrivate {
0139 class QPropertyBindingData;
0140 }
0141 struct QPropertyDelayedNotifications;
0142 struct QPropertyProxyBindingData
0143 {
0144
0145 quintptr d_ptr;
0146
0147
0148
0149
0150
0151 const QtPrivate::QPropertyBindingData *originalBindingData;
0152 QUntypedPropertyData *propertyData;
0153 };
0154
0155 namespace QtPrivate {
0156 struct BindingEvaluationState;
0157
0158
0159
0160
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 [](QMetaType metaType, QUntypedPropertyData *dataPtr, void *f){
0180 if constexpr (!std::is_invocable_v<Callable>) {
0181
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
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
0199 Q_UNREACHABLE_RETURN(false);
0200 }
0201 },
0202 [](void *f){ static_cast<Callable *>(f)->~Callable(); },
0203 [](void *addr, void *other){
0204 new (addr) Callable(std::move(*static_cast<Callable *>(other)));
0205 },
0206 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
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
0226
0227
0228
0229
0230
0231
0232
0233
0234 class Q_CORE_EXPORT QPropertyBindingData
0235 {
0236
0237
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
0254 static inline constexpr quintptr BindingBit = 0x1;
0255
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;
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
0295
0296
0297
0298
0299
0300
0301
0302
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 }
0391
0392 QT_END_NAMESPACE
0393
0394 #endif