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