Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qpropertyprivate.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QPROPERTYPRIVATE_H
5#define QPROPERTYPRIVATE_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/qglobal.h>
19#include <QtCore/qtaggedpointer.h>
20#include <QtCore/qmetatype.h>
21#include <QtCore/qcontainerfwd.h>
22#include <QtCore/qttypetraits.h>
23
24#include <functional>
25
26QT_BEGIN_NAMESPACE
27
28class QBindingStorage;
29
30template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
32
34using PendingBindingObserverList = QVarLengthArray<QPropertyBindingPrivatePtr>;
35
36namespace QtPrivate {
37// QPropertyBindingPrivatePtr operates on a RefCountingMixin solely so that we can inline
38// the constructor and copy constructor
39struct RefCounted {
40
41 int refCount() const { return ref; }
42 void addRef() { ++ref; }
43 bool deref() { return --ref != 0; }
44
45private:
46 int ref = 0;
47};
48}
49
50class QQmlPropertyBinding;
51class QPropertyBindingPrivate;
53{
54public:
56 T &operator*() const { return *d; }
57 T *operator->() noexcept { return d; }
58 T *operator->() const noexcept { return d; }
59 explicit operator T *() { return d; }
60 explicit operator const T *() const noexcept { return d; }
61 T *data() const noexcept { return d; }
62 T *get() const noexcept { return d; }
63 const T *constData() const noexcept { return d; }
64 T *take() noexcept { T *x = d; d = nullptr; return x; }
65
66 QPropertyBindingPrivatePtr() noexcept : d(nullptr) { }
68 {
69 if (d && !d->deref())
70 destroyAndFreeMemory();
71 }
73
74 explicit QPropertyBindingPrivatePtr(T *data) noexcept : d(data) { if (d) d->addRef(); }
76 : d(o.d) { if (d) d->addRef(); }
77
78 void reset(T *ptr = nullptr) noexcept;
79
81 {
82 reset(o.d);
83 return *this;
84 }
86 {
87 reset(o);
88 return *this;
89 }
92
93 operator bool () const noexcept { return d != nullptr; }
94 bool operator!() const noexcept { return d == nullptr; }
95
98
99private:
101 const QPropertyBindingPrivatePtr &rhs) noexcept
102 { return lhs.d == rhs.d; }
105 const T *rhs) noexcept
106 { return lhs.d == rhs; }
109 std::nullptr_t) noexcept
110 { return !lhs; }
112
114};
115
116class QUntypedPropertyBinding;
117class QPropertyBindingPrivate;
119class QPropertyObserver;
121
123{
124};
125
126namespace QtPrivate {
127template <typename T>
129}
130
131template <typename T>
132class QPropertyData;
133
134// Used for grouped property evaluations
135namespace QtPrivate {
136class QPropertyBindingData;
137}
140{
141 // acts as QPropertyBindingData::d_ptr
143 /*
144 The two members below store the original binding data and property
145 data pointer of the property which gets proxied.
146 They are set in QPropertyDelayedNotifications::addProperty
147 */
148 const QtPrivate::QPropertyBindingData *originalBindingData;
150};
151
152namespace QtPrivate {
154
155/* used in BindingFunctionVTable::createFor; on all other compilers, void would work, but on
156 MSVC this causes C2182 when compiling in C++20 mode. As we only need to provide some default
157 value which gets ignored, we introduce this dummy type.
158*/
160
162{
163 using CallFn = bool(*)(QMetaType, QUntypedPropertyData *, void *);
164 using DtorFn = void(*)(void *);
165 using MoveCtrFn = void(*)(void *, void *);
166 const CallFn call;
167 const DtorFn destroy;
168 const MoveCtrFn moveConstruct;
170
171 template<typename Callable, typename PropertyType=MSVCWorkAround>
173 {
174 static_assert (alignof(Callable) <= alignof(std::max_align_t), "Bindings do not support overaligned functors!");
175 return {
176 /*call=*/[](QMetaType metaType, QUntypedPropertyData *dataPtr, void *f){
177 if constexpr (!std::is_invocable_v<Callable>) {
178 // we got an untyped callable
179 static_assert (std::is_invocable_r_v<bool, Callable, QMetaType, QUntypedPropertyData *> );
180 auto untypedEvaluationFunction = static_cast<Callable *>(f);
181 return std::invoke(*untypedEvaluationFunction, metaType, dataPtr);
182 } else if constexpr (!std::is_same_v<PropertyType, MSVCWorkAround>) {
183 Q_UNUSED(metaType);
184 QPropertyData<PropertyType> *propertyPtr = static_cast<QPropertyData<PropertyType> *>(dataPtr);
185 // That is allowed by POSIX even if Callable is a function pointer
186 auto evaluationFunction = static_cast<Callable *>(f);
187 PropertyType newValue = std::invoke(*evaluationFunction);
188 if constexpr (QTypeTraits::has_operator_equal_v<PropertyType>) {
189 if (newValue == propertyPtr->valueBypassingBindings())
190 return false;
191 }
192 propertyPtr->setValueBypassingBindings(std::move(newValue));
193 return true;
194 } else {
195 // Our code will never instantiate this
196 Q_UNREACHABLE_RETURN(false);
197 }
198 },
199 /*destroy*/[](void *f){ static_cast<Callable *>(f)->~Callable(); },
200 /*moveConstruct*/[](void *addr, void *other){
201 new (addr) Callable(std::move(*static_cast<Callable *>(other)));
202 },
203 /*size*/sizeof(Callable)
204 };
205 }
206};
207
208template<typename Callable, typename PropertyType=MSVCWorkAround>
210
211
212// writes binding result into dataPtr
217
218using QPropertyObserverCallback = void (*)(QUntypedPropertyData *);
219using QPropertyBindingWrapper = bool(*)(QMetaType, QUntypedPropertyData *dataPtr, QPropertyBindingFunction);
220
221/*!
222 \internal
223 A property normally consists of the actual property value and metadata for the binding system.
224 QPropertyBindingData is the latter part. It stores a pointer to either
225 - a (potentially empty) linked list of notifiers, in case there is no binding set,
226 - an actual QUntypedPropertyBinding when the property has a binding,
227 - or a pointer to QPropertyProxyBindingData when notifications occur inside a grouped update.
228
229 \sa QPropertyDelayedNotifications, beginPropertyUpdateGroup
230 */
231class Q_CORE_EXPORT QPropertyBindingData
232{
233 // Mutable because the address of the observer of the currently evaluating binding is stored here, for
234 // notification later when the value changes.
235 mutable quintptr d_ptr = 0;
239
240 template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
242
244public:
249
250 // Is d_ptr pointing to a binding (1) or list of notifiers (0)?
251 static inline constexpr quintptr BindingBit = 0x1;
252 // Is d_ptr pointing to QPropertyProxyBindingData (1) or to an actual binding/list of notifiers?
253 static inline constexpr quintptr DelayedNotificationBit = 0x2;
254
255 bool hasBinding() const { return d_ptr & BindingBit; }
257
262
264 {
265 quintptr dd = d();
266 if (dd & BindingBit)
267 return reinterpret_cast<QPropertyBindingPrivate*>(dd - BindingBit);
268 return nullptr;
269
270 }
271
272 void evaluateIfDirty(const QUntypedPropertyData *) const; // ### Kept for BC reasons, unused
273
275 {
276 if (hasBinding())
278 }
279
289private:
290 /*!
291 \internal
292 Returns a reference to d_ptr, except when d_ptr points to a proxy.
293 In that case, a reference to proxy->d_ptr is returned instead.
294
295 To properly support proxying, direct access to d_ptr only occurs when
296 - a function actually deals with proxying (e.g.
297 QPropertyDelayedNotifications::addProperty),
298 - only the tag value is accessed (e.g. hasBinding) or
299 - inside a constructor.
300 */
301 quintptr &d_ref() const
302 {
303 quintptr &d = d_ptr;
305 return proxyData()->d_ptr;
306 return d;
307 }
308 quintptr d() const { return d_ref(); }
310 {
312 return reinterpret_cast<QPropertyProxyBindingData *>(d_ptr & ~(BindingBit|DelayedNotificationBit));
313 }
316
322};
323
324template <typename T, typename Tag>
326{
327public:
328 constexpr QTagPreservingPointerToPointer() = default;
329
331 : d(reinterpret_cast<quintptr*>(ptr))
332 {}
333
335 {
336 d = reinterpret_cast<quintptr *>(ptr);
337 return *this;
338 }
339
340 QTagPreservingPointerToPointer<T, Tag> &operator=(QTaggedPointer<T, Tag> *ptr)
341 {
342 d = reinterpret_cast<quintptr *>(ptr);
343 return *this;
344 }
345
346 void clear()
347 {
348 d = nullptr;
349 }
350
351 void setPointer(T *ptr)
352 {
353 *d = reinterpret_cast<quintptr>(ptr) | (*d & QTaggedPointer<T, Tag>::tagMask());
354 }
355
356 T *get() const
357 {
358 return reinterpret_cast<T*>(*d & QTaggedPointer<T, Tag>::pointerMask());
359 }
360
361 explicit operator bool() const
362 {
363 return d != nullptr;
364 }
365
366private:
367 quintptr *d = nullptr;
368};
369
370namespace detail {
371 template <typename F>
372 struct ExtractClassFromFunctionPointer;
373
374 template<typename T, typename C>
375 struct ExtractClassFromFunctionPointer<T C::*> { using Class = C; };
376
377 constexpr size_t getOffset(size_t o)
378 {
379 return o;
380 }
382 {
383 return offsetFn();
384 }
385}
386
387} // namespace QtPrivate
388
389QT_END_NAMESPACE
390
391#endif // QPROPERTYPRIVATE_H
\macro Q_OBJECT_BINDABLE_PROPERTY(containingClass, type, name, signal)
operator const T *() const noexcept
QPropertyBindingPrivatePtr & operator=(const QPropertyBindingPrivatePtr &o) noexcept
QPropertyBindingPrivatePtr & operator=(T *o) noexcept
T * operator->() const noexcept
T * get() const noexcept
Q_CORE_EXPORT void destroyAndFreeMemory()
Definition qproperty.cpp:21
QPropertyBindingPrivatePtr(QPropertyBindingPrivatePtr &&o) noexcept
QPropertyBindingPrivatePtr(const QPropertyBindingPrivatePtr &o) noexcept
T * data() const noexcept
void reset(T *ptr=nullptr) noexcept
Definition qproperty.cpp:26
const T * constData() const noexcept
QPropertyBindingPrivatePtr(T *data) noexcept
\inmodule QtCore
Definition qproperty.h:70
QTagPreservingPointerToPointer< T, Tag > & operator=(T **ptr)
QTagPreservingPointerToPointer< T, Tag > & operator=(QTaggedPointer< T, Tag > *ptr)
constexpr QTagPreservingPointerToPointer()=default
constexpr size_t getOffset(size_t o)
constexpr size_t getOffset(size_t(*offsetFn)())
constexpr BindingFunctionVTable bindingFunctionVTable
QUntypedPropertyData * propertyData
const QtPrivate::QPropertyBindingData * originalBindingData
static constexpr BindingFunctionVTable createFor()
const QtPrivate::BindingFunctionVTable * vtable