18#include <private/qglobal_p.h>
21#include <qmetaobject.h>
22#include <qscopedvaluerollback.h>
25#include <QtCore/QVarLengthArray>
38
39
40
41
42
46 QPropertyObserver *d =
nullptr;
59 inline QPropertyObserver *
operator ->();
62using PendingBindingObserverList = QVarLengthArray<QPropertyBindingPrivatePtr>;
74 return ptr->binding();
79 auto &d = ptr->d_ref();
80 observer->prev =
reinterpret_cast<QPropertyObserver**>(&d);
81 d =
reinterpret_cast<quintptr>(observer);
116 QPropertyObserver *
next()
const {
return m_placeHolder.next.data(); }
124 QPropertyObserver *
ptr =
nullptr;
129#if QT_DEPRECATED_SINCE(6
, 6
)
130 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
131 if (ptr->next.tag() == QPropertyObserver::ObserverIsAlias)
132 ptr->aliasData =
nullptr;
139#if QT_DEPRECATED_SINCE(6
, 6
)
140 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
141 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsAlias);
149 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsPlaceholder);
150 ptr->binding = binding;
151 ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding);
159 void notify(QUntypedPropertyData *propertyDataPtr);
165 void evaluateBindings(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
174 Q_ASSERT(ptr->next.tag() == QPropertyObserver::ObserverNotifiesBinding);
182 ptr->next->prev =
ptr->prev;
184 ptr->prev.setPointer(
ptr->next.data());
214
215
216
217
218
219
236
237
238
239
240
241
259 friend struct QPropertyBindingDataPointer;
260 friend class QPropertyBindingPrivatePtr;
262 using ObserverArray = std::array<QPropertyObserver, 4>;
267 bool updating =
false;
268 bool hasStaticObserver =
false;
269 bool pendingNotify =
false;
270 bool hasBindingWrapper:1;
272 bool isQQmlPropertyBinding:1;
274
275
276
279 const QtPrivate::BindingFunctionVTable *vtable;
282 QtPrivate::QPropertyObserverCallback staticObserverCallback =
nullptr;
283 QtPrivate::QPropertyBindingWrapper staticBindingWrapper;
285 ObserverArray inlineDependencyObservers;
287 QPropertyObserverPointer firstObserver;
288 std::unique_ptr<std::vector<QPropertyObserver>> heapObservers;
291 QUntypedPropertyData *propertyDataPtr =
nullptr;
294
295
296
297
298
299
300 using DeclarativeErrorCallback =
void(*)(QPropertyBindingPrivate *);
302 QPropertyBindingSourceLocation location;
304 std::byte declarativeExtraData[
sizeof(QPropertyBindingSourceLocation) -
sizeof(DeclarativeErrorCallback)];
305 DeclarativeErrorCallback errorCallBack;
309 QPropertyBindingError m_error;
314 static constexpr size_t getSizeEnsuringAlignment() {
315 constexpr auto align =
alignof (std::max_align_t) - 1;
316 constexpr size_t sizeEnsuringAlignment = (
sizeof(QPropertyBindingPrivate) + align) & ~align;
317 static_assert (sizeEnsuringAlignment %
alignof (std::max_align_t) == 0,
318 "Required for placement new'ing the function behind it.");
319 return sizeEnsuringAlignment;
324 size_t dependencyObserverCount = 0;
326 bool isUpdating() {
return updating;}
327 void setSticky(
bool keep =
true) {m_sticky = keep;}
328 bool isSticky() {
return m_sticky;}
329 void scheduleNotify() {pendingNotify =
true;}
331 QPropertyBindingPrivate(QMetaType metaType,
const QtPrivate::BindingFunctionVTable *vtable,
332 const QPropertyBindingSourceLocation &location,
bool isQQmlPropertyBinding=
false)
333 : hasBindingWrapper(
false)
334 , isQQmlPropertyBinding(isQQmlPropertyBinding)
340 ~QPropertyBindingPrivate();
343 void setProperty(QUntypedPropertyData *propertyPtr) { propertyDataPtr = propertyPtr; }
344 void setStaticObserver(QtPrivate::QPropertyObserverCallback callback, QtPrivate::QPropertyBindingWrapper bindingWrapper)
346 Q_ASSERT(!(callback && bindingWrapper));
348 hasStaticObserver =
true;
349 hasBindingWrapper =
false;
350 staticObserverCallback = callback;
351 }
else if (bindingWrapper) {
352 hasStaticObserver =
false;
353 hasBindingWrapper =
true;
354 staticBindingWrapper = bindingWrapper;
356 hasStaticObserver =
false;
357 hasBindingWrapper =
false;
358 staticObserverCallback =
nullptr;
361 void prependObserver(QPropertyObserverPointer observer)
363 observer.ptr->prev =
const_cast<QPropertyObserver **>(&firstObserver.ptr);
364 firstObserver = observer;
367 QPropertyObserverPointer takeObservers()
369 auto observers = firstObserver;
370 firstObserver.ptr =
nullptr;
374 void clearDependencyObservers();
376 Q_ALWAYS_INLINE QPropertyObserverPointer allocateDependencyObserver() {
377 if (dependencyObserverCount < inlineDependencyObservers.size()) {
378 ++dependencyObserverCount;
379 return {&inlineDependencyObservers[dependencyObserverCount - 1]};
381 return allocateDependencyObserver_slow();
384 QPropertyObserverPointer allocateDependencyObserver_slow();
386 QPropertyBindingSourceLocation sourceLocation()
const
388 if (!hasCustomVTable())
391 constexpr auto msg =
"Custom location";
392 QPropertyBindingSourceLocation result;
393 result.fileName = msg;
397 QPropertyBindingError bindingError()
const {
return m_error; }
398 QMetaType valueMetaType()
const {
return metaType; }
400 void unlinkAndDeref();
402 bool evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status =
nullptr);
404 Q_ALWAYS_INLINE
bool evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
406 void notifyNonRecursive(
const PendingBindingObserverList &bindingObservers);
407 enum NotificationState :
bool { Delayed, Sent };
408 NotificationState notifyNonRecursive();
410 static QPropertyBindingPrivate *get(
const QUntypedPropertyBinding &binding)
411 {
return static_cast<QPropertyBindingPrivate *>(binding.d.data()); }
413 void setError(QPropertyBindingError &&e)
414 { m_error = std::move(e); }
416 void detachFromProperty()
418 hasStaticObserver =
false;
419 hasBindingWrapper =
false;
420 propertyDataPtr =
nullptr;
421 clearDependencyObservers();
424 static QPropertyBindingPrivate *currentlyEvaluatingBinding();
426 bool hasCustomVTable()
const
428 return vtable->size == 0;
431 static void destroyAndFreeMemory(QPropertyBindingPrivate *priv) {
432 if (priv->hasCustomVTable()) {
435 priv->vtable->destroy(priv);
437 priv->~QPropertyBindingPrivate();
438 delete[]
reinterpret_cast<std::byte *>(priv);
445 if (
auto *b = binding()) {
446 b->firstObserver.ptr = observer;
449 auto &d = ptr->d_ref();
450 d =
reinterpret_cast<quintptr>(observer);
455 auto &d = ptr->d_ref();
456 if (ptr->isNotificationDelayed()) {
457 QPropertyProxyBindingData *proxy = ptr->proxyData();
459 proxy->originalBindingData = ptr;
464 if (d & QtPrivate::QPropertyBindingData::BindingBit)
466 if (
auto observer =
reinterpret_cast<QPropertyObserver *>(d))
467 observer->prev =
reinterpret_cast<QPropertyObserver **>(&d);
472 if (
auto *b = binding())
473 return b->firstObserver;
474 return {
reinterpret_cast<QPropertyObserver *>(ptr->d()) };
478
479
480
483 if (!ptr->isNotificationDelayed())
485 return ptr->proxyData();
501template<
typename Class,
typename T,
auto Offset,
auto Setter,
auto Signal =
nullptr,
502 auto Getter =
nullptr>
505 template<
typename Property,
typename>
509 using SignalTakesValue =
std::is_invocable<
decltype(Signal), Class, T>;
512 char *that =
reinterpret_cast<
char *>(
this);
513 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
515 const Class *owner()
const
517 char *that =
const_cast<
char *>(
reinterpret_cast<
const char *>(
this));
518 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
521 static bool bindingWrapper(QMetaType type, QUntypedPropertyData *dataPtr, QtPrivate::QPropertyBindingFunction binding)
523 auto *thisData =
static_cast<ThisType *>(dataPtr);
524 QBindingStorage *storage = qGetBindingStorage(thisData->owner());
528 if (!binding.vtable->call(type, ©, binding.functor))
533 (thisData->owner()->*Setter)(copy.valueBypassingBindings());
536 bool inBindingWrapper(
const QBindingStorage *storage)
const
538 return storage->bindingStatus && storage->bindingStatus->currentCompatProperty
539 && QtPrivate::isPropertyInBindingWrapper(
this);
542 inline static T getPropertyValue(
const QUntypedPropertyData *d) {
543 auto prop =
static_cast<
const ThisType *>(d);
544 if constexpr (
std::is_null_pointer_v<
decltype(Getter)>)
545 return prop->value();
547 return (prop->owner()->*Getter)();
561 const QBindingStorage *storage = qGetBindingStorage(owner());
563 if (storage->bindingStatus && storage->bindingStatus->currentlyEvaluatingBinding && !inBindingWrapper(storage))
564 storage->registerDependency_helper(
this);
570 if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
572 }
else if constexpr (
std::is_pointer_v<T>) {
592 QBindingStorage *storage = qGetBindingStorage(owner());
593 if (
auto *bd = storage->bindingData(
this)) {
595 if (bd->hasBinding() && !inBindingWrapper(storage))
596 bd->removeBinding_helper();
609 QtPrivate::QPropertyBindingData *bd = qGetBindingStorage(owner())->bindingData(
this,
true);
612 return static_cast<QPropertyBinding<T> &>(oldBinding);
617 if (!newBinding.isNull() && newBinding.valueMetaType() != QMetaType::fromType<T>())
624 template <
typename Functor>
627 std::enable_if_t<std::is_invocable_v<Functor>> * =
nullptr)
637 auto *bd = qGetBindingStorage(owner())->bindingData(
this);
638 return bd && bd->binding() !=
nullptr;
643 QBindingStorage *storage = qGetBindingStorage(owner());
644 if (
auto *bd = storage->bindingData(
this)) {
646 if (bd->hasBinding() && !inBindingWrapper(storage))
647 bd->removeBinding_helper();
653 QBindingStorage *storage = qGetBindingStorage(owner());
654 if (
auto bd = storage->bindingData(
this,
false)) {
658 if (!bd->isNotificationDelayed()) {
661 if (!inBindingWrapper(storage)) {
662 PendingBindingObserverList bindingObservers;
663 if (bd->notifyObserver_helper(
this, storage, observer, bindingObservers)
664 == QtPrivate::QPropertyBindingData::Evaluated) {
668 bd = storage->bindingData(
this,
false);
672 for (
auto&& bindingPtr: bindingObservers) {
673 auto *binding =
static_cast<QPropertyBindingPrivate *>(bindingPtr.get());
674 binding->notifyNonRecursive();
681 if constexpr (!
std::is_null_pointer_v<
decltype(Signal)>) {
682 if constexpr (SignalTakesValue::value)
683 (owner()->*Signal)(getPropertyValue(
this));
685 (owner()->*Signal)();
691 auto *bd = qGetBindingStorage(owner())->bindingData(
this);
692 return static_cast<
QPropertyBinding<T> &&>(QUntypedPropertyBinding(bd ? bd->binding() :
nullptr));
700 template<
typename Functor>
703 static_assert(
std::is_invocable_v<Functor>,
"Functor callback must be callable without any parameters");
707 template<
typename Functor>
710 static_assert(
std::is_invocable_v<Functor>,
"Functor callback must be callable without any parameters");
712 return onValueChanged(f);
715 template<
typename Functor>
718 static_assert(
std::is_invocable_v<Functor>,
"Functor callback must be callable without any parameters");
724 auto *storage =
const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
757#define QT_OBJECT_COMPAT_PROPERTY_4(Class, Type, name, setter)
758 static constexpr size_t _qt_property_##name##_offset() {
759 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
760 return offsetof(Class, name);
763 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter> name;
765#define QT_OBJECT_COMPAT_PROPERTY_5(Class, Type, name, setter, signal)
766 static constexpr size_t _qt_property_##name##_offset() {
767 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
768 return offsetof(Class, name);
771 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal> name;
773#define Q_OBJECT_COMPAT_PROPERTY(...)
774 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
775 QT_OVERLOADED_MACRO(QT_OBJECT_COMPAT_PROPERTY, __VA_ARGS__)
778#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_5(Class, Type, name, setter, value)
779 static constexpr size_t _qt_property_##name##_offset() {
780 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
781 return offsetof(Class, name);
784 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter> name =
785 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter>(
788#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_6(Class, Type, name, setter, signal, value)
789 static constexpr size_t _qt_property_##name##_offset() {
790 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
791 return offsetof(Class, name);
794 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal> name =
795 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter,
798#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_7(Class, Type, name, setter, signal, getter, value)
799 static constexpr size_t _qt_property_##name##_offset() {
800 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
801 return offsetof(Class, name);
804 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal, getter>
805 name = QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter,
806 signal, getter>(value);
808#define Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(...)
809 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
810 QT_OVERLOADED_MACRO(QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS, __VA_ARGS__)
828 return bindable.data;
832inline bool QPropertyBindingPrivate::evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
835 m_error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
836 if (isQQmlPropertyBinding)
842
843
844
845
846
847
848
849 QPropertyBindingPrivatePtr keepAlive {
this};
851 QScopedValueRollback<
bool> updateGuard(updating,
true);
853 QtPrivate::BindingEvaluationState evaluationFrame(
this, status);
855 auto bindingFunctor =
reinterpret_cast<std::byte *>(
this) +
856 QPropertyBindingPrivate::getSizeEnsuringAlignment();
857 bool changed =
false;
858 if (hasBindingWrapper) {
859 changed = staticBindingWrapper(metaType, propertyDataPtr,
860 {vtable, bindingFunctor});
862 changed = vtable->call(metaType, propertyDataPtr, bindingFunctor);
866 pendingNotify = pendingNotify || changed;
867 if (!changed || !firstObserver)
870 firstObserver.noSelfDependencies(
this);
871 firstObserver.evaluateBindings(bindingObservers, status);
876
877
878
879
880
881
882
885 auto observer =
const_cast<QPropertyObserver*>(
ptr);
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
904 QPropertyObserver *next = observer->next.data();
905 switch (QPropertyObserver::ObserverTag(observer->next.tag())) {
906 case QPropertyObserver::ObserverNotifiesChangeHandler:
908 auto handlerToCall = observer->changeHandler;
910 if (next && next->next.tag() == QPropertyObserver::ObserverIsPlaceholder) {
911 observer = next->next.data();
916 handlerToCall(observer, propertyDataPtr);
920 case QPropertyObserver::ObserverNotifiesBinding:
922 case QPropertyObserver::ObserverIsPlaceholder:
925#if QT_DEPRECATED_SINCE(6
, 6
)
926 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
927 case QPropertyObserver::ObserverIsAlias:
931 default: Q_UNREACHABLE();
954 QPropertyBindingPrivate *bindingPrivate = binding();
955 if (!bindingPrivate->deref())
956 QPropertyBindingPrivate::destroyAndFreeMemory(bindingPrivate);
966 QPropertyBindingData bindingData_;
968 QMetaProperty metaProperty_;
970#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
973 static void impl(QSlotObjectBase *this_, QObject *r,
void **a,
int which,
bool *ret);
976 QPropertyAdaptorSlotObject(QObject *o,
const QMetaProperty& p);
981 if (ptr->isImpl(&QPropertyAdaptorSlotObject::impl)) {
983 if (p->metaProperty_.propertyIndex() == propertyIndex)
\macro Q_OBJECT_BINDABLE_PROPERTY(containingClass, type, name, signal)
QPropertyBinding< T > binding() const
operator parameter_type() const
typename QPropertyData< T >::value_type value_type
QtPrivate::QPropertyBindingData & bindingData() const
QObjectCompatProperty & operator=(parameter_type newValue)
typename QPropertyData< T >::arrow_operator_result arrow_operator_result
typename QPropertyData< T >::parameter_type parameter_type
parameter_type value() const
QObjectCompatProperty()=default
QPropertyChangeHandler< Functor > onValueChanged(Functor f)
void setValue(parameter_type t)
void removeBindingUnlessInWrapper()
bool setBinding(const QUntypedPropertyBinding &newBinding)
QPropertyBinding< T > setBinding(Functor &&f, const QPropertyBindingSourceLocation &location=QT_PROPERTY_DEFAULT_BINDING_LOCATION, std::enable_if_t< std::is_invocable_v< Functor > > *=nullptr)
arrow_operator_result operator->() const
QObjectCompatProperty(T &&initialValue)
QPropertyNotifier addNotifier(Functor f)
parameter_type operator*() const
QObjectCompatProperty(const T &initialValue)
QPropertyBinding< T > takeBinding()
QPropertyChangeHandler< Functor > subscribe(Functor f)
QPropertyBinding< T > setBinding(const QPropertyBinding< T > &newBinding)
~QTimerPrivate() override
QTimerPrivate(QTimer *qq)
void setIntervalDuration(std::chrono::nanoseconds nsec)
static constexpr int INV_TIMER
void setInterval(int msec)
QTimerPrivate(std::chrono::nanoseconds nsec, QChronoTimer *qq)
const QtPrivate::QBindableInterface * iface
QPrivateSlotObject(Func f)
QPropertyBindingData & bindingData()
friend class QT_PREPEND_NAMESPACE(QUntypedBindable)
const QMetaProperty & metaProperty() const
static QPropertyAdaptorSlotObject * cast(QSlotObjectBase *ptr, int propertyIndex)
const QPropertyBindingData & bindingData() const
void assertObjectType(QObjectPrivate *d)
Q_CORE_EXPORT bool isAnyBindingEvaluating()
Q_CORE_EXPORT void restoreBindingStatus(BindingEvaluationState *status)
const QObject * getQObject(const QObjectPrivate *d)
Q_CORE_EXPORT bool isPropertyInBindingWrapper(const QUntypedPropertyData *property)
#define QT_CONCAT(B, M, m, u)
QBindingStorage * qGetBindingStorage(QObjectPrivate *o)
QBindingStorage * qGetBindingStorage(QObjectPrivate::ExtraData *ed)
const QBindingStorage * qGetBindingStorage(const QObjectPrivate *o)
#define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...)
#define QT_PROPERTY_DEFAULT_BINDING_LOCATION
#define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...)
#define Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(...)
QBindingObserverPtr()=default
QPropertyObserver * operator->()
QPropertyBindingPrivate * binding() const noexcept
static QPropertyProxyBindingData * proxyData(QtPrivate::QPropertyBindingData *ptr)
static void fixupAfterMove(QtPrivate::QPropertyBindingData *ptr)
Q_ALWAYS_INLINE void addObserver(QPropertyObserver *observer)
const QtPrivate::QPropertyBindingData * ptr
int observerCount() const
static QPropertyBindingDataPointer get(QProperty< T > &property)
QPropertyBindingPrivate * binding() const
void setObservers(QPropertyObserver *observer)
QPropertyObserverPointer firstObserver() const
void setFirstObserver(QPropertyObserver *observer)
~QPropertyObserverNodeProtector()
QPropertyObserver * next() const
void noSelfDependencies(QPropertyBindingPrivate *binding)
void notify(QUntypedPropertyData *propertyDataPtr)
QPropertyBindingPrivate * binding() const
void evaluateBindings(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
void observeProperty(QPropertyBindingDataPointer property)
QPropertyObserverPointer nextObserver() const
void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding)
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler)
void setBindingToNotify(QPropertyBindingPrivate *binding)
void(* BeginCallback)(QObject *caller, int signal_or_method_index, void **argv)
BeginCallback slot_begin_callback
EndCallback slot_end_callback
EndCallback signal_end_callback
BeginCallback signal_begin_callback
void(* EndCallback)(QObject *caller, int signal_or_method_index)
static QtPrivate::QBindableInterface const * getInterface(const QUntypedBindable &bindable)
static QUntypedPropertyData * getPropertyData(const QUntypedBindable &bindable)
QPropertyBindingPrivate * binding
QVarLengthArray< const QPropertyBindingData *, 8 > alreadyCaptureProperties
BindingEvaluationState(QPropertyBindingPrivate *binding, QBindingStatus *status)
BindingEvaluationState * previousState
~BindingEvaluationState()
BindingEvaluationState ** currentState
QtPrivate::BindingEvaluationState ** currentlyEvaluatingBindingList
CompatPropertySafePoint * previousState
CompatPropertySafePoint ** currentState
~CompatPropertySafePoint()
QUntypedPropertyData * property
QtPrivate::BindingEvaluationState * bindingState