123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 | // Copyright (C) 2020 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#ifndef QPROPERTYPRIVATE_H#define QPROPERTYPRIVATE_H//// W A R N I N G// -------------//// This file is not part of the Qt API. It exists purely as an// implementation detail. This header file may change from version to// version without notice, or even be removed.//// We mean it.//#include <QtCore/qglobal.h>#include <QtCore/qtaggedpointer.h>#include <QtCore/qmetatype.h>#include <QtCore/qcontainerfwd.h>#include <QtCore/qttypetraits.h>#include <functional> QT_BEGIN_NAMESPACE class QBindingStorage;template<typename Class, typename T,auto Offset,auto Setter,auto Signal,auto Getter>class QObjectCompatProperty;class QPropertyBindingPrivatePtr;using PendingBindingObserverList = QVarLengthArray<QPropertyBindingPrivatePtr>;namespace QtPrivate {// QPropertyBindingPrivatePtr operates on a RefCountingMixin solely so that we can inline// the constructor and copy constructorstruct RefCounted {intrefCount()const{return ref; }voidaddRef() { ++ref; }boolderef() {return--ref !=0; }private:int ref =0;};}class QQmlPropertyBinding;class QPropertyBindingPrivate;class QPropertyBindingPrivatePtr {public:using T =QtPrivate::RefCounted; T &operator*()const{return*d; } T *operator->() noexcept {return d; } T *operator->()const noexcept {return d; }explicit operator T *() {return d; }explicit operatorconst T *()const noexcept {return d; } T *data()const noexcept {return d; } T *get()const noexcept {return d; }const T *constData()const noexcept {return d; } T *take() noexcept { T *x = d; d =nullptr;return x; }QPropertyBindingPrivatePtr() noexcept :d(nullptr) { }~QPropertyBindingPrivatePtr(){if(d && !d->deref())destroyAndFreeMemory();} Q_CORE_EXPORT voiddestroyAndFreeMemory();explicitQPropertyBindingPrivatePtr(T *data) noexcept :d(data) {if(d) d->addRef(); }QPropertyBindingPrivatePtr(const QPropertyBindingPrivatePtr &o) noexcept :d(o.d) {if(d) d->addRef(); }voidreset(T *ptr =nullptr) noexcept; QPropertyBindingPrivatePtr &operator=(const QPropertyBindingPrivatePtr &o) noexcept {reset(o.d);return*this;} QPropertyBindingPrivatePtr &operator=(T *o) noexcept {reset(o);return*this;}QPropertyBindingPrivatePtr(QPropertyBindingPrivatePtr &&o) noexcept :d(std::exchange(o.d,nullptr)) {}QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QPropertyBindingPrivatePtr)operatorbool()const noexcept {return d !=nullptr; }booloperator!()const noexcept {return d ==nullptr; }voidswap(QPropertyBindingPrivatePtr &other) noexcept {qt_ptr_swap(d, other.d); }private:friendboolcomparesEqual(const QPropertyBindingPrivatePtr &lhs,const QPropertyBindingPrivatePtr &rhs) noexcept {return lhs.d == rhs.d; }Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr)friendboolcomparesEqual(const QPropertyBindingPrivatePtr &lhs,const T *rhs) noexcept {return lhs.d == rhs; }Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr, T*)friendboolcomparesEqual(const QPropertyBindingPrivatePtr &lhs,std::nullptr_t) noexcept {return!lhs; }Q_DECLARE_EQUALITY_COMPARABLE(QPropertyBindingPrivatePtr,std::nullptr_t)QtPrivate::RefCounted *d;};class QUntypedPropertyBinding;class QPropertyBindingPrivate;struct QPropertyBindingDataPointer;class QPropertyObserver;struct QPropertyObserverPointer;class QUntypedPropertyData {};namespace QtPrivate {template<typename T>using IsUntypedPropertyData =std::enable_if_t<std::is_base_of_v<QUntypedPropertyData, T>,bool>;}template<typename T>class QPropertyData;// Used for grouped property evaluationsnamespace QtPrivate {class QPropertyBindingData;}struct QPropertyDelayedNotifications;struct QPropertyProxyBindingData {// acts as QPropertyBindingData::d_ptr quintptr d_ptr;/* The two members below store the original binding data and property data pointer of the property which gets proxied. They are set in QPropertyDelayedNotifications::addProperty */constQtPrivate::QPropertyBindingData *originalBindingData; QUntypedPropertyData *propertyData;};namespace QtPrivate {struct BindingEvaluationState;/* used in BindingFunctionVTable::createFor; on all other compilers, void would work, but on MSVC this causes C2182 when compiling in C++20 mode. As we only need to provide some default value which gets ignored, we introduce this dummy type.*/struct MSVCWorkAround {};struct BindingFunctionVTable {using CallFn =bool(*)(QMetaType, QUntypedPropertyData *,void*);using DtorFn =void(*)(void*);using MoveCtrFn =void(*)(void*,void*);const CallFn call;const DtorFn destroy;const MoveCtrFn moveConstruct;const qsizetype size;template<typename Callable, typename PropertyType=MSVCWorkAround>staticconstexpr BindingFunctionVTable createFor(){static_assert(alignof(Callable) <=alignof(std::max_align_t),"Bindings do not support overaligned functors!");return{/*call=*/[](QMetaType metaType, QUntypedPropertyData *dataPtr,void*f){ifconstexpr(!std::is_invocable_v<Callable>) {// we got an untyped callablestatic_assert(std::is_invocable_r_v<bool, Callable, QMetaType, QUntypedPropertyData *> );auto untypedEvaluationFunction =static_cast<Callable *>(f);returnstd::invoke(*untypedEvaluationFunction, metaType, dataPtr);}else ifconstexpr(!std::is_same_v<PropertyType, MSVCWorkAround>) {Q_UNUSED(metaType); QPropertyData<PropertyType> *propertyPtr =static_cast<QPropertyData<PropertyType> *>(dataPtr);// That is allowed by POSIX even if Callable is a function pointerauto evaluationFunction =static_cast<Callable *>(f); PropertyType newValue =std::invoke(*evaluationFunction);ifconstexpr(QTypeTraits::has_operator_equal_v<PropertyType>) {if(newValue == propertyPtr->valueBypassingBindings())return false;} propertyPtr->setValueBypassingBindings(std::move(newValue));return true;}else{// Our code will never instantiate thisQ_UNREACHABLE_RETURN(false);}},/*destroy*/[](void*f){static_cast<Callable *>(f)->~Callable(); },/*moveConstruct*/[](void*addr,void*other){new(addr)Callable(std::move(*static_cast<Callable *>(other)));},/*size*/sizeof(Callable)};}};template<typename Callable, typename PropertyType=MSVCWorkAround>inline constexpr BindingFunctionVTable bindingFunctionVTable =BindingFunctionVTable::createFor<Callable, PropertyType>();// writes binding result into dataPtrstruct QPropertyBindingFunction {constQtPrivate::BindingFunctionVTable *vtable;void*functor;};using QPropertyObserverCallback =void(*)(QUntypedPropertyData *);using QPropertyBindingWrapper =bool(*)(QMetaType, QUntypedPropertyData *dataPtr, QPropertyBindingFunction);/*! \internal A property normally consists of the actual property value and metadata for the binding system. QPropertyBindingData is the latter part. It stores a pointer to either - a (potentially empty) linked list of notifiers, in case there is no binding set, - an actual QUntypedPropertyBinding when the property has a binding, - or a pointer to QPropertyProxyBindingData when notifications occur inside a grouped update. \sa QPropertyDelayedNotifications, beginPropertyUpdateGroup */class Q_CORE_EXPORT QPropertyBindingData {// Mutable because the address of the observer of the currently evaluating binding is stored here, for// notification later when the value changes.mutable quintptr d_ptr =0;friendstructQT_PREPEND_NAMESPACE(QPropertyBindingDataPointer);friend classQT_PREPEND_NAMESPACE(QQmlPropertyBinding);friendstructQT_PREPEND_NAMESPACE(QPropertyDelayedNotifications);template<typename Class, typename T,auto Offset,auto Setter,auto Signal,auto Getter>friend classQT_PREPEND_NAMESPACE(QObjectCompatProperty);Q_DISABLE_COPY(QPropertyBindingData)public:QPropertyBindingData() =default;QPropertyBindingData(QPropertyBindingData &&other); QPropertyBindingData &operator=(QPropertyBindingData &&other) =delete;~QPropertyBindingData();// Is d_ptr pointing to a binding (1) or list of notifiers (0)?staticinline constexpr quintptr BindingBit =0x1;// Is d_ptr pointing to QPropertyProxyBindingData (1) or to an actual binding/list of notifiers?staticinline constexpr quintptr DelayedNotificationBit =0x2;boolhasBinding()const{return d_ptr & BindingBit; }boolisNotificationDelayed()const{return d_ptr & DelayedNotificationBit; } QUntypedPropertyBinding setBinding(const QUntypedPropertyBinding &newBinding, QUntypedPropertyData *propertyDataPtr, QPropertyObserverCallback staticObserverCallback =nullptr, QPropertyBindingWrapper bindingWrapper =nullptr); QPropertyBindingPrivate *binding()const{ quintptr dd =d();if(dd & BindingBit)return reinterpret_cast<QPropertyBindingPrivate*>(dd - BindingBit);returnnullptr;}voidevaluateIfDirty(const QUntypedPropertyData *)const;// ### Kept for BC reasons, unusedvoidremoveBinding(){if(hasBinding())removeBinding_helper();}voidregisterWithCurrentlyEvaluatingBinding(QtPrivate::BindingEvaluationState *currentBinding)const{if(!currentBinding)return;registerWithCurrentlyEvaluatingBinding_helper(currentBinding);}voidregisterWithCurrentlyEvaluatingBinding()const;voidnotifyObservers(QUntypedPropertyData *propertyDataPtr)const;voidnotifyObservers(QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage)const;private:/*! \internal Returns a reference to d_ptr, except when d_ptr points to a proxy. In that case, a reference to proxy->d_ptr is returned instead. To properly support proxying, direct access to d_ptr only occurs when - a function actually deals with proxying (e.g. QPropertyDelayedNotifications::addProperty), - only the tag value is accessed (e.g. hasBinding) or - inside a constructor. */ quintptr &d_ref()const{ quintptr &d = d_ptr;if(isNotificationDelayed())returnproxyData()->d_ptr;return d;} quintptr d()const{returnd_ref(); } QPropertyProxyBindingData *proxyData()const{Q_ASSERT(isNotificationDelayed());return reinterpret_cast<QPropertyProxyBindingData *>(d_ptr & ~(BindingBit|DelayedNotificationBit));}voidregisterWithCurrentlyEvaluatingBinding_helper(BindingEvaluationState *currentBinding)const;voidremoveBinding_helper();enum NotificationResult { Delayed, Evaluated }; NotificationResult notifyObserver_helper( QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage, QPropertyObserverPointer observer, PendingBindingObserverList &bindingObservers)const;};template<typename T, typename Tag>class QTagPreservingPointerToPointer {public:constexprQTagPreservingPointerToPointer() =default;QTagPreservingPointerToPointer(T **ptr):d(reinterpret_cast<quintptr*>(ptr)){} QTagPreservingPointerToPointer<T, Tag> &operator=(T **ptr){ d =reinterpret_cast<quintptr *>(ptr);return*this;} QTagPreservingPointerToPointer<T, Tag> &operator=(QTaggedPointer<T, Tag> *ptr){ d =reinterpret_cast<quintptr *>(ptr);return*this;}voidclear(){ d =nullptr;}voidsetPointer(T *ptr){*d =reinterpret_cast<quintptr>(ptr) | (*d & QTaggedPointer<T, Tag>::tagMask());} T *get()const{return reinterpret_cast<T*>(*d & QTaggedPointer<T, Tag>::pointerMask());}explicit operatorbool()const{return d !=nullptr;}private: quintptr *d =nullptr;};namespace detail {template<typename F>struct ExtractClassFromFunctionPointer;template<typename T, typename C>struct ExtractClassFromFunctionPointer<T C::*> {using Class = C; };constexprsize_tgetOffset(size_t o){return o;}constexprsize_tgetOffset(size_t(*offsetFn)()){returnoffsetFn();}}}// namespace QtPrivate QT_END_NAMESPACE #endif// QPROPERTYPRIVATE_H
|