Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
23#include <functional>
24
26
27class QBindingStorage;
28
29template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
31
33using PendingBindingObserverList = QVarLengthArray<QBindingObserverPtr>;
34
35namespace QtPrivate {
36// QPropertyBindingPrivatePtr operates on a RefCountingMixin solely so that we can inline
37// the constructor and copy constructor
38struct RefCounted {
39
40 int refCount() const { return ref; }
41 void addRef() { ++ref; }
42 bool deref() { return --ref != 0; }
43
44private:
45 int ref = 0;
46};
47}
48
52{
53public:
55 T &operator*() const { return *d; }
56 T *operator->() noexcept { return d; }
57 T *operator->() const noexcept { return d; }
58 explicit operator T *() { return d; }
59 explicit operator const T *() const noexcept { return d; }
60 T *data() const noexcept { return d; }
61 T *get() const noexcept { return d; }
62 const T *constData() const noexcept { return d; }
63 T *take() noexcept { T *x = d; d = nullptr; return x; }
64
65 QPropertyBindingPrivatePtr() noexcept : d(nullptr) { }
67 {
68 if (d && !d->deref())
70 }
71 Q_CORE_EXPORT void destroyAndFreeMemory();
72
73 explicit QPropertyBindingPrivatePtr(T *data) noexcept : d(data) { if (d) d->addRef(); }
75 : d(o.d) { if (d) d->addRef(); }
76
77 void reset(T *ptr = nullptr) noexcept;
78
80 {
81 reset(o.d);
82 return *this;
83 }
85 {
86 reset(o);
87 return *this;
88 }
89 QPropertyBindingPrivatePtr(QPropertyBindingPrivatePtr &&o) noexcept : d(std::exchange(o.d, nullptr)) {}
90 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QPropertyBindingPrivatePtr)
91
92 operator bool () const noexcept { return d != nullptr; }
93 bool operator!() const noexcept { return d == nullptr; }
94
96 { qt_ptr_swap(d, other.d); }
97
98private:
100 const QPropertyBindingPrivatePtr &rhs) noexcept
101 { return lhs.d == rhs.d; }
104 const T *rhs) noexcept
105 { return lhs.d == rhs; }
108 std::nullptr_t) noexcept
109 { return !lhs; }
111
113};
114
120
122{
123};
124
125namespace QtPrivate {
126template <typename T>
127using IsUntypedPropertyData = std::enable_if_t<std::is_base_of_v<QUntypedPropertyData, T>, bool>;
128}
129
130template <typename T>
131class QPropertyData;
132
133// Used for grouped property evaluations
134namespace QtPrivate {
135class QPropertyBindingData;
136}
139{
140 // acts as QPropertyBindingData::d_ptr
142 /*
143 The two members below store the original binding data and property
144 data pointer of the property which gets proxied.
145 They are set in QPropertyDelayedNotifications::addProperty
146 */
149};
150
151namespace QtPrivate {
152struct BindingEvaluationState;
153
154/* used in BindingFunctionVTable::createFor; on all other compilers, void would work, but on
155 MSVC this causes C2182 when compiling in C++20 mode. As we only need to provide some default
156 value which gets ignored, we introduce this dummy type.
157*/
159
161{
162 using CallFn = bool(*)(QMetaType, QUntypedPropertyData *, void *);
163 using DtorFn = void(*)(void *);
164 using MoveCtrFn = void(*)(void *, void *);
169
170 template<typename Callable, typename PropertyType=MSVCWorkAround>
172 {
173 static_assert (alignof(Callable) <= alignof(std::max_align_t), "Bindings do not support overaligned functors!");
174 return {
175 /*call=*/[](QMetaType metaType, QUntypedPropertyData *dataPtr, void *f){
176 if constexpr (!std::is_invocable_v<Callable>) {
177 // we got an untyped callable
178 static_assert (std::is_invocable_r_v<bool, Callable, QMetaType, QUntypedPropertyData *> );
179 auto untypedEvaluationFunction = static_cast<Callable *>(f);
180 return std::invoke(*untypedEvaluationFunction, metaType, dataPtr);
181 } else if constexpr (!std::is_same_v<PropertyType, MSVCWorkAround>) {
182 Q_UNUSED(metaType);
183 QPropertyData<PropertyType> *propertyPtr = static_cast<QPropertyData<PropertyType> *>(dataPtr);
184 // That is allowed by POSIX even if Callable is a function pointer
185 auto evaluationFunction = static_cast<Callable *>(f);
186 PropertyType newValue = std::invoke(*evaluationFunction);
187 if constexpr (QTypeTraits::has_operator_equal_v<PropertyType>) {
188 if (newValue == propertyPtr->valueBypassingBindings())
189 return false;
190 }
191 propertyPtr->setValueBypassingBindings(std::move(newValue));
192 return true;
193 } else {
194 // Our code will never instantiate this
195 Q_UNREACHABLE_RETURN(false);
196 }
197 },
198 /*destroy*/[](void *f){ static_cast<Callable *>(f)->~Callable(); },
199 /*moveConstruct*/[](void *addr, void *other){
200 new (addr) Callable(std::move(*static_cast<Callable *>(other)));
201 },
202 /*size*/sizeof(Callable)
203 };
204 }
205};
206
207template<typename Callable, typename PropertyType=MSVCWorkAround>
208inline constexpr BindingFunctionVTable bindingFunctionVTable = BindingFunctionVTable::createFor<Callable, PropertyType>();
209
210
211// writes binding result into dataPtr
216
219
230class Q_CORE_EXPORT QPropertyBindingData
231{
232 // Mutable because the address of the observer of the currently evaluating binding is stored here, for
233 // notification later when the value changes.
234 mutable quintptr d_ptr = 0;
235 friend struct QT_PREPEND_NAMESPACE(QPropertyBindingDataPointer);
236 friend class QT_PREPEND_NAMESPACE(QQmlPropertyBinding);
237 friend struct QT_PREPEND_NAMESPACE(QPropertyDelayedNotifications);
238
239 template<typename Class, typename T, auto Offset, auto Setter, auto Signal, auto Getter>
240 friend class QT_PREPEND_NAMESPACE(QObjectCompatProperty);
241
242 Q_DISABLE_COPY(QPropertyBindingData)
243public:
248
249 // Is d_ptr pointing to a binding (1) or list of notifiers (0)?
250 static inline constexpr quintptr BindingBit = 0x1;
251 // Is d_ptr pointing to QPropertyProxyBindingData (1) or to an actual binding/list of notifiers?
252 static inline constexpr quintptr DelayedNotificationBit = 0x2;
253
254 bool hasBinding() const { return d_ptr & BindingBit; }
255 bool isNotificationDelayed() const { return d_ptr & DelayedNotificationBit; }
256
257 QUntypedPropertyBinding setBinding(const QUntypedPropertyBinding &newBinding,
258 QUntypedPropertyData *propertyDataPtr,
259 QPropertyObserverCallback staticObserverCallback = nullptr,
260 QPropertyBindingWrapper bindingWrapper = nullptr);
261
263 {
264 quintptr dd = d();
265 if (dd & BindingBit)
266 return reinterpret_cast<QPropertyBindingPrivate*>(dd - BindingBit);
267 return nullptr;
268
269 }
270
271 void evaluateIfDirty(const QUntypedPropertyData *) const; // ### Kept for BC reasons, unused
272
274 {
275 if (hasBinding())
276 removeBinding_helper();
277 }
278
280 {
281 if (!currentBinding)
282 return;
283 registerWithCurrentlyEvaluatingBinding_helper(currentBinding);
284 }
285 void registerWithCurrentlyEvaluatingBinding() const;
286 void notifyObservers(QUntypedPropertyData *propertyDataPtr) const;
287 void notifyObservers(QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage) const;
288private:
300 quintptr &d_ref() const
301 {
302 quintptr &d = d_ptr;
303 if (isNotificationDelayed())
304 return proxyData()->d_ptr;
305 return d;
306 }
307 quintptr d() const { return d_ref(); }
308 QPropertyProxyBindingData *proxyData() const
309 {
310 Q_ASSERT(isNotificationDelayed());
311 return reinterpret_cast<QPropertyProxyBindingData *>(d_ptr & ~(BindingBit|DelayedNotificationBit));
312 }
313 void registerWithCurrentlyEvaluatingBinding_helper(BindingEvaluationState *currentBinding) const;
314 void removeBinding_helper();
315
316 enum NotificationResult { Delayed, Evaluated };
317 NotificationResult notifyObserver_helper(
320 PendingBindingObserverList &bindingObservers) const;
321};
322
323template <typename T, typename Tag>
325{
326public:
327 constexpr QTagPreservingPointerToPointer() = default;
328
330 : d(reinterpret_cast<quintptr*>(ptr))
331 {}
332
333 QTagPreservingPointerToPointer<T, Tag> &operator=(T **ptr)
334 {
335 d = reinterpret_cast<quintptr *>(ptr);
336 return *this;
337 }
338
339 QTagPreservingPointerToPointer<T, Tag> &operator=(QTaggedPointer<T, Tag> *ptr)
340 {
341 d = reinterpret_cast<quintptr *>(ptr);
342 return *this;
343 }
344
345 void clear()
346 {
347 d = nullptr;
348 }
349
351 {
352 *d = reinterpret_cast<quintptr>(ptr) | (*d & QTaggedPointer<T, Tag>::tagMask());
353 }
354
355 T *get() const
356 {
357 return reinterpret_cast<T*>(*d & QTaggedPointer<T, Tag>::pointerMask());
358 }
359
360 explicit operator bool() const
361 {
362 return d != nullptr;
363 }
364
365private:
366 quintptr *d = nullptr;
367};
368
369namespace detail {
370 template <typename F>
372
373 template<typename T, typename C>
374 struct ExtractClassFromFunctionPointer<T C::*> { using Class = C; };
375
376 constexpr size_t getOffset(size_t o)
377 {
378 return o;
379 }
380 constexpr size_t getOffset(size_t (*offsetFn)())
381 {
382 return offsetFn();
383 }
384}
385
386} // namespace QtPrivate
387
389
390#endif // QPROPERTYPRIVATE_H
\inmodule QtCore
Definition qmetatype.h:341
\macro Q_OBJECT_BINDABLE_PROPERTY(containingClass, type, name, signal)
friend bool comparesEqual(const QPropertyBindingPrivatePtr &lhs, const QPropertyBindingPrivatePtr &rhs) noexcept
void swap(QPropertyBindingPrivatePtr &other) 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
bool operator!() const noexcept
QPropertyBindingPrivatePtr(const QPropertyBindingPrivatePtr &o) noexcept
T * data() const noexcept
const T * constData() const noexcept
QPropertyBindingPrivatePtr(T *data) noexcept
\inmodule QtCore
Definition qproperty.h:69
static constexpr quintptr pointerMask()
void registerWithCurrentlyEvaluatingBinding(QtPrivate::BindingEvaluationState *currentBinding) const
QPropertyBindingPrivate * binding() const
QPropertyBindingData & operator=(QPropertyBindingData &&other)=delete
QTagPreservingPointerToPointer< T, Tag > & operator=(T **ptr)
QTagPreservingPointerToPointer< T, Tag > & operator=(QTaggedPointer< T, Tag > *ptr)
constexpr QTagPreservingPointerToPointer()=default
Combined button and popup list for selecting options.
constexpr size_t getOffset(size_t o)
\macro QT_NO_KEYWORDS >
std::enable_if_t< std::is_base_of_v< QUntypedPropertyData, T >, bool > IsUntypedPropertyData
constexpr BindingFunctionVTable bindingFunctionVTable
void(*)(QUntypedPropertyData *) QPropertyObserverCallback
bool(*)(QMetaType, QUntypedPropertyData *dataPtr, QPropertyBindingFunction) QPropertyBindingWrapper
#define Q_DECLARE_EQUALITY_COMPARABLE(...)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static ControlElement< T > * ptr(QWidget *widget)
GLint GLint GLint GLint GLint x
[0]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLint ref
GLboolean reset
GLenum const void * addr
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
constexpr void qt_ptr_swap(T *&lhs, T *&rhs) noexcept
Definition qswap.h:29
#define Q_UNUSED(x)
size_t quintptr
Definition qtypes.h:167
ptrdiff_t qsizetype
Definition qtypes.h:165
QStorageInfo storage
[1]
QSharedPointer< T > other(t)
[5]
QUntypedPropertyData * propertyData
const QtPrivate::QPropertyBindingData * originalBindingData
bool(*)(QMetaType, QUntypedPropertyData *, void *) CallFn
static constexpr BindingFunctionVTable createFor()
void(*)(void *, void *) MoveCtrFn
const QtPrivate::BindingFunctionVTable * vtable