1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2018 Intel Corporation.
3// Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#ifndef QMETATYPE_H
7#define QMETATYPE_H
8
9#include <QtCore/qglobal.h>
10#include <QtCore/qatomic.h>
11#include <QtCore/qbytearray.h>
12#include <QtCore/qcompare.h>
13#include <QtCore/qdatastream.h>
14#include <QtCore/qflags.h>
15#include <QtCore/qfloat16.h>
16#include <QtCore/qhashfunctions.h>
17#include <QtCore/qiterable.h>
18#ifndef QT_NO_QOBJECT
19#include <QtCore/qobjectdefs.h>
20#endif
21#include <QtCore/qscopeguard.h>
22#include <QtCore/qttypetraits.h>
23
24#include <array>
25#include <new>
26#include <vector>
27#include <list>
28#include <map>
29#include <functional>
30#include <optional>
31#include <QtCore/qxptype_traits.h>
32
33#ifdef Bool
34#error qmetatype.h must be included before any header file that defines Bool
35#endif
36
37QT_BEGIN_NAMESPACE
38
39// from qcborcommon.h
40enum class QCborSimpleType : quint8;
41
42template <typename T>
43struct QMetaTypeId2;
44
45template <typename T>
46inline constexpr int qMetaTypeId();
47
48// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
49#define QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F)\
50 F(Bool, 1, bool) \
51 F(Int, 2, int) \
52 F(UInt, 3, uint) \
53 F(LongLong, 4, qlonglong) \
54 F(ULongLong, 5, qulonglong) \
55 F(Double, 6, double) \
56 F(Long, 32, long) \
57 F(Short, 33, short) \
58 F(Char, 34, char) \
59 F(Char16, 56, char16_t) \
60 F(Char32, 57, char32_t) \
61 F(ULong, 35, ulong) \
62 F(UShort, 36, ushort) \
63 F(UChar, 37, uchar) \
64 F(Float, 38, float) \
65 F(SChar, 40, signed char) \
66 F(Nullptr, 51, std::nullptr_t) \
67 F(QCborSimpleType, 52, QCborSimpleType) \
68
69#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \
70 QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F) \
71 F(Void, 43, void) \
72
73#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F) \
74 F(VoidStar, 31, void*) \
75
76#if QT_CONFIG(easingcurve)
77#define QT_FOR_EACH_STATIC_EASINGCURVE(F)\
78 F(QEasingCurve, 29, QEasingCurve)
79#else
80#define QT_FOR_EACH_STATIC_EASINGCURVE(F)
81#endif
82
83#if QT_CONFIG(itemmodel)
84#define QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)\
85 F(QModelIndex, 42, QModelIndex) \
86 F(QPersistentModelIndex, 50, QPersistentModelIndex)
87#else
88#define QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
89#endif
90
91#if QT_CONFIG(regularexpression)
92# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
93 F(QRegularExpression, 44, QRegularExpression)
94#else
95# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F)
96#endif
97#ifndef QT_NO_VARIANT
98# define QT_FOR_EACH_STATIC_QVARIANT(F) \
99 F(QVariant, 41, QVariant)
100#else
101# define QT_FOR_EACH_STATIC_QVARIANT(F)
102#endif
103
104#define QT_FOR_EACH_STATIC_CORE_CLASS(F)\
105 F(QChar, 7, QChar) \
106 F(QString, 10, QString) \
107 F(QByteArray, 12, QByteArray) \
108 F(QBitArray, 13, QBitArray) \
109 F(QDate, 14, QDate) \
110 F(QTime, 15, QTime) \
111 F(QDateTime, 16, QDateTime) \
112 F(QUrl, 17, QUrl) \
113 F(QLocale, 18, QLocale) \
114 F(QRect, 19, QRect) \
115 F(QRectF, 20, QRectF) \
116 F(QSize, 21, QSize) \
117 F(QSizeF, 22, QSizeF) \
118 F(QLine, 23, QLine) \
119 F(QLineF, 24, QLineF) \
120 F(QPoint, 25, QPoint) \
121 F(QPointF, 26, QPointF) \
122 QT_FOR_EACH_STATIC_EASINGCURVE(F) \
123 F(QUuid, 30, QUuid) \
124 QT_FOR_EACH_STATIC_QVARIANT(F) \
125 QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
126 F(QJsonValue, 45, QJsonValue) \
127 F(QJsonObject, 46, QJsonObject) \
128 F(QJsonArray, 47, QJsonArray) \
129 F(QJsonDocument, 48, QJsonDocument) \
130 F(QCborValue, 53, QCborValue) \
131 F(QCborArray, 54, QCborArray) \
132 F(QCborMap, 55, QCborMap) \
133 F(Float16, 63, qfloat16) \
134 QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
135
136#define QT_FOR_EACH_STATIC_CORE_POINTER(F)\
137 F(QObjectStar, 39, QObject*)
138
139#ifndef QT_NO_VARIANT
140# define QT_FOR_EACH_STATIC_CORE_QVARIANT_TEMPLATE(F) \
141 F(QVariantMap, 8, QVariantMap) \
142 F(QVariantList, 9, QVariantList) \
143 F(QVariantHash, 28, QVariantHash) \
144 F(QVariantPair, 58, QVariantPair) \
145 /**/
146#else
147# define QT_FOR_EACH_STATIC_CORE_QVARIANT_TEMPLATE(F)
148#endif // QT_NO_VARIANT
149
150#define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F) \
151 QT_FOR_EACH_STATIC_CORE_QVARIANT_TEMPLATE(F) \
152 F(QByteArrayList, 49, QByteArrayList) \
153 F(QStringList, 11, QStringList)
154
155#if QT_CONFIG(shortcut)
156#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)\
157 F(QKeySequence, 0x100b, QKeySequence)
158#else
159#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)
160#endif
161
162#define QT_FOR_EACH_STATIC_GUI_CLASS(F)\
163 F(QFont, 0x1000, QFont) \
164 F(QPixmap, 0x1001, QPixmap) \
165 F(QBrush, 0x1002, QBrush) \
166 F(QColor, 0x1003, QColor) \
167 F(QPalette, 0x1004, QPalette) \
168 F(QIcon, 0x1005, QIcon) \
169 F(QImage, 0x1006, QImage) \
170 F(QPolygon, 0x1007, QPolygon) \
171 F(QRegion, 0x1008, QRegion) \
172 F(QBitmap, 0x1009, QBitmap) \
173 F(QCursor, 0x100a, QCursor) \
174 QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F) \
175 F(QPen, 0x100c, QPen) \
176 F(QTextLength, 0x100d, QTextLength) \
177 F(QTextFormat, 0x100e, QTextFormat) \
178 F(QTransform, 0x1010, QTransform) \
179 F(QMatrix4x4, 0x1011, QMatrix4x4) \
180 F(QVector2D, 0x1012, QVector2D) \
181 F(QVector3D, 0x1013, QVector3D) \
182 F(QVector4D, 0x1014, QVector4D) \
183 F(QQuaternion, 0x1015, QQuaternion) \
184 F(QPolygonF, 0x1016, QPolygonF) \
185 F(QColorSpace, 0x1017, QColorSpace) \
186
187
188#define QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\
189 F(QSizePolicy, 0x2000, QSizePolicy) \
190
191// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, AliasingType, "RealType")
192#define QT_FOR_EACH_STATIC_ALIAS_TYPE(F)\
193 F(ULong, -1, ulong, "unsigned long") \
194 F(UInt, -1, uint, "unsigned int") \
195 F(UShort, -1, ushort, "unsigned short") \
196 F(UChar, -1, uchar, "unsigned char") \
197 F(LongLong, -1, qlonglong, "long long") \
198 F(ULongLong, -1, qulonglong, "unsigned long long") \
199 F(SChar, -1, signed char, "qint8") \
200 F(UChar, -1, uchar, "quint8") \
201 F(Short, -1, short, "qint16") \
202 F(UShort, -1, ushort, "quint16") \
203 F(Int, -1, int, "qint32") \
204 F(UInt, -1, uint, "quint32") \
205 F(LongLong, -1, qlonglong, "qint64") \
206 F(ULongLong, -1, qulonglong, "quint64") \
207 F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
208 F(QStringList, -1, QStringList, "QList<QString>") \
209 QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F)
210
211#ifndef QT_NO_VARIANT
212#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F) \
213 F(QVariantList, -1, QVariantList, "QList<QVariant>") \
214 F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
215 F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
216 F(QVariantPair, -1, QVariantPair, "QPair<QVariant,QVariant>") \
217 /**/
218#else
219#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F)
220#endif
221
222#define QT_FOR_EACH_STATIC_TYPE(F)\
223 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
224 QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
225 QT_FOR_EACH_STATIC_CORE_CLASS(F)\
226 QT_FOR_EACH_STATIC_CORE_POINTER(F)\
227 QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
228 QT_FOR_EACH_STATIC_GUI_CLASS(F)\
229 QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\
230
231#define QT_DEFINE_METATYPE_ID(TypeName, Id, Name) \
232 TypeName = Id,
233
234#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \
235 F(QList) \
236 F(QQueue) \
237 F(QStack) \
238 F(QSet) \
239 /*end*/
240
241#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(F) \
242 F(QHash, class) \
243 F(QMap, class)
244
245#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(F) \
246 F(QSharedPointer) \
247 F(QWeakPointer) \
248 F(QPointer)
249
250class QDataStream;
251struct QMetaObject;
252
253namespace QtPrivate
254{
255
256class QMetaTypeInterface;
257
258// MSVC is the only supported compiler that includes the type of a variable in
259// its mangled form, so it's not binary-compatible to drop the const in
260// QMetaTypeInterfaceWrapper::metaType for it, which means we must keep the
261// mutable field until Qt 7.
262#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || !defined(Q_CC_MSVC)
263# define QMTI_MUTABLE
264using NonConstMetaTypeInterface = QMetaTypeInterface;
265#else
266# define QMTI_MUTABLE mutable
267using NonConstMetaTypeInterface = const QMetaTypeInterface;
268#endif
269
270class QMetaTypeInterface
271{
272public:
273
274 /* Revision: Can increase if new field are added, or if semantics changes
275 0: Initial Revision
276 1: the meaning of the NeedsDestruction flag changed
277 */
278 static inline constexpr ushort CurrentRevision = 1;
279
280 ushort revision;
281 ushort alignment;
282 uint size;
283 uint flags;
284 QMTI_MUTABLE QBasicAtomicInt typeId;
285
286 using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
287 MetaObjectFn metaObjectFn;
288
289 const char *name;
290
291 using DefaultCtrFn = void (*)(const QMetaTypeInterface *, void *);
292 DefaultCtrFn defaultCtr;
293 using CopyCtrFn = void (*)(const QMetaTypeInterface *, void *, const void *);
294 CopyCtrFn copyCtr;
295 using MoveCtrFn = void (*)(const QMetaTypeInterface *, void *, void *);
296 MoveCtrFn moveCtr;
297 using DtorFn = void (*)(const QMetaTypeInterface *, void *);
298 DtorFn dtor;
299 using EqualsFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
300 EqualsFn equals;
301 using LessThanFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
302 LessThanFn lessThan;
303 using DebugStreamFn = void (*)(const QMetaTypeInterface *, QDebug &, const void *);
304 DebugStreamFn debugStream;
305 using DataStreamOutFn = void (*)(const QMetaTypeInterface *, QDataStream &, const void *);
306 DataStreamOutFn dataStreamOut;
307 using DataStreamInFn = void (*)(const QMetaTypeInterface *, QDataStream &, void *);
308 DataStreamInFn dataStreamIn;
309
310 using LegacyRegisterOp = void (*)();
311 LegacyRegisterOp legacyRegisterOp;
312};
313#undef QMTI_MUTABLE
314
315/*!
316 This template is used for implicit conversion from type From to type To.
317 \internal
318*/
319template<typename From, typename To>
320To convertImplicit(const From& from)
321{
322 return from;
323}
324
325 template<typename T, bool>
326 struct SequentialValueTypeIsMetaType;
327 template<typename T, bool>
328 struct AssociativeValueTypeIsMetaType;
329 template<typename T, bool>
330 struct IsMetaTypePair;
331 template<typename, typename>
332 struct MetaTypeSmartPointerHelper;
333
334 template<typename T>
335 struct IsEnumOrFlags : std::disjunction<std::is_enum<T>, IsQFlags<T>> {};
336} // namespace QtPrivate
337
338class Q_CORE_EXPORT QMetaType {
339public:
340#ifndef Q_QDOC
341 // The code that actually gets compiled.
342 enum Type {
343 // these are merged with QVariant
344 QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
345
346 FirstCoreType = Bool,
347 LastCoreType = Float16,
348 FirstGuiType = QFont,
349 LastGuiType = QColorSpace,
350 FirstWidgetsType = QSizePolicy,
351 LastWidgetsType = QSizePolicy,
352 HighestInternalId = LastWidgetsType,
353
354 QReal = sizeof(qreal) == sizeof(double) ? Double : Float,
355
356 UnknownType = 0,
357 User = 65536
358 };
359#else
360 // If we are using QDoc it fakes the Type enum looks like this.
361 enum Type {
362 UnknownType = 0, Bool = 1, Int = 2, UInt = 3, LongLong = 4, ULongLong = 5,
363 Double = 6, Long = 32, Short = 33, Char = 34, ULong = 35, UShort = 36,
364 UChar = 37, Float = 38,
365 VoidStar = 31,
366 QChar = 7, QString = 10, QStringList = 11, QByteArray = 12,
367 QBitArray = 13, QDate = 14, QTime = 15, QDateTime = 16, QUrl = 17,
368 QLocale = 18, QRect = 19, QRectF = 20, QSize = 21, QSizeF = 22,
369 QLine = 23, QLineF = 24, QPoint = 25, QPointF = 26,
370 QEasingCurve = 29, QUuid = 30, QVariant = 41, QModelIndex = 42,
371 QPersistentModelIndex = 50, QRegularExpression = 44,
372 QJsonValue = 45, QJsonObject = 46, QJsonArray = 47, QJsonDocument = 48,
373 QByteArrayList = 49, QObjectStar = 39, SChar = 40,
374 Void = 43,
375 Nullptr = 51,
376 QVariantMap = 8, QVariantList = 9, QVariantHash = 28, QVariantPair = 58,
377 QCborSimpleType = 52, QCborValue = 53, QCborArray = 54, QCborMap = 55,
378 Char16 = 56, Char32 = 57,
379 Int128 = 59, UInt128 = 60, Float128 = 61, BFloat16 = 62, Float16 = 63,
380
381 // Gui types
382 QFont = 0x1000, QPixmap = 0x1001, QBrush = 0x1002, QColor = 0x1003, QPalette = 0x1004,
383 QIcon = 0x1005, QImage = 0x1006, QPolygon = 0x1007, QRegion = 0x1008, QBitmap = 0x1009,
384 QCursor = 0x100a, QKeySequence = 0x100b, QPen = 0x100c, QTextLength = 0x100d, QTextFormat = 0x100e,
385 QTransform = 0x1010, QMatrix4x4 = 0x1011, QVector2D = 0x1012,
386 QVector3D = 0x1013, QVector4D = 0x1014, QQuaternion = 0x1015, QPolygonF = 0x1016, QColorSpace = 0x1017,
387
388 // Widget types
389 QSizePolicy = 0x2000,
390
391 // Start-point for client-code types:
392 User = 65536
393 };
394#endif
395
396 enum TypeFlag {
397 NeedsConstruction = 0x1,
398 NeedsDestruction = 0x2,
399 RelocatableType = 0x4,
400#if QT_DEPRECATED_SINCE(6, 0)
401 MovableType Q_DECL_ENUMERATOR_DEPRECATED_X("Use RelocatableType instead.") = RelocatableType,
402#endif
403 PointerToQObject = 0x8,
404 IsEnumeration = 0x10,
405 SharedPointerToQObject = 0x20,
406 WeakPointerToQObject = 0x40,
407 TrackingPointerToQObject = 0x80,
408 IsUnsignedEnumeration = 0x100,
409 IsGadget = 0x200,
410 PointerToGadget = 0x400,
411 IsPointer = 0x800,
412 IsQmlList =0x1000, // used in the QML engine to recognize QQmlListProperty<T> and list<T>
413 IsConst = 0x2000,
414 // since 6.5:
415 NeedsCopyConstruction = 0x4000,
416 NeedsMoveConstruction = 0x8000,
417 };
418 Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
419
420 static void registerNormalizedTypedef(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, QMetaType type);
421
422#if QT_DEPRECATED_SINCE(6, 0)
423 QT_DEPRECATED_VERSION_6_0
424 static int type(const char *typeName)
425 { return QMetaType::fromName(name: typeName).id(); }
426 QT_DEPRECATED_VERSION_6_0
427 static int type(const QT_PREPEND_NAMESPACE(QByteArray) &typeName)
428 { return QMetaType::fromName(name: typeName).id(); }
429 QT_DEPRECATED_VERSION_6_0
430 static const char *typeName(int type)
431 { return QMetaType(type).name(); }
432 QT_DEPRECATED_VERSION_6_0
433 static int sizeOf(int type)
434 { return int(QMetaType(type).sizeOf()); }
435 QT_DEPRECATED_VERSION_6_0
436 static TypeFlags typeFlags(int type)
437 { return QMetaType(type).flags(); }
438 QT_DEPRECATED_VERSION_6_0
439 static const QMetaObject *metaObjectForType(int type)
440 { return QMetaType(type).metaObject(); }
441 QT_DEPRECATED_VERSION_6_0
442 static void *create(int type, const void *copy = nullptr)
443 { return QMetaType(type).create(copy); }
444 QT_DEPRECATED_VERSION_6_0
445 static void destroy(int type, void *data)
446 { return QMetaType(type).destroy(data); }
447 QT_DEPRECATED_VERSION_6_0
448 static void *construct(int type, void *where, const void *copy)
449 { return QMetaType(type).construct(where, copy); }
450 QT_DEPRECATED_VERSION_6_0
451 static void destruct(int type, void *where)
452 { return QMetaType(type).destruct(data: where); }
453#endif
454 static bool isRegistered(int type);
455
456 explicit QMetaType(int type);
457 explicit constexpr QMetaType(const QtPrivate::QMetaTypeInterface *d) : d_ptr(d) {}
458 constexpr QMetaType() = default;
459
460#if QT_CORE_REMOVED_SINCE(6, 9)
461 bool isValid() const;
462 bool isRegistered() const;
463#endif
464 constexpr bool isValid(QT6_DECL_NEW_OVERLOAD) const noexcept;
465 inline bool isRegistered(QT6_DECL_NEW_OVERLOAD) const noexcept;
466 void registerType() const
467 {
468 // "register" is a reserved keyword
469 registerHelper();
470 }
471#if QT_CORE_REMOVED_SINCE(6, 1) || defined(Q_QDOC)
472 int id() const;
473#else
474 // ### Qt 7: Remove traces of out of line version
475 // unused int parameter is used to avoid ODR violation
476 int id(int = 0) const
477 {
478 return registerHelper();
479 }
480#endif
481 constexpr qsizetype sizeOf() const;
482 constexpr qsizetype alignOf() const;
483 constexpr TypeFlags flags() const;
484 constexpr const QMetaObject *metaObject() const;
485 constexpr const char *name() const;
486
487 void *create(const void *copy = nullptr) const;
488 void destroy(void *data) const;
489 void *construct(void *where, const void *copy = nullptr) const;
490 void destruct(void *data) const;
491 QPartialOrdering compare(const void *lhs, const void *rhs) const;
492 bool equals(const void *lhs, const void *rhs) const;
493
494 bool isDefaultConstructible() const noexcept { return d_ptr && isDefaultConstructible(d_ptr); }
495 bool isCopyConstructible() const noexcept { return d_ptr && isCopyConstructible(d_ptr); }
496 bool isMoveConstructible() const noexcept { return d_ptr && isMoveConstructible(d_ptr); }
497 bool isDestructible() const noexcept { return d_ptr && isDestructible(d_ptr); }
498 bool isEqualityComparable() const;
499 bool isOrdered() const;
500
501#ifndef QT_NO_DATASTREAM
502 bool save(QDataStream &stream, const void *data) const;
503 bool load(QDataStream &stream, void *data) const;
504 bool hasRegisteredDataStreamOperators() const;
505
506#if QT_DEPRECATED_SINCE(6, 0)
507 QT_DEPRECATED_VERSION_6_0
508 static bool save(QDataStream &stream, int type, const void *data)
509 { return QMetaType(type).save(stream, data); }
510 QT_DEPRECATED_VERSION_6_0
511 static bool load(QDataStream &stream, int type, void *data)
512 { return QMetaType(type).load(stream, data); }
513#endif
514#endif
515
516 QMetaType underlyingType() const;
517
518 template<typename T>
519 constexpr static QMetaType fromType();
520 static QMetaType fromName(QByteArrayView name);
521private:
522 friend bool comparesEqual(const QMetaType &lhs,
523 const QMetaType &rhs)
524 {
525 if (lhs.d_ptr == rhs.d_ptr)
526 return true;
527 if (!lhs.d_ptr || !rhs.d_ptr)
528 return false; // one type is undefined, the other is defined
529 // avoid id call if we already have the id
530 const int aId = lhs.id();
531 const int bId = rhs.id();
532 return aId == bId;
533 }
534 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(QMetaType)
535#ifndef QT_NO_DEBUG_STREAM
536private:
537 friend Q_CORE_EXPORT QDebug operator<<(QDebug d, QMetaType m);
538public:
539 bool debugStream(QDebug& dbg, const void *rhs);
540 bool hasRegisteredDebugStreamOperator() const;
541
542#if QT_DEPRECATED_SINCE(6, 0)
543 QT_DEPRECATED_VERSION_6_0
544 static bool debugStream(QDebug& dbg, const void *rhs, int typeId)
545 { return QMetaType(typeId).debugStream(dbg, rhs); }
546 template<typename T>
547 QT_DEPRECATED_VERSION_6_0
548 static bool hasRegisteredDebugStreamOperator()
549 { return QMetaType::fromType<T>().hasRegisteredDebugStreamOperator(); }
550 QT_DEPRECATED_VERSION_6_0
551 static bool hasRegisteredDebugStreamOperator(int typeId)
552 { return QMetaType(typeId).hasRegisteredDebugStreamOperator(); }
553#endif
554#endif
555
556public:
557 // type erased converter function
558 using ConverterFunction = std::function<bool(const void *src, void *target)>;
559
560 // type erased mutable view, primarily for containers
561 using MutableViewFunction = std::function<bool(void *src, void *target)>;
562
563 // implicit conversion supported like double -> float
564 template<typename From, typename To>
565 static bool registerConverter()
566 {
567 return registerConverter<From, To>(QtPrivate::convertImplicit<From, To>);
568 }
569
570 // member function as in "QString QFont::toString() const"
571 template<typename From, typename To>
572 static bool registerConverter(To(From::*function)() const)
573 {
574 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
575 "QMetaType::registerConverter: At least one of the types must be a custom type.");
576
577 const QMetaType fromType = QMetaType::fromType<From>();
578 const QMetaType toType = QMetaType::fromType<To>();
579 auto converter = [function](const void *from, void *to) -> bool {
580 const From *f = static_cast<const From *>(from);
581 To *t = static_cast<To *>(to);
582 *t = (f->*function)();
583 return true;
584 };
585 return registerConverterImpl<From, To>(converter, fromType, toType);
586 }
587
588 // member function
589 template<typename From, typename To>
590 static bool registerMutableView(To(From::*function)())
591 {
592 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
593 "QMetaType::registerMutableView: At least one of the types must be a custom type.");
594
595 const QMetaType fromType = QMetaType::fromType<From>();
596 const QMetaType toType = QMetaType::fromType<To>();
597 auto view = [function](void *from, void *to) -> bool {
598 From *f = static_cast<From *>(from);
599 To *t = static_cast<To *>(to);
600 *t = (f->*function)();
601 return true;
602 };
603 return registerMutableViewImpl<From, To>(view, fromType, toType);
604 }
605
606 // member function as in "double QString::toDouble(bool *ok = nullptr) const"
607 template<typename From, typename To>
608 static bool registerConverter(To(From::*function)(bool*) const)
609 {
610 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
611 "QMetaType::registerConverter: At least one of the types must be a custom type.");
612
613 const QMetaType fromType = QMetaType::fromType<From>();
614 const QMetaType toType = QMetaType::fromType<To>();
615 auto converter = [function](const void *from, void *to) -> bool {
616 const From *f = static_cast<const From *>(from);
617 To *t = static_cast<To *>(to);
618 bool result = true;
619 *t = (f->*function)(&result);
620 if (!result)
621 *t = To();
622 return result;
623 };
624 return registerConverterImpl<From, To>(converter, fromType, toType);
625 }
626
627 // functor or function pointer
628 template<typename From, typename To, typename UnaryFunction>
629 static bool registerConverter(UnaryFunction function)
630 {
631 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
632 "QMetaType::registerConverter: At least one of the types must be a custom type.");
633
634 const QMetaType fromType = QMetaType::fromType<From>();
635 const QMetaType toType = QMetaType::fromType<To>();
636 auto converter = [function = std::move(function)](const void *from, void *to) -> bool {
637 const From *f = static_cast<const From *>(from);
638 To *t = static_cast<To *>(to);
639 auto &&r = function(*f);
640 if constexpr (std::is_same_v<q20::remove_cvref_t<decltype(r)>, std::optional<To>>) {
641 if (!r)
642 return false;
643 *t = *std::forward<decltype(r)>(r);
644 } else {
645 *t = std::forward<decltype(r)>(r);
646 }
647 return true;
648 };
649 return registerConverterImpl<From, To>(std::move(converter), fromType, toType);
650 }
651
652 // functor or function pointer
653 template<typename From, typename To, typename UnaryFunction>
654 static bool registerMutableView(UnaryFunction function)
655 {
656 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
657 "QMetaType::registerMutableView: At least one of the types must be a custom type.");
658
659 const QMetaType fromType = QMetaType::fromType<From>();
660 const QMetaType toType = QMetaType::fromType<To>();
661 auto view = [function = std::move(function)](void *from, void *to) -> bool {
662 From *f = static_cast<From *>(from);
663 To *t = static_cast<To *>(to);
664 *t = function(*f);
665 return true;
666 };
667 return registerMutableViewImpl<From, To>(std::move(view), fromType, toType);
668 }
669
670private:
671 template<typename From, typename To>
672 static bool registerConverterImpl(ConverterFunction converter, QMetaType fromType, QMetaType toType)
673 {
674 if (registerConverterFunction(f: std::move(converter), from: fromType, to: toType)) {
675 static const auto unregister = qScopeGuard([=] {
676 unregisterConverterFunction(from: fromType, to: toType);
677 });
678 return true;
679 } else {
680 return false;
681 }
682 }
683
684 template<typename From, typename To>
685 static bool registerMutableViewImpl(MutableViewFunction view, QMetaType fromType, QMetaType toType)
686 {
687 if (registerMutableViewFunction(f: std::move(view), from: fromType, to: toType)) {
688 static const auto unregister = qScopeGuard([=] {
689 unregisterMutableViewFunction(from: fromType, to: toType);
690 });
691 return true;
692 } else {
693 return false;
694 }
695 }
696public:
697
698 static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to);
699 static bool canConvert(QMetaType fromType, QMetaType toType);
700
701 static bool view(QMetaType fromType, void *from, QMetaType toType, void *to);
702 static bool canView(QMetaType fromType, QMetaType toType);
703#if QT_DEPRECATED_SINCE(6, 0)
704 QT_DEPRECATED_VERSION_6_0
705 static bool convert(const void *from, int fromTypeId, void *to, int toTypeId)
706 { return convert(fromType: QMetaType(fromTypeId), from, toType: QMetaType(toTypeId), to); }
707 QT_DEPRECATED_VERSION_6_0
708 static bool compare(const void *lhs, const void *rhs, int typeId, int *result)
709 {
710 QMetaType t(typeId);
711 auto c = t.compare(lhs, rhs);
712 if (c == QPartialOrdering::Unordered) {
713 *result = 0;
714 return false;
715 } else if (c == QPartialOrdering::Less) {
716 *result = -1;
717 return true;
718 } else if (c == QPartialOrdering::Equivalent) {
719 *result = 0;
720 return true;
721 } else {
722 *result = 1;
723 return true;
724 }
725 }
726 QT_DEPRECATED_VERSION_6_0
727 static bool equals(const void *lhs, const void *rhs, int typeId, int *result)
728 {
729 QMetaType t(typeId);
730 if (!t.isEqualityComparable())
731 return false;
732 *result = t.equals(lhs, rhs) ? 0 : -1;
733 return true;
734 }
735#endif
736
737 template<typename From, typename To>
738 static bool hasRegisteredConverterFunction()
739 {
740 return hasRegisteredConverterFunction(
741 QMetaType::fromType<From>(), QMetaType::fromType<To>());
742 }
743
744 static bool hasRegisteredConverterFunction(QMetaType fromType, QMetaType toType);
745
746 template<typename From, typename To>
747 static bool hasRegisteredMutableViewFunction()
748 {
749 return hasRegisteredMutableViewFunction(
750 QMetaType::fromType<From>(), QMetaType::fromType<To>());
751 }
752
753 static bool hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType);
754
755#ifndef Q_QDOC
756 template<typename, bool> friend struct QtPrivate::SequentialValueTypeIsMetaType;
757 template<typename, bool> friend struct QtPrivate::AssociativeValueTypeIsMetaType;
758 template<typename, bool> friend struct QtPrivate::IsMetaTypePair;
759 template<typename, typename> friend struct QtPrivate::MetaTypeSmartPointerHelper;
760#endif
761 static bool registerConverterFunction(const ConverterFunction &f, QMetaType from, QMetaType to);
762 static void unregisterConverterFunction(QMetaType from, QMetaType to);
763
764 static bool registerMutableViewFunction(const MutableViewFunction &f, QMetaType from, QMetaType to);
765 static void unregisterMutableViewFunction(QMetaType from, QMetaType to);
766
767 static void unregisterMetaType(QMetaType type);
768
769#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
770 constexpr const QtPrivate::QMetaTypeInterface *iface() { return d_ptr; }
771#endif
772 constexpr const QtPrivate::QMetaTypeInterface *iface() const { return d_ptr; }
773
774private:
775 static bool isDefaultConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
776 static bool isCopyConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
777 static bool isMoveConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
778 static bool isDestructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
779
780#if QT_CORE_REMOVED_SINCE(6, 5)
781 int idHelper() const;
782#endif
783 static int registerHelper(const QtPrivate::QMetaTypeInterface *iface);
784 int registerHelper() const
785 {
786 if (d_ptr) {
787 if (int id = d_ptr->typeId.loadRelaxed())
788 return id;
789 return registerHelper(iface: d_ptr);
790 }
791 return 0;
792 }
793
794 friend int qRegisterMetaType(QMetaType meta);
795
796 friend class QVariant;
797 const QtPrivate::QMetaTypeInterface *d_ptr = nullptr;
798};
799
800#undef QT_DEFINE_METATYPE_ID
801
802Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaType::TypeFlags)
803
804#define QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(C, F) \
805 } \
806 Q_DECLARE_TYPEINFO(QtMetaTypePrivate:: C, (F)); \
807 namespace QtMetaTypePrivate {
808
809
810namespace QtMetaTypePrivate {
811
812class QPairVariantInterfaceImpl
813{
814public:
815 const void *_pair;
816 QMetaType _metaType_first;
817 QMetaType _metaType_second;
818
819 typedef void (*getFunc)(const void * const *p, void *);
820
821 getFunc _getFirst;
822 getFunc _getSecond;
823
824 template<class T>
825 static void getFirstImpl(const void * const *pair, void *dataPtr)
826 { *static_cast<typename T::first_type *>(dataPtr) = static_cast<const T*>(*pair)->first; }
827 template<class T>
828 static void getSecondImpl(const void * const *pair, void *dataPtr)
829 { *static_cast<typename T::second_type *>(dataPtr) = static_cast<const T*>(*pair)->second; }
830
831public:
832 template<class T> QPairVariantInterfaceImpl(const T*p)
833 : _pair(p)
834 , _metaType_first(QMetaType::fromType<typename T::first_type>())
835 , _metaType_second(QMetaType::fromType<typename T::second_type>())
836 , _getFirst(getFirstImpl<T>)
837 , _getSecond(getSecondImpl<T>)
838 {
839 }
840
841 constexpr QPairVariantInterfaceImpl()
842 : _pair(nullptr)
843 , _getFirst(nullptr)
844 , _getSecond(nullptr)
845 {
846 }
847
848 inline void first(void *dataPtr) const { _getFirst(&_pair, dataPtr); }
849 inline void second(void *dataPtr) const { _getSecond(&_pair, dataPtr); }
850};
851QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QPairVariantInterfaceImpl, Q_RELOCATABLE_TYPE)
852
853template<typename From>
854struct QPairVariantInterfaceConvertFunctor;
855
856template<typename T, typename U>
857struct QPairVariantInterfaceConvertFunctor<std::pair<T, U> >
858{
859 QPairVariantInterfaceImpl operator()(const std::pair<T, U>& f) const
860 {
861 return QPairVariantInterfaceImpl(&f);
862 }
863};
864
865}
866
867class QObject;
868
869#define QT_FORWARD_DECLARE_SHARED_POINTER_TYPES_ITER(Name) \
870 template <class T> class Name; \
871
872QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(QT_FORWARD_DECLARE_SHARED_POINTER_TYPES_ITER)
873
874namespace QtPrivate
875{
876 namespace detail {
877 template<typename T, typename ODR_VIOLATION_PREVENTER>
878 struct is_complete_helper
879 {
880 template<typename U>
881 static auto check(U *) -> std::integral_constant<bool, sizeof(U) != 0>;
882 static auto check(...) -> std::false_type;
883 using type = decltype(check(static_cast<T *>(nullptr)));
884 };
885 } // namespace detail
886
887 template <typename T, typename ODR_VIOLATION_PREVENTER>
888 struct is_complete : detail::is_complete_helper<std::remove_reference_t<T>, ODR_VIOLATION_PREVENTER>::type {};
889
890 template <typename T> struct MetatypeDecay { using type = T; };
891 template <typename T> struct MetatypeDecay<const T> { using type = T; };
892 template <typename T> struct MetatypeDecay<const T &> { using type = T; };
893
894 template <typename T> struct IsPointerDeclaredOpaque :
895 std::disjunction<std::is_member_pointer<T>,
896 std::is_function<std::remove_pointer_t<T>>>
897 {};
898 template <> struct IsPointerDeclaredOpaque<void *> : std::true_type {};
899 template <> struct IsPointerDeclaredOpaque<const void *> : std::true_type {};
900
901 // Note: this does not check that T = U* isn't pointing to a
902 // forward-declared type. You may want to combine with
903 // checkTypeIsSuitableForMetaType().
904 template<typename T>
905 struct IsPointerToTypeDerivedFromQObject
906 {
907 enum { Value = false };
908 };
909
910 // Specialize to avoid sizeof(void) warning
911 template<>
912 struct IsPointerToTypeDerivedFromQObject<void*>
913 {
914 enum { Value = false };
915 };
916 template<>
917 struct IsPointerToTypeDerivedFromQObject<const void*>
918 {
919 enum { Value = false };
920 };
921 template<>
922 struct IsPointerToTypeDerivedFromQObject<QObject*>
923 {
924 enum { Value = true };
925 };
926
927 template<typename T>
928 struct IsPointerToTypeDerivedFromQObject<T*>
929 {
930 typedef qint8 yes_type;
931 typedef qint64 no_type;
932
933#ifndef QT_NO_QOBJECT
934 static yes_type checkType(QObject* );
935 static yes_type checkType(const QObject* );
936#endif
937 static no_type checkType(...);
938 enum { Value = sizeof(checkType(static_cast<T*>(nullptr))) == sizeof(yes_type) };
939 };
940
941 template<typename T, typename Enable = void>
942 struct IsGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
943
944 template<typename T>
945 struct IsGadgetHelper<T, typename T::QtGadgetHelper>
946 {
947 template <typename X>
948 static char checkType(void (X::*)());
949 static void *checkType(void (T::*)());
950 enum {
951 IsRealGadget = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
952 IsGadgetOrDerivedFrom = true
953 };
954 };
955
956 template <typename T>
957 using IsRealGadget = std::bool_constant<IsGadgetHelper<T>::IsRealGadget>;
958
959 template<typename T, typename Enable = void>
960 struct IsPointerToGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
961
962 template<typename T>
963 struct IsPointerToGadgetHelper<T*, typename T::QtGadgetHelper>
964 {
965 using BaseType = T;
966 template <typename X>
967 static char checkType(void (X::*)());
968 static void *checkType(void (T::*)());
969 enum {
970 IsRealGadget = !IsPointerToTypeDerivedFromQObject<T*>::Value && sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
971 IsGadgetOrDerivedFrom = !IsPointerToTypeDerivedFromQObject<T*>::Value
972 };
973 };
974
975
976 template<typename T> char qt_getEnumMetaObject(const T&);
977
978 template<typename T>
979 struct IsQEnumHelper {
980 static const T &declval();
981 // If the type was declared with Q_ENUM, the friend qt_getEnumMetaObject() declared in the
982 // Q_ENUM macro will be chosen by ADL, and the return type will be QMetaObject*.
983 // Otherwise the chosen overload will be the catch all template function
984 // qt_getEnumMetaObject(T) which returns 'char'
985 enum { Value = sizeof(qt_getEnumMetaObject(declval())) == sizeof(QMetaObject*) };
986 };
987 template<> struct IsQEnumHelper<void> { enum { Value = false }; };
988
989 template<typename T, typename Enable = void>
990 struct MetaObjectForType
991 {
992 static constexpr const QMetaObject *value() { return nullptr; }
993 using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
994 static constexpr MetaObjectFn metaObjectFunction = nullptr;
995 };
996#ifndef QT_NO_QOBJECT
997 template<typename T>
998 struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type>
999 {
1000 static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
1001 static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
1002 };
1003 template<typename T>
1004 struct MetaObjectForType<T, std::enable_if_t<
1005 std::disjunction_v<
1006 std::bool_constant<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>,
1007 std::is_base_of<QObject, T>
1008 >
1009 >>
1010 {
1011 static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
1012 static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
1013 };
1014 template<typename T>
1015 struct MetaObjectForType<T, typename std::enable_if<IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
1016 {
1017 static constexpr const QMetaObject *value()
1018 {
1019 return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject;
1020 }
1021 static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return value(); }
1022 };
1023 template<typename T>
1024 struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type >
1025 {
1026 static constexpr const QMetaObject *value() { return qt_getEnumMetaObject(T()); }
1027 static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return value(); }
1028 };
1029#endif
1030
1031 template<typename T>
1032 struct IsSharedPointerToTypeDerivedFromQObject
1033 {
1034 enum { Value = false };
1035 };
1036
1037 template<typename T>
1038 struct IsSharedPointerToTypeDerivedFromQObject<QSharedPointer<T> > : IsPointerToTypeDerivedFromQObject<T*>
1039 {
1040 };
1041
1042 template<typename T>
1043 struct IsWeakPointerToTypeDerivedFromQObject
1044 {
1045 enum { Value = false };
1046 };
1047
1048 template<typename T>
1049 struct IsWeakPointerToTypeDerivedFromQObject<QWeakPointer<T> > : IsPointerToTypeDerivedFromQObject<T*>
1050 {
1051 };
1052
1053 template<typename T>
1054 struct IsTrackingPointerToTypeDerivedFromQObject
1055 {
1056 enum { Value = false };
1057 };
1058
1059 template<typename T>
1060 struct IsTrackingPointerToTypeDerivedFromQObject<QPointer<T> >
1061 {
1062 enum { Value = true };
1063 };
1064
1065 template<typename T>
1066 struct IsSequentialContainer
1067 {
1068 enum { Value = false };
1069 };
1070
1071 template<typename T>
1072 struct IsAssociativeContainer
1073 {
1074 enum { Value = false };
1075 };
1076
1077 template<typename T, bool = QtPrivate::IsSequentialContainer<T>::Value>
1078 struct SequentialContainerTransformationHelper
1079 {
1080 static bool registerConverter()
1081 {
1082 return false;
1083 }
1084
1085 static bool registerMutableView()
1086 {
1087 return false;
1088 }
1089 };
1090
1091 template<typename T, bool = QMetaTypeId2<typename T::value_type>::Defined>
1092 struct SequentialValueTypeIsMetaType
1093 {
1094 static bool registerConverter()
1095 {
1096 return false;
1097 }
1098
1099 static bool registerMutableView()
1100 {
1101 return false;
1102 }
1103 };
1104
1105 template<typename T>
1106 struct SequentialContainerTransformationHelper<T, true> : SequentialValueTypeIsMetaType<T>
1107 {
1108 };
1109
1110 template<typename T, bool = QtPrivate::IsAssociativeContainer<T>::Value>
1111 struct AssociativeContainerTransformationHelper
1112 {
1113 static bool registerConverter()
1114 {
1115 return false;
1116 }
1117
1118 static bool registerMutableView()
1119 {
1120 return false;
1121 }
1122 };
1123
1124 template<typename T, bool = QMetaTypeId2<typename T::key_type>::Defined>
1125 struct AssociativeKeyTypeIsMetaType
1126 {
1127 static bool registerConverter()
1128 {
1129 return false;
1130 }
1131
1132 static bool registerMutableView()
1133 {
1134 return false;
1135 }
1136 };
1137
1138 template<typename T, bool = QMetaTypeId2<typename T::mapped_type>::Defined>
1139 struct AssociativeMappedTypeIsMetaType
1140 {
1141 static bool registerConverter()
1142 {
1143 return false;
1144 }
1145
1146 static bool registerMutableView()
1147 {
1148 return false;
1149 }
1150 };
1151
1152 template<typename T>
1153 struct AssociativeContainerTransformationHelper<T, true> : AssociativeKeyTypeIsMetaType<T>
1154 {
1155 };
1156
1157 template<typename T, bool = QMetaTypeId2<typename T::first_type>::Defined
1158 && QMetaTypeId2<typename T::second_type>::Defined>
1159 struct IsMetaTypePair
1160 {
1161 static bool registerConverter()
1162 {
1163 return false;
1164 }
1165 };
1166
1167 template<typename T>
1168 struct IsMetaTypePair<T, true>
1169 {
1170 inline static bool registerConverter();
1171 };
1172
1173 template<typename T>
1174 struct IsPair
1175 {
1176 static bool registerConverter()
1177 {
1178 return false;
1179 }
1180 };
1181 template<typename T, typename U>
1182 struct IsPair<std::pair<T, U> > : IsMetaTypePair<std::pair<T, U> > {};
1183
1184 template<typename T>
1185 struct MetaTypePairHelper : IsPair<T> {};
1186
1187 template<typename T, typename = void>
1188 struct MetaTypeSmartPointerHelper
1189 {
1190 static bool registerConverter() { return false; }
1191 };
1192
1193#if QT_CONFIG(future)
1194 template<typename T>
1195 struct MetaTypeQFutureHelper
1196 {
1197 static bool registerConverter() { return false; }
1198 };
1199#endif
1200
1201 template <typename X> static constexpr bool checkTypeIsSuitableForMetaType()
1202 {
1203 using T = typename MetatypeDecay<X>::type;
1204 static_assert(is_complete<T, void>::value || std::is_void_v<T>,
1205 "Meta Types must be fully defined");
1206 static_assert(!std::is_reference_v<T>,
1207 "Meta Types cannot be non-const references or rvalue references.");
1208 if constexpr (std::is_pointer_v<T> && !IsPointerDeclaredOpaque<T>::value) {
1209 using Pointed = std::remove_pointer_t<T>;
1210 static_assert(is_complete<Pointed, void>::value,
1211 "Pointer Meta Types must either point to fully-defined types "
1212 "or be declared with Q_DECLARE_OPAQUE_POINTER(T *)");
1213 }
1214 return true;
1215 }
1216} // namespace QtPrivate
1217
1218template <typename T, int =
1219 QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
1220 QtPrivate::IsRealGadget<T>::value ? QMetaType::IsGadget :
1221 QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget :
1222 QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0>
1223struct QMetaTypeIdQObject
1224{
1225 enum {
1226 Defined = 0
1227 };
1228};
1229
1230template <typename T>
1231struct QMetaTypeId : public QMetaTypeIdQObject<T>
1232{
1233};
1234
1235template <typename T>
1236struct QMetaTypeId2
1237{
1238 using NameAsArrayType = void;
1239 enum { Defined = QMetaTypeId<T>::Defined, IsBuiltIn=false };
1240 static inline constexpr int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); }
1241};
1242
1243template <typename T>
1244struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {};
1245
1246template <typename T>
1247struct QMetaTypeId2<T&>
1248{
1249 using NameAsArrayType = void;
1250 enum { Defined = false, IsBuiltIn = false };
1251 static inline constexpr int qt_metatype_id() { return 0; }
1252};
1253
1254namespace QtPrivate {
1255 template <typename T, bool Defined = QMetaTypeId2<T>::Defined>
1256 struct QMetaTypeIdHelper {
1257 static inline constexpr int qt_metatype_id()
1258 { return QMetaTypeId2<T>::qt_metatype_id(); }
1259 };
1260 template <typename T> struct QMetaTypeIdHelper<T, false> {
1261 static inline constexpr int qt_metatype_id()
1262 { return -1; }
1263 };
1264
1265 // Function pointers don't derive from QObject
1266 template <typename Result, typename... Args>
1267 struct IsPointerToTypeDerivedFromQObject<Result(*)(Args...)> { enum { Value = false }; };
1268
1269 template<typename T>
1270 inline constexpr bool IsQmlListType = false;
1271
1272 template<typename T, bool = std::is_enum<T>::value>
1273 constexpr bool IsUnsignedEnum = false;
1274 template<typename T>
1275 constexpr bool IsUnsignedEnum<T, true> = !std::is_signed_v<std::underlying_type_t<T>>;
1276
1277 template<typename T, bool defined>
1278 struct MetaTypeDefinedHelper
1279 {
1280 enum DefinedType { Defined = defined };
1281 };
1282
1283 template<typename SmartPointer>
1284 struct QSmartPointerConvertFunctor
1285 {
1286 QObject* operator()(const SmartPointer &p) const
1287 {
1288 return p.operator->();
1289 }
1290 };
1291
1292 // hack to delay name lookup to instantiation time by making
1293 // EnableInternalData a dependent name:
1294 template <typename T>
1295 struct EnableInternalDataWrap;
1296
1297 template<typename T>
1298 struct QSmartPointerConvertFunctor<QWeakPointer<T> >
1299 {
1300 QObject* operator()(const QWeakPointer<T> &p) const
1301 {
1302 return QtPrivate::EnableInternalDataWrap<T>::internalData(p);
1303 }
1304 };
1305}
1306
1307template <typename T>
1308int qRegisterNormalizedMetaTypeImplementation(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
1309{
1310#ifndef QT_NO_QOBJECT
1311 Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()),
1312 "qRegisterNormalizedMetaType",
1313 "qRegisterNormalizedMetaType was called with a not normalized type name, "
1314 "please call qRegisterMetaType instead.");
1315#endif
1316
1317 const QMetaType metaType = QMetaType::fromType<T>();
1318 const int id = metaType.id();
1319
1320 QtPrivate::SequentialContainerTransformationHelper<T>::registerConverter();
1321 QtPrivate::SequentialContainerTransformationHelper<T>::registerMutableView();
1322 QtPrivate::AssociativeContainerTransformationHelper<T>::registerConverter();
1323 QtPrivate::AssociativeContainerTransformationHelper<T>::registerMutableView();
1324 QtPrivate::MetaTypePairHelper<T>::registerConverter();
1325 QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter();
1326#if QT_CONFIG(future)
1327 QtPrivate::MetaTypeQFutureHelper<T>::registerConverter();
1328#endif
1329
1330 if (normalizedTypeName != metaType.name())
1331 QMetaType::registerNormalizedTypedef(normalizedTypeName, type: metaType);
1332
1333 return id;
1334}
1335
1336// This primary template calls the -Implementation, like all other specialisations should.
1337// But the split allows to
1338// - in a header:
1339// - define a specialization of this template calling an out-of-line function
1340// (QT_DECL_METATYPE_EXTERN{,_TAGGED})
1341// - in the .cpp file:
1342// - define the out-of-line wrapper to call the -Implementation
1343// (QT_IMPL_METATYPE_EXTERN{,_TAGGED})
1344// The _TAGGED variants let you choose a tag (must be a C identifier) to disambiguate
1345// the out-of-line function; the non-_TAGGED variants use the passed class name as tag.
1346template <typename T>
1347int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
1348{
1349 return qRegisterNormalizedMetaTypeImplementation<T>(normalizedTypeName);
1350}
1351
1352#if defined(QT_BOOTSTRAPPED)
1353#define QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TAG, EXPORT)
1354#define QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TAG)
1355#else
1356#define QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TAG, EXPORT) \
1357 QT_BEGIN_NAMESPACE \
1358 EXPORT int qRegisterNormalizedMetaType_ ## TAG (const QByteArray &); \
1359 template <> inline int qRegisterNormalizedMetaType< TYPE >(const QByteArray &name) \
1360 { return qRegisterNormalizedMetaType_ ## TAG (name); } \
1361 QT_END_NAMESPACE \
1362 Q_DECLARE_METATYPE(TYPE) \
1363 /* end */
1364#define QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TAG) \
1365 int qRegisterNormalizedMetaType_ ## TAG (const QByteArray &name) \
1366 { return qRegisterNormalizedMetaTypeImplementation< TYPE >(name); } \
1367 /* end */
1368#endif
1369#define QT_DECL_METATYPE_EXTERN(TYPE, EXPORT) \
1370 QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TYPE, EXPORT)
1371#define QT_IMPL_METATYPE_EXTERN(TYPE) \
1372 QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TYPE)
1373
1374template <typename T>
1375int qRegisterMetaType(const char *typeName)
1376{
1377#ifdef QT_NO_QOBJECT
1378 QT_PREPEND_NAMESPACE(QByteArray) normalizedTypeName = typeName;
1379#else
1380 QT_PREPEND_NAMESPACE(QByteArray) normalizedTypeName = QMetaObject::normalizedType(type: typeName);
1381#endif
1382 return qRegisterNormalizedMetaType<T>(normalizedTypeName);
1383}
1384
1385template <typename T>
1386inline constexpr int qMetaTypeId()
1387{
1388 if constexpr (bool(QMetaTypeId2<T>::IsBuiltIn)) {
1389 // this has the same result as the below code, but avoids asking the
1390 // compiler to load a global variable whose value we know at compile
1391 // time
1392 return QMetaTypeId2<T>::MetaType;
1393 } else {
1394 return QMetaType::fromType<T>().id();
1395 }
1396}
1397
1398template <typename T>
1399inline constexpr int qRegisterMetaType()
1400{
1401 int id = qMetaTypeId<T>();
1402 return id;
1403}
1404
1405inline int qRegisterMetaType(QMetaType meta)
1406{
1407 return meta.registerHelper();
1408}
1409
1410#ifndef QT_NO_QOBJECT
1411template <typename T>
1412struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
1413{
1414 enum {
1415 Defined = 1
1416 };
1417
1418 static int qt_metatype_id()
1419 {
1420 Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1421 if (const int id = metatype_id.loadAcquire())
1422 return id;
1423 const char *const cName = T::staticMetaObject.className();
1424 QByteArray typeName;
1425 typeName.reserve(asize: strlen(s: cName) + 1);
1426 typeName.append(s: cName).append(c: '*');
1427 const int newId = qRegisterNormalizedMetaType<T *>(typeName);
1428 metatype_id.storeRelease(newValue: newId);
1429 return newId;
1430 }
1431};
1432
1433template <typename T>
1434struct QMetaTypeIdQObject<T, QMetaType::IsGadget>
1435{
1436 enum {
1437 Defined = std::is_default_constructible<T>::value
1438 };
1439
1440 static int qt_metatype_id()
1441 {
1442 Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1443 if (const int id = metatype_id.loadAcquire())
1444 return id;
1445 const char *const cName = T::staticMetaObject.className();
1446 const int newId = qRegisterNormalizedMetaType<T>(cName);
1447 metatype_id.storeRelease(newValue: newId);
1448 return newId;
1449 }
1450};
1451
1452template <typename T>
1453struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget>
1454{
1455 enum {
1456 Defined = 1
1457 };
1458
1459 static int qt_metatype_id()
1460 {
1461 Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1462 if (const int id = metatype_id.loadAcquire())
1463 return id;
1464 const char *const cName = T::staticMetaObject.className();
1465 QByteArray typeName;
1466 typeName.reserve(asize: strlen(s: cName) + 1);
1467 typeName.append(s: cName).append(c: '*');
1468 const int newId = qRegisterNormalizedMetaType<T *>(typeName);
1469 metatype_id.storeRelease(newValue: newId);
1470 return newId;
1471 }
1472};
1473
1474template <typename T>
1475struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
1476{
1477 enum {
1478 Defined = 1
1479 };
1480
1481 static int qt_metatype_id()
1482 {
1483 Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1484 if (const int id = metatype_id.loadAcquire())
1485 return id;
1486 const char *eName = qt_getEnumName(T());
1487 const char *cName = qt_getEnumMetaObject(T())->className();
1488 QByteArray typeName;
1489 typeName.reserve(asize: strlen(s: cName) + 2 + strlen(s: eName));
1490 typeName.append(s: cName).append(s: "::").append(s: eName);
1491 const int newId = qRegisterNormalizedMetaType<T>(typeName);
1492 metatype_id.storeRelease(newValue: newId);
1493 return newId;
1494 }
1495};
1496#endif
1497
1498#define Q_DECLARE_OPAQUE_POINTER(POINTER) \
1499 QT_BEGIN_NAMESPACE namespace QtPrivate { \
1500 template <> struct IsPointerDeclaredOpaque<POINTER> \
1501 : std::true_type {}; \
1502 } QT_END_NAMESPACE \
1503 /**/
1504
1505#ifndef Q_MOC_RUN
1506#define Q_DECLARE_METATYPE(TYPE) Q_DECLARE_METATYPE_IMPL(TYPE)
1507#define Q_DECLARE_METATYPE_IMPL(TYPE) \
1508 QT_BEGIN_NAMESPACE \
1509 template <> \
1510 struct QMetaTypeId< TYPE > \
1511 { \
1512 enum { Defined = 1 }; \
1513 static_assert(QtPrivate::checkTypeIsSuitableForMetaType<TYPE>()); \
1514 static int qt_metatype_id() \
1515 { \
1516 Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1517 if (const int id = metatype_id.loadAcquire()) \
1518 return id; \
1519 constexpr auto arr = QtPrivate::typenameHelper<TYPE>(); \
1520 auto name = arr.data(); \
1521 if (QByteArrayView(name) == (#TYPE)) { \
1522 const int id = qRegisterNormalizedMetaType<TYPE>(name); \
1523 metatype_id.storeRelease(id); \
1524 return id; \
1525 } \
1526 const int newId = qRegisterMetaType< TYPE >(#TYPE); \
1527 metatype_id.storeRelease(newId); \
1528 return newId; \
1529 } \
1530 }; \
1531 QT_END_NAMESPACE
1532#endif // Q_MOC_RUN
1533
1534#define Q_DECLARE_BUILTIN_METATYPE(TYPE, METATYPEID, NAME) \
1535 QT_BEGIN_NAMESPACE \
1536 template<> struct QMetaTypeId2<NAME> \
1537 { \
1538 using NameAsArrayType = std::array<char, sizeof(#NAME)>; \
1539 enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID }; \
1540 static inline constexpr int qt_metatype_id() { return METATYPEID; } \
1541 static constexpr NameAsArrayType nameAsArray = { #NAME }; \
1542 }; \
1543 QT_END_NAMESPACE
1544
1545#define QT_FORWARD_DECLARE_STATIC_TYPES_ITER(TypeName, TypeId, Name) \
1546 class Name;
1547
1548QT_FOR_EACH_STATIC_CORE_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
1549QT_FOR_EACH_STATIC_GUI_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
1550QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
1551
1552#undef QT_FORWARD_DECLARE_STATIC_TYPES_ITER
1553
1554#define Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE) \
1555QT_BEGIN_NAMESPACE \
1556template <typename T> \
1557struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
1558{ \
1559 enum { \
1560 Defined = QMetaTypeId2<T>::Defined \
1561 }; \
1562 static int qt_metatype_id() \
1563 { \
1564 Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1565 if (const int id = metatype_id.loadRelaxed()) \
1566 return id; \
1567 const char *tName = QMetaType::fromType<T>().name(); \
1568 Q_ASSERT(tName); \
1569 const size_t tNameLen = qstrlen(tName); \
1570 QByteArray typeName; \
1571 typeName.reserve(sizeof(#SINGLE_ARG_TEMPLATE) + 1 + tNameLen + 1 + 1); \
1572 typeName.append(#SINGLE_ARG_TEMPLATE, int(sizeof(#SINGLE_ARG_TEMPLATE)) - 1) \
1573 .append('<').append(tName, tNameLen); \
1574 typeName.append('>'); \
1575 const int newId = qRegisterNormalizedMetaType< SINGLE_ARG_TEMPLATE<T> >(typeName); \
1576 metatype_id.storeRelease(newId); \
1577 return newId; \
1578 } \
1579}; \
1580QT_END_NAMESPACE
1581
1582#define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \
1583QT_BEGIN_NAMESPACE \
1584template<typename T, typename U> \
1585struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \
1586{ \
1587 enum { \
1588 Defined = QMetaTypeId2<T>::Defined && QMetaTypeId2<U>::Defined \
1589 }; \
1590 static int qt_metatype_id() \
1591 { \
1592 Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1593 if (const int id = metatype_id.loadAcquire()) \
1594 return id; \
1595 const char *tName = QMetaType::fromType<T>().name(); \
1596 const char *uName = QMetaType::fromType<U>().name(); \
1597 Q_ASSERT(tName); \
1598 Q_ASSERT(uName); \
1599 const size_t tNameLen = qstrlen(tName); \
1600 const size_t uNameLen = qstrlen(uName); \
1601 QByteArray typeName; \
1602 typeName.reserve(sizeof(#DOUBLE_ARG_TEMPLATE) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \
1603 typeName.append(#DOUBLE_ARG_TEMPLATE, int(sizeof(#DOUBLE_ARG_TEMPLATE)) - 1) \
1604 .append('<').append(tName, tNameLen).append(',').append(uName, uNameLen); \
1605 typeName.append('>'); \
1606 const int newId = qRegisterNormalizedMetaType< DOUBLE_ARG_TEMPLATE<T, U> >(typeName); \
1607 metatype_id.storeRelease(newId); \
1608 return newId; \
1609 } \
1610}; \
1611QT_END_NAMESPACE
1612
1613namespace QtPrivate {
1614
1615template<typename T, bool /* isSharedPointerToQObjectDerived */ = false>
1616struct SharedPointerMetaTypeIdHelper
1617{
1618 enum {
1619 Defined = 0
1620 };
1621 static int qt_metatype_id()
1622 {
1623 return -1;
1624 }
1625};
1626
1627}
1628
1629#define Q_DECLARE_SMART_POINTER_METATYPE(SMART_POINTER) \
1630QT_BEGIN_NAMESPACE \
1631namespace QtPrivate { \
1632template<typename T> \
1633struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
1634{ \
1635 enum { \
1636 Defined = 1 \
1637 }; \
1638 static int qt_metatype_id() \
1639 { \
1640 Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1641 if (const int id = metatype_id.loadAcquire()) \
1642 return id; \
1643 const char * const cName = T::staticMetaObject.className(); \
1644 QByteArray typeName; \
1645 typeName.reserve(sizeof(#SMART_POINTER) + 1 + strlen(cName) + 1); \
1646 typeName.append(#SMART_POINTER, int(sizeof(#SMART_POINTER)) - 1) \
1647 .append('<').append(cName).append('>'); \
1648 const int newId = qRegisterNormalizedMetaType< SMART_POINTER<T> >(typeName); \
1649 metatype_id.storeRelease(newId); \
1650 return newId; \
1651 } \
1652}; \
1653template<typename T> \
1654struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \
1655 typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value && !std::is_const_v<T>>::type> \
1656{ \
1657 static bool registerConverter() \
1658 { \
1659 const QMetaType to = QMetaType(QMetaType::QObjectStar); \
1660 if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<SMART_POINTER<T>>(), to)) { \
1661 QtPrivate::QSmartPointerConvertFunctor<SMART_POINTER<T> > o; \
1662 return QMetaType::registerConverter<SMART_POINTER<T>, QObject*>(o); \
1663 } \
1664 return true; \
1665 } \
1666}; \
1667} \
1668template <typename T> \
1669struct QMetaTypeId< SMART_POINTER<T> > \
1670 : QtPrivate::SharedPointerMetaTypeIdHelper< SMART_POINTER<T>, \
1671 QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value> \
1672{ \
1673};\
1674QT_END_NAMESPACE
1675
1676#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(SINGLE_ARG_TEMPLATE) \
1677 QT_BEGIN_NAMESPACE \
1678 namespace QtPrivate { \
1679 template<typename T> \
1680 struct IsSequentialContainer<SINGLE_ARG_TEMPLATE<T> > \
1681 { \
1682 enum { Value = true }; \
1683 }; \
1684 } \
1685 QT_END_NAMESPACE \
1686 Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE)
1687
1688#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER(TEMPLATENAME) \
1689 Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(TEMPLATENAME)
1690
1691QT_END_NAMESPACE
1692
1693QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER)
1694
1695#undef Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER
1696
1697Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::vector)
1698Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::list)
1699
1700#define Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(TEMPLATENAME) \
1701 QT_BEGIN_NAMESPACE \
1702 namespace QtPrivate { \
1703 template<typename T, typename U> \
1704 struct IsAssociativeContainer<TEMPLATENAME<T, U> > \
1705 { \
1706 enum { Value = true }; \
1707 }; \
1708 } \
1709 QT_END_NAMESPACE \
1710 Q_DECLARE_METATYPE_TEMPLATE_2ARG(TEMPLATENAME)
1711
1712Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QHash)
1713Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QMap)
1714Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::map)
1715
1716Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::pair)
1717
1718#define Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER(TEMPLATENAME) \
1719 Q_DECLARE_SMART_POINTER_METATYPE(TEMPLATENAME)
1720
1721QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER)
1722
1723QT_BEGIN_NAMESPACE
1724
1725#undef Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER
1726
1727QT_END_NAMESPACE
1728
1729QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
1730
1731
1732QT_BEGIN_NAMESPACE
1733
1734namespace QtPrivate {
1735// out-of-line helpers to reduce template code bloat ("SCARY") and improve compile times:
1736Q_CORE_EXPORT bool hasRegisteredConverterFunctionToPairVariantInterface(QMetaType m);
1737Q_CORE_EXPORT bool hasRegisteredConverterFunctionToIterableMetaSequence(QMetaType m);
1738Q_CORE_EXPORT bool hasRegisteredMutableViewFunctionToIterableMetaSequence(QMetaType m);
1739Q_CORE_EXPORT bool hasRegisteredConverterFunctionToIterableMetaAssociation(QMetaType m);
1740Q_CORE_EXPORT bool hasRegisteredMutableViewFunctionToIterableMetaAssociation(QMetaType m);
1741}
1742
1743template <typename T>
1744inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter()
1745{
1746 if (!QtPrivate::hasRegisteredConverterFunctionToPairVariantInterface(m: QMetaType::fromType<T>())) {
1747 QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o;
1748 return QMetaType::registerConverter<T, QtMetaTypePrivate::QPairVariantInterfaceImpl>(o);
1749 }
1750 return true;
1751}
1752
1753namespace QtPrivate {
1754
1755template<typename From>
1756struct QSequentialIterableConvertFunctor
1757{
1758 QIterable<QMetaSequence> operator()(const From &f) const
1759 {
1760 return QIterable<QMetaSequence>(QMetaSequence::fromContainer<From>(), &f);
1761 }
1762};
1763
1764template<typename From>
1765struct QSequentialIterableMutableViewFunctor
1766{
1767 QIterable<QMetaSequence> operator()(From &f) const
1768 {
1769 return QIterable<QMetaSequence>(QMetaSequence::fromContainer<From>(), &f);
1770 }
1771};
1772
1773template<typename T>
1774struct SequentialValueTypeIsMetaType<T, true>
1775{
1776 static bool registerConverter()
1777 {
1778 if (!QtPrivate::hasRegisteredConverterFunctionToIterableMetaSequence(m: QMetaType::fromType<T>())) {
1779 QSequentialIterableConvertFunctor<T> o;
1780 return QMetaType::registerConverter<T, QIterable<QMetaSequence>>(o);
1781 }
1782 return true;
1783 }
1784
1785 static bool registerMutableView()
1786 {
1787 if (!QtPrivate::hasRegisteredMutableViewFunctionToIterableMetaSequence(m: QMetaType::fromType<T>())) {
1788 QSequentialIterableMutableViewFunctor<T> o;
1789 return QMetaType::registerMutableView<T, QIterable<QMetaSequence>>(o);
1790 }
1791 return true;
1792 }
1793};
1794
1795template<typename From>
1796struct QAssociativeIterableConvertFunctor
1797{
1798 QIterable<QMetaAssociation> operator()(const From &f) const
1799 {
1800 return QIterable<QMetaAssociation>(QMetaAssociation::fromContainer<From>(), &f);
1801 }
1802};
1803
1804template<typename From>
1805struct QAssociativeIterableMutableViewFunctor
1806{
1807 QIterable<QMetaAssociation> operator()(From &f) const
1808 {
1809 return QIterable<QMetaAssociation>(QMetaAssociation::fromContainer<From>(), &f);
1810 }
1811};
1812
1813// Mapped type can be omitted, for example in case of a set.
1814// However, if it is available, we want to instantiate the metatype here.
1815template<typename T>
1816struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T>
1817{
1818 static bool registerConverter()
1819 {
1820 if (!QtPrivate::hasRegisteredConverterFunctionToIterableMetaAssociation(m: QMetaType::fromType<T>())) {
1821 QAssociativeIterableConvertFunctor<T> o;
1822 return QMetaType::registerConverter<T, QIterable<QMetaAssociation>>(o);
1823 }
1824 return true;
1825 }
1826
1827 static bool registerMutableView()
1828 {
1829 if (!QtPrivate::hasRegisteredMutableViewFunctionToIterableMetaAssociation(m: QMetaType::fromType<T>())) {
1830 QAssociativeIterableMutableViewFunctor<T> o;
1831 return QMetaType::registerMutableView<T, QIterable<QMetaAssociation>>(o);
1832 }
1833 return true;
1834 }
1835};
1836
1837struct QTypeNormalizer
1838{
1839 char *output;
1840 int len = 0;
1841 char last = 0;
1842
1843private:
1844 static constexpr bool is_ident_char(char s)
1845 {
1846 return ((s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || (s >= '0' && s <= '9')
1847 || s == '_');
1848 }
1849 static constexpr bool is_space(char s) { return (s == ' ' || s == '\t' || s == '\n'); }
1850 static constexpr bool is_number(char s) { return s >= '0' && s <= '9'; }
1851 static constexpr bool starts_with_token(const char *b, const char *e, const char *token,
1852 bool msvcKw = false)
1853 {
1854 while (b != e && *token && *b == *token) {
1855 b++;
1856 token++;
1857 }
1858 if (*token)
1859 return false;
1860#ifdef Q_CC_MSVC
1861 /// On MSVC, keywords like class or struct are not separated with spaces in constexpr
1862 /// context
1863 if (msvcKw && !is_ident_char(*b))
1864 return true;
1865#endif
1866 Q_UNUSED(msvcKw);
1867 return b == e || !is_ident_char(s: *b);
1868 }
1869 static constexpr bool skipToken(const char *&x, const char *e, const char *token,
1870 bool msvcKw = false)
1871 {
1872 if (!starts_with_token(b: x, e, token, msvcKw))
1873 return false;
1874 while (*token++)
1875 x++;
1876 while (x != e && is_space(s: *x))
1877 x++;
1878 return true;
1879 }
1880 static constexpr const char *skipString(const char *x, const char *e)
1881 {
1882 char delim = *x;
1883 x++;
1884 while (x != e && *x != delim) {
1885 if (*x == '\\') {
1886 x++;
1887 if (x == e)
1888 return e;
1889 }
1890 x++;
1891 }
1892 if (x != e)
1893 x++;
1894 return x;
1895 }
1896 static constexpr const char *skipTemplate(const char *x, const char *e, bool stopAtComa = false)
1897 {
1898 int scopeDepth = 0;
1899 int templateDepth = 0;
1900 while (x != e) {
1901 switch (*x) {
1902 case '<':
1903 if (!scopeDepth)
1904 templateDepth++;
1905 break;
1906 case ',':
1907 if (stopAtComa && !scopeDepth && !templateDepth)
1908 return x;
1909 break;
1910 case '>':
1911 if (!scopeDepth)
1912 if (--templateDepth < 0)
1913 return x;
1914 break;
1915 case '(':
1916 case '[':
1917 case '{':
1918 scopeDepth++;
1919 break;
1920 case '}':
1921 case ']':
1922 case ')':
1923 scopeDepth--;
1924 break;
1925 case '\'':
1926 if (is_number(s: x[-1]))
1927 break;
1928 Q_FALLTHROUGH();
1929 case '\"':
1930 x = skipString(x, e);
1931 continue;
1932 }
1933 x++;
1934 }
1935 return x;
1936 }
1937
1938 constexpr void append(char x)
1939 {
1940 last = x;
1941 len++;
1942 if (output)
1943 *output++ = x;
1944 }
1945
1946 constexpr void replaceLast(char x)
1947 {
1948 last = x;
1949 if (output)
1950 *(output - 1) = x;
1951 }
1952
1953 constexpr void appendStr(const char *x)
1954 {
1955 while (*x)
1956 append(x: *x++);
1957 }
1958
1959 constexpr void normalizeIntegerTypes(const char *&begin, const char *end)
1960 {
1961 int numLong = 0;
1962 int numSigned = 0;
1963 int numUnsigned = 0;
1964 int numInt = 0;
1965 int numShort = 0;
1966 int numChar = 0;
1967 while (begin < end) {
1968 if (skipToken(x&: begin, e: end, token: "long")) {
1969 numLong++;
1970 continue;
1971 }
1972 if (skipToken(x&: begin, e: end, token: "int")) {
1973 numInt++;
1974 continue;
1975 }
1976 if (skipToken(x&: begin, e: end, token: "short")) {
1977 numShort++;
1978 continue;
1979 }
1980 if (skipToken(x&: begin, e: end, token: "unsigned")) {
1981 numUnsigned++;
1982 continue;
1983 }
1984 if (skipToken(x&: begin, e: end, token: "signed")) {
1985 numSigned++;
1986 continue;
1987 }
1988 if (skipToken(x&: begin, e: end, token: "char")) {
1989 numChar++;
1990 continue;
1991 }
1992#ifdef Q_CC_MSVC
1993 if (skipToken(begin, end, "__int64")) {
1994 numLong = 2;
1995 continue;
1996 }
1997#endif
1998 break;
1999 }
2000 if (numLong == 2)
2001 append(x: 'q'); // q(u)longlong
2002 if (numSigned && numChar)
2003 appendStr(x: "signed ");
2004 else if (numUnsigned)
2005 appendStr(x: "u");
2006 if (numChar)
2007 appendStr(x: "char");
2008 else if (numShort)
2009 appendStr(x: "short");
2010 else if (numLong == 1)
2011 appendStr(x: "long");
2012 else if (numLong == 2)
2013 appendStr(x: "longlong");
2014 else if (numUnsigned || numSigned || numInt)
2015 appendStr(x: "int");
2016 }
2017
2018 constexpr void skipStructClassOrEnum(const char *&begin, const char *end)
2019 {
2020 // discard 'struct', 'class', and 'enum'; they are optional
2021 // and we don't want them in the normalized signature
2022 skipToken(x&: begin, e: end, token: "struct", msvcKw: true) || skipToken(x&: begin, e: end, token: "class", msvcKw: true)
2023 || skipToken(x&: begin, e: end, token: "enum", msvcKw: true);
2024 }
2025
2026 constexpr void skipQtNamespace(const char *&begin, const char *end)
2027 {
2028#ifdef QT_NAMESPACE
2029 const char *nsbeg = begin;
2030 if (skipToken(nsbeg, end, QT_STRINGIFY(QT_NAMESPACE)) && nsbeg + 2 < end && nsbeg[0] == ':'
2031 && nsbeg[1] == ':') {
2032 begin = nsbeg + 2;
2033 while (begin != end && is_space(*begin))
2034 begin++;
2035 }
2036#else
2037 Q_UNUSED(begin);
2038 Q_UNUSED(end);
2039#endif
2040 }
2041
2042public:
2043#if defined(Q_CC_CLANG) || defined (Q_CC_GNU)
2044 // this is much simpler than the full type normalization below
2045 // the reason is that the signature returned by Q_FUNC_INFO is already
2046 // normalized to the largest degree, and we need to do only small adjustments
2047 constexpr int normalizeTypeFromSignature(const char *begin, const char *end)
2048 {
2049 // bail out if there is an anonymous struct
2050 std::string_view name(begin, end-begin);
2051#if defined (Q_CC_CLANG)
2052 if (name.find(str: "anonymous ") != std::string_view::npos)
2053 return normalizeType(begin, end);
2054#endif
2055 if (name.find(str: "unnamed ") != std::string_view::npos)
2056 return normalizeType(begin, end);
2057 while (begin < end) {
2058 if (*begin == ' ') {
2059 if (last == ',' || last == '>' || last == '<' || last == '*' || last == '&') {
2060 ++begin;
2061 continue;
2062 }
2063 }
2064 if (last == ' ') {
2065 if (*begin == '*' || *begin == '&' || *begin == '(') {
2066 replaceLast(x: *begin);
2067 ++begin;
2068 continue;
2069 }
2070 }
2071 if (!is_ident_char(s: last)) {
2072 skipStructClassOrEnum(begin, end);
2073 if (begin == end)
2074 break;
2075
2076 skipQtNamespace(begin, end);
2077 if (begin == end)
2078 break;
2079
2080 normalizeIntegerTypes(begin, end);
2081 if (begin == end)
2082 break;
2083 }
2084 append(x: *begin);
2085 ++begin;
2086 }
2087 return len;
2088 }
2089#else
2090 // MSVC needs the full normalization, as it puts the const in a different
2091 // place than we expect
2092 constexpr int normalizeTypeFromSignature(const char *begin, const char *end)
2093 { return normalizeType(begin, end); }
2094#endif
2095
2096 constexpr int normalizeType(const char *begin, const char *end, bool adjustConst = true)
2097 {
2098 // Trim spaces
2099 while (begin != end && is_space(s: *begin))
2100 begin++;
2101 while (begin != end && is_space(s: *(end - 1)))
2102 end--;
2103
2104 if (begin == end)
2105 return len;
2106
2107 // Convert 'char const *' into 'const char *'. Start at index 1,
2108 // not 0, because 'const char *' is already OK.
2109 const char *cst = begin + 1;
2110 if (*begin == '\'' || *begin == '"')
2111 cst = skipString(x: begin, e: end);
2112 bool seenStar = false;
2113 bool hasMiddleConst = false;
2114 while (cst < end) {
2115 if (*cst == '\"' || (*cst == '\'' && !is_number(s: cst[-1]))) {
2116 cst = skipString(x: cst, e: end);
2117 if (cst == end)
2118 break;
2119 }
2120
2121 // We mustn't convert 'char * const *' into 'const char **'
2122 // and we must beware of 'Bar<const Bla>'.
2123 if (*cst == '&' || *cst == '*' || *cst == '[') {
2124 seenStar = *cst != '&' || cst != (end - 1);
2125 break;
2126 }
2127 if (*cst == '<') {
2128 cst = skipTemplate(x: cst + 1, e: end);
2129 if (cst == end)
2130 break;
2131 }
2132 cst++;
2133 const char *skipedCst = cst;
2134 if (!is_ident_char(s: *(cst - 1)) && skipToken(x&: skipedCst, e: end, token: "const")) {
2135 const char *testEnd = end;
2136 while (skipedCst < testEnd--) {
2137 if (*testEnd == '*' || *testEnd == '['
2138 || (*testEnd == '&' && testEnd != (end - 1))) {
2139 seenStar = true;
2140 break;
2141 }
2142 if (*testEnd == '>')
2143 break;
2144 }
2145 if (adjustConst && !seenStar) {
2146 if (*(end - 1) == '&')
2147 end--;
2148 } else {
2149 appendStr(x: "const ");
2150 }
2151 normalizeType(begin, end: cst, adjustConst: false);
2152 begin = skipedCst;
2153 hasMiddleConst = true;
2154 break;
2155 }
2156 }
2157 if (skipToken(x&: begin, e: end, token: "const")) {
2158 if (adjustConst && !seenStar) {
2159 if (*(end - 1) == '&')
2160 end--;
2161 } else {
2162 appendStr(x: "const ");
2163 }
2164 }
2165 if (seenStar && adjustConst) {
2166 const char *e = end;
2167 if (*(end - 1) == '&' && *(end - 2) != '&')
2168 e--;
2169 while (begin != e && is_space(s: *(e - 1)))
2170 e--;
2171 const char *token = "tsnoc"; // 'const' reverse, to check if it ends with const
2172 while (*token && begin != e && *(--e) == *token++)
2173 ;
2174 if (!*token && begin != e && !is_ident_char(s: *(e - 1))) {
2175 while (begin != e && is_space(s: *(e - 1)))
2176 e--;
2177 end = e;
2178 }
2179 }
2180
2181 skipStructClassOrEnum(begin, end);
2182 skipQtNamespace(begin, end);
2183
2184 if (skipToken(x&: begin, e: end, token: "QVector")) {
2185 // Replace QVector by QList
2186 appendStr(x: "QList");
2187 }
2188
2189 if (skipToken(x&: begin, e: end, token: "QPair")) {
2190 // replace QPair by std::pair
2191 appendStr(x: "std::pair");
2192 }
2193
2194 if (!hasMiddleConst)
2195 // Normalize the integer types
2196 normalizeIntegerTypes(begin, end);
2197
2198 bool spaceSkiped = true;
2199 while (begin != end) {
2200 char c = *begin++;
2201 if (is_space(s: c)) {
2202 spaceSkiped = true;
2203 } else if ((c == '\'' && !is_number(s: last)) || c == '\"') {
2204 begin--;
2205 auto x = skipString(x: begin, e: end);
2206 while (begin < x)
2207 append(x: *begin++);
2208 } else {
2209 if (spaceSkiped && is_ident_char(s: last) && is_ident_char(s: c))
2210 append(x: ' ');
2211 append(x: c);
2212 spaceSkiped = false;
2213 if (c == '<') {
2214 do {
2215 // template recursion
2216 const char *tpl = skipTemplate(x: begin, e: end, stopAtComa: true);
2217 normalizeType(begin, end: tpl, adjustConst: false);
2218 if (tpl == end)
2219 return len;
2220 append(x: *tpl);
2221 begin = tpl;
2222 } while (*begin++ == ',');
2223 }
2224 }
2225 }
2226 return len;
2227 }
2228};
2229
2230// Normalize the type between begin and end, and store the data in the output. Returns the length.
2231// The idea is to first run this function with nullptr as output to allocate the output with the
2232// size
2233constexpr int qNormalizeType(const char *begin, const char *end, char *output)
2234{
2235 return QTypeNormalizer { .output: output }.normalizeType(begin, end);
2236}
2237
2238template<typename T>
2239struct is_std_pair : std::false_type {};
2240
2241template <typename T1_, typename T2_>
2242struct is_std_pair<std::pair<T1_, T2_>> : std::true_type {
2243 using T1 = T1_;
2244 using T2 = T2_;
2245};
2246
2247namespace TypeNameHelper {
2248template<typename T>
2249constexpr auto typenameHelper()
2250{
2251 if constexpr (is_std_pair<T>::value) {
2252 using T1 = typename is_std_pair<T>::T1;
2253 using T2 = typename is_std_pair<T>::T2;
2254 std::remove_const_t<std::conditional_t<bool (QMetaTypeId2<T1>::IsBuiltIn), typename QMetaTypeId2<T1>::NameAsArrayType, decltype(typenameHelper<T1>())>> t1Name {};
2255 std::remove_const_t<std::conditional_t<bool (QMetaTypeId2<T2>::IsBuiltIn), typename QMetaTypeId2<T2>::NameAsArrayType, decltype(typenameHelper<T2>())>> t2Name {};
2256 if constexpr (bool (QMetaTypeId2<T1>::IsBuiltIn) ) {
2257 t1Name = QMetaTypeId2<T1>::nameAsArray;
2258 } else {
2259 t1Name = typenameHelper<T1>();
2260 }
2261 if constexpr (bool(QMetaTypeId2<T2>::IsBuiltIn)) {
2262 t2Name = QMetaTypeId2<T2>::nameAsArray;
2263 } else {
2264 t2Name = typenameHelper<T2>();
2265 }
2266 constexpr auto nonTypeDependentLen = sizeof("std::pair<,>");
2267 constexpr auto t1Len = t1Name.size() - 1;
2268 constexpr auto t2Len = t2Name.size() - 1;
2269 constexpr auto length = nonTypeDependentLen + t1Len + t2Len;
2270 std::array<char, length + 1> result {};
2271 constexpr auto prefix = "std::pair<";
2272 int currentLength = 0;
2273 for (; currentLength < int(sizeof("std::pair<") - 1); ++currentLength)
2274 result[currentLength] = prefix[currentLength];
2275 for (int i = 0; i < int(t1Len); ++currentLength, ++i)
2276 result[currentLength] = t1Name[i];
2277 result[currentLength++] = ',';
2278 for (int i = 0; i < int(t2Len); ++currentLength, ++i)
2279 result[currentLength] = t2Name[i];
2280 result[currentLength++] = '>';
2281 result[currentLength++] = '\0';
2282 return result;
2283 } else {
2284 constexpr auto prefix = sizeof(
2285#ifdef QT_NAMESPACE
2286 QT_STRINGIFY(QT_NAMESPACE) "::"
2287#endif
2288#if defined(Q_CC_MSVC) && defined(Q_CC_CLANG)
2289 "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper(void) [T = "
2290#elif defined(Q_CC_MSVC)
2291 "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper<"
2292#elif defined(Q_CC_CLANG)
2293 "auto QtPrivate::TypeNameHelper::typenameHelper() [T = "
2294#elif defined(Q_CC_GHS)
2295 "auto QtPrivate::TypeNameHelper::typenameHelper<T>()[with T="
2296#else
2297 "constexpr auto QtPrivate::TypeNameHelper::typenameHelper() [with T = "
2298#endif
2299 ) - 1;
2300#if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
2301 constexpr int suffix = sizeof(">(void)");
2302#else
2303 constexpr int suffix = sizeof("]");
2304#endif
2305
2306#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU_ONLY < 804
2307 auto func = Q_FUNC_INFO;
2308 const char *begin = func + prefix;
2309 const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
2310 // This is an upper bound of the size since the normalized signature should always be smaller
2311 constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix;
2312#else
2313 constexpr auto func = Q_FUNC_INFO;
2314 constexpr const char *begin = func + prefix;
2315 constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
2316 constexpr int len = QTypeNormalizer{ .output: nullptr }.normalizeTypeFromSignature(begin, end);
2317#endif
2318 std::array<char, len + 1> result {};
2319 QTypeNormalizer{ result.data() }.normalizeTypeFromSignature(begin, end);
2320 return result;
2321 }
2322}
2323} // namespace TypeNameHelper
2324using TypeNameHelper::typenameHelper;
2325
2326template<typename T, typename = void>
2327struct BuiltinMetaType : std::integral_constant<int, 0>
2328{
2329};
2330template<typename T>
2331struct BuiltinMetaType<T, std::enable_if_t<QMetaTypeId2<T>::IsBuiltIn>>
2332 : std::integral_constant<int, QMetaTypeId2<T>::MetaType>
2333{
2334};
2335
2336template<typename T, bool = (QTypeTraits::has_operator_equal_v<T> && !std::is_pointer_v<T>)>
2337struct QEqualityOperatorForType
2338{
2339QT_WARNING_PUSH
2340QT_WARNING_DISABLE_FLOAT_COMPARE
2341 static bool equals(const QMetaTypeInterface *, const void *a, const void *b)
2342 { return *reinterpret_cast<const T *>(a) == *reinterpret_cast<const T *>(b); }
2343QT_WARNING_POP
2344};
2345
2346template<typename T>
2347struct QEqualityOperatorForType <T, false>
2348{
2349 static constexpr QMetaTypeInterface::EqualsFn equals = nullptr;
2350};
2351
2352template<typename T, bool = (QTypeTraits::has_operator_less_than_v<T> && !std::is_pointer_v<T>)>
2353struct QLessThanOperatorForType
2354{
2355 static bool lessThan(const QMetaTypeInterface *, const void *a, const void *b)
2356 { return *reinterpret_cast<const T *>(a) < *reinterpret_cast<const T *>(b); }
2357};
2358
2359template<typename T>
2360struct QLessThanOperatorForType <T, false>
2361{
2362 static constexpr QMetaTypeInterface::LessThanFn lessThan = nullptr;
2363};
2364
2365template<typename T, bool = (QTypeTraits::has_ostream_operator_v<QDebug, T> && !std::is_pointer_v<T>)>
2366struct QDebugStreamOperatorForType
2367{
2368 static constexpr QMetaTypeInterface::DebugStreamFn debugStream = nullptr;
2369};
2370
2371#ifndef QT_NO_DEBUG_STREAM
2372template<typename T>
2373struct QDebugStreamOperatorForType <T, true>
2374{
2375 static void debugStream(const QMetaTypeInterface *, QDebug &dbg, const void *a)
2376 { dbg << *reinterpret_cast<const T *>(a); }
2377};
2378#endif
2379
2380template<typename T, bool = QTypeTraits::has_stream_operator_v<QDataStream, T>>
2381struct QDataStreamOperatorForType
2382{
2383 static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
2384 static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
2385};
2386
2387#ifndef QT_NO_DATASTREAM
2388template<typename T>
2389struct QDataStreamOperatorForType <T, true>
2390{
2391 static void dataStreamOut(const QMetaTypeInterface *, QDataStream &ds, const void *a)
2392 { ds << *reinterpret_cast<const T *>(a); }
2393 static void dataStreamIn(const QMetaTypeInterface *, QDataStream &ds, void *a)
2394 { ds >> *reinterpret_cast<T *>(a); }
2395};
2396#endif
2397
2398// Performance optimization:
2399//
2400// Don't add all these symbols to the dynamic symbol tables on ELF systems and
2401// on Darwin. Each library is going to have a copy anyway and QMetaType already
2402// copes with some of these being "hidden" (see QMetaType::idHelper()). We may
2403// as well let the linker know it can always use the local copy.
2404//
2405// This is currently not enabled for GCC due to
2406// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106023
2407
2408#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
2409# pragma GCC visibility push(hidden)
2410#endif
2411
2412// ### Qt 7: consider removing this infrastructure if nothing uses it
2413// (see also getCopyCtr())
2414namespace QMetaTypeCopyTraits
2415{
2416 // Hack to suppress deprecation warnings from types
2417 // with deprecated copy operations, cf. QTBUG-132752
2418 template <typename T>
2419 using HasDeprecatedCopyConstructorTest = typename T::_q_hasDeprecatedCopyConstructor;
2420
2421#if !defined(QT_BOOTSTRAPPED)
2422 Q_CORE_EXPORT void warnAboutDeprecatedCopy(const char *name);
2423#endif
2424} // namespace QMetaTypeCopyTraits
2425
2426template<typename S>
2427class QMetaTypeForType
2428{
2429public:
2430 static constexpr decltype(typenameHelper<S>()) name = typenameHelper<S>();
2431
2432 static constexpr unsigned flags()
2433 {
2434 uint flags = 0;
2435 if constexpr (QTypeInfo<S>::isRelocatable)
2436 flags |= QMetaType::RelocatableType;
2437 if constexpr (!std::is_default_constructible_v<S> || !QTypeInfo<S>::isValueInitializationBitwiseZero)
2438 flags |= QMetaType::NeedsConstruction;
2439 if constexpr (!std::is_trivially_destructible_v<S>)
2440 flags |= QMetaType::NeedsDestruction;
2441 if constexpr (!std::is_trivially_copy_constructible_v<S>)
2442 flags |= QMetaType::NeedsCopyConstruction;
2443 if constexpr (!std::is_trivially_move_constructible_v<S>)
2444 flags |= QMetaType::NeedsMoveConstruction;
2445 if constexpr (IsPointerToTypeDerivedFromQObject<S>::Value)
2446 flags |= QMetaType::PointerToQObject;
2447 if constexpr (IsSharedPointerToTypeDerivedFromQObject<S>::Value)
2448 flags |= QMetaType::SharedPointerToQObject;
2449 if constexpr (IsWeakPointerToTypeDerivedFromQObject<S>::Value)
2450 flags |= QMetaType::WeakPointerToQObject;
2451 if constexpr (IsTrackingPointerToTypeDerivedFromQObject<S>::Value)
2452 flags |= QMetaType::TrackingPointerToQObject;
2453 if constexpr (IsEnumOrFlags<S>::value)
2454 flags |= QMetaType::IsEnumeration;
2455 if constexpr (IsGadgetHelper<S>::IsGadgetOrDerivedFrom)
2456 flags |= QMetaType::IsGadget;
2457 if constexpr (IsPointerToGadgetHelper<S>::IsGadgetOrDerivedFrom)
2458 flags |= QMetaType::PointerToGadget;
2459 if constexpr (std::is_pointer_v<S>)
2460 flags |= QMetaType::IsPointer;
2461 if constexpr (IsUnsignedEnum<S>)
2462 flags |= QMetaType::IsUnsignedEnumeration;
2463 if constexpr (IsQmlListType<S>)
2464 flags |= QMetaType::IsQmlList;
2465 if constexpr (std::is_const_v<std::remove_pointer_t<S>>)
2466 flags |= QMetaType::IsConst;
2467 return flags;
2468 }
2469
2470 static constexpr QMetaTypeInterface::DefaultCtrFn getDefaultCtr()
2471 {
2472 if constexpr (std::is_default_constructible_v<S> && !QTypeInfo<S>::isValueInitializationBitwiseZero) {
2473 return [](const QMetaTypeInterface *, void *addr) { new (addr) S(); };
2474 } else {
2475 return nullptr;
2476 }
2477 }
2478
2479 static constexpr QMetaTypeInterface::CopyCtrFn getCopyCtr()
2480 {
2481 if constexpr (std::is_copy_constructible_v<S> && !std::is_trivially_copy_constructible_v<S>) {
2482 return [](const QMetaTypeInterface *, void *addr, const void *other) {
2483 if constexpr (qxp::is_detected_v<QMetaTypeCopyTraits::HasDeprecatedCopyConstructorTest, S>) {
2484#if !defined(QT_BOOTSTRAPPED)
2485 QMetaTypeCopyTraits::warnAboutDeprecatedCopy(name: getName());
2486#endif
2487 QT_IGNORE_DEPRECATIONS(new (addr) S(*reinterpret_cast<const S *>(other));)
2488 } else {
2489 new (addr) S(*reinterpret_cast<const S *>(other));
2490 }
2491 };
2492 } else {
2493 return nullptr;
2494 }
2495 }
2496
2497 static constexpr QMetaTypeInterface::MoveCtrFn getMoveCtr()
2498 {
2499 if constexpr (std::is_move_constructible_v<S> && !std::is_trivially_move_constructible_v<S>) {
2500 return [](const QMetaTypeInterface *, void *addr, void *other) {
2501 new (addr) S(std::move(*reinterpret_cast<S *>(other)));
2502 };
2503 } else {
2504 return nullptr;
2505 }
2506 }
2507
2508 static constexpr QMetaTypeInterface::DtorFn getDtor()
2509 {
2510 if constexpr (std::is_destructible_v<S> && !std::is_trivially_destructible_v<S>)
2511 return [](const QMetaTypeInterface *, void *addr) {
2512 reinterpret_cast<S *>(addr)->~S();
2513 };
2514 else
2515 return nullptr;
2516 }
2517
2518 static constexpr QMetaTypeInterface::LegacyRegisterOp getLegacyRegister()
2519 {
2520 if constexpr (QMetaTypeId2<S>::Defined && !QMetaTypeId2<S>::IsBuiltIn) {
2521 return []() { QMetaTypeId2<S>::qt_metatype_id(); };
2522 } else {
2523 return nullptr;
2524 }
2525 }
2526
2527 static constexpr const char *getName()
2528 {
2529 if constexpr (bool(QMetaTypeId2<S>::IsBuiltIn)) {
2530 return QMetaTypeId2<S>::nameAsArray.data();
2531 } else {
2532 return name.data();
2533 }
2534 }
2535};
2536
2537template<typename T>
2538struct QMetaTypeInterfaceWrapper
2539{
2540 // if the type ID for T is known at compile-time, then we can declare
2541 // the QMetaTypeInterface object const; otherwise, we declare it as
2542 // non-const and the .typeId is updated by QMetaType::idHelper().
2543 static constexpr bool IsConstMetaTypeInterface = !!BuiltinMetaType<T>::value;
2544 using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>;
2545
2546 static inline InterfaceType metaType = {
2547 /*.revision=*/ QMetaTypeInterface::CurrentRevision,
2548 /*.alignment=*/ alignof(T),
2549 /*.size=*/ sizeof(T),
2550 /*.flags=*/ QMetaTypeForType<T>::flags(),
2551 /*.typeId=*/ BuiltinMetaType<T>::value,
2552 /*.metaObjectFn=*/ MetaObjectForType<T>::metaObjectFunction,
2553 /*.name=*/ QMetaTypeForType<T>::getName(),
2554 /*.defaultCtr=*/ QMetaTypeForType<T>::getDefaultCtr(),
2555 /*.copyCtr=*/ QMetaTypeForType<T>::getCopyCtr(),
2556 /*.moveCtr=*/ QMetaTypeForType<T>::getMoveCtr(),
2557 /*.dtor=*/ QMetaTypeForType<T>::getDtor(),
2558 /*.equals=*/ QEqualityOperatorForType<T>::equals,
2559 /*.lessThan=*/ QLessThanOperatorForType<T>::lessThan,
2560 /*.debugStream=*/ QDebugStreamOperatorForType<T>::debugStream,
2561 /*.dataStreamOut=*/ QDataStreamOperatorForType<T>::dataStreamOut,
2562 /*.dataStreamIn=*/ QDataStreamOperatorForType<T>::dataStreamIn,
2563 /*.legacyRegisterOp=*/ QMetaTypeForType<T>::getLegacyRegister()
2564 };
2565};
2566template<typename T> struct QMetaTypeInterfaceWrapper<T &> {};
2567
2568
2569#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
2570# pragma GCC visibility pop
2571#endif
2572
2573template<>
2574class QMetaTypeInterfaceWrapper<void>
2575{
2576public:
2577 static constexpr QMetaTypeInterface metaType =
2578 {
2579 /*.revision=*/ .revision: 0,
2580 /*.alignment=*/ .alignment: 0,
2581 /*.size=*/ .size: 0,
2582 /*.flags=*/ .flags: 0,
2583 /*.typeId=*/ .typeId: BuiltinMetaType<void>::value,
2584 /*.metaObjectFn=*/ .metaObjectFn: nullptr,
2585 /*.name=*/ .name: "void",
2586 /*.defaultCtr=*/ .defaultCtr: nullptr,
2587 /*.copyCtr=*/ .copyCtr: nullptr,
2588 /*.moveCtr=*/ .moveCtr: nullptr,
2589 /*.dtor=*/ .dtor: nullptr,
2590 /*.equals=*/ .equals: nullptr,
2591 /*.lessThan=*/ .lessThan: nullptr,
2592 /*.debugStream=*/ .debugStream: nullptr,
2593 /*.dataStreamOut=*/ .dataStreamOut: nullptr,
2594 /*.dataStreamIn=*/ .dataStreamIn: nullptr,
2595 /*.legacyRegisterOp=*/ .legacyRegisterOp: nullptr
2596 };
2597};
2598
2599/*
2600 MSVC instantiates extern templates
2601(https://developercommunity.visualstudio.com/t/c11-extern-templates-doesnt-work-for-class-templat/157868)
2602
2603 The INTEGRITY compiler apparently does too.
2604
2605 On Windows (with other compilers or whenever MSVC is fixed), we can't declare
2606 QMetaTypeInterfaceWrapper with __declspec(dllimport) because taking its
2607 address is not a core constant expression.
2608 */
2609#if !defined(QT_BOOTSTRAPPED) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY)
2610
2611#ifdef QT_NO_DATA_RELOCATION
2612# define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
2613 extern template class Q_CORE_EXPORT QMetaTypeForType<Name>;
2614#else
2615# define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
2616 extern template class Q_CORE_EXPORT QMetaTypeForType<Name>; \
2617 extern template struct Q_CORE_EXPORT QMetaTypeInterfaceWrapper<Name>;
2618#endif
2619
2620QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2621QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2622QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2623QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2624QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2625#undef QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER
2626#endif
2627
2628template<typename T>
2629struct QRemovePointerLike
2630{
2631 using type = std::remove_pointer_t<T>;
2632};
2633
2634#define Q_REMOVE_POINTER_LIKE_IMPL(Pointer) \
2635template <typename T> \
2636struct QRemovePointerLike<Pointer<T>> \
2637{ \
2638 using type = T; \
2639};
2640
2641QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_REMOVE_POINTER_LIKE_IMPL)
2642#undef Q_REMOVE_POINTER_LIKE_IMPL
2643
2644template<typename T>
2645constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType()
2646{
2647 // don't check the type is suitable here
2648 using Ty = typename MetatypeDecay<T>::type;
2649 return &QMetaTypeInterfaceWrapper<Ty>::metaType;
2650}
2651
2652// Relaxed vesion of the above, used by moc-generated code to create the
2653// metatype array without requiring types to be complete and allowing
2654// references. Unique is passed to is_complete and must be a different unique
2655// type; if it is void, this function is equal to qMetaTypeInterfaceForType()
2656// above.
2657template<typename Unique, typename T>
2658constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType()
2659{
2660 using Ty = typename MetatypeDecay<T>::type;
2661 using Tz = typename QRemovePointerLike<Ty>::type;
2662
2663 if constexpr (std::is_void_v<Tz>) {
2664 // early out to avoid expanding the rest of the templates
2665 return &QMetaTypeInterfaceWrapper<Ty>::metaType;
2666 } else if constexpr (std::is_void_v<Unique>) {
2667 checkTypeIsSuitableForMetaType<Ty>();
2668 return &QMetaTypeInterfaceWrapper<Ty>::metaType;
2669 } else if constexpr (std::is_reference_v<Tz>) {
2670 return nullptr;
2671 } else if constexpr (!is_complete<Tz, Unique>::value) {
2672 return nullptr;
2673 } else {
2674 // don't check the type is suitable here
2675 return &QMetaTypeInterfaceWrapper<Ty>::metaType;
2676 }
2677}
2678
2679} // namespace QtPrivate
2680
2681template<typename T>
2682constexpr QMetaType QMetaType::fromType()
2683{
2684 QtPrivate::checkTypeIsSuitableForMetaType<T>();
2685 return QMetaType(QtPrivate::qMetaTypeInterfaceForType<T>());
2686}
2687
2688constexpr bool QMetaType::isValid(QT6_IMPL_NEW_OVERLOAD) const noexcept
2689{
2690 return d_ptr;
2691}
2692
2693bool QMetaType::isRegistered(QT6_IMPL_NEW_OVERLOAD) const noexcept
2694{
2695 return d_ptr && d_ptr->typeId.loadRelaxed();
2696}
2697
2698constexpr qsizetype QMetaType::sizeOf() const
2699{
2700 return d_ptr ? d_ptr->size : 0;
2701}
2702
2703constexpr qsizetype QMetaType::alignOf() const
2704{
2705 return d_ptr ? d_ptr->alignment : 0;
2706}
2707
2708constexpr QMetaType::TypeFlags QMetaType::flags() const
2709{
2710 return d_ptr ? TypeFlags(d_ptr->flags) : TypeFlags{};
2711}
2712
2713constexpr const QMetaObject *QMetaType::metaObject() const
2714{
2715 return d_ptr && d_ptr->metaObjectFn ? d_ptr->metaObjectFn(d_ptr) : nullptr;
2716}
2717
2718constexpr const char *QMetaType::name() const
2719{
2720 return d_ptr ? d_ptr->name : nullptr;
2721}
2722
2723inline size_t qHash(QMetaType type, size_t seed = 0)
2724{
2725 // We cannot use d_ptr here since the same type in different DLLs
2726 // might result in different pointers!
2727 return qHash(key: type.id(), seed);
2728}
2729
2730QT_END_NAMESPACE
2731
2732QT_DECL_METATYPE_EXTERN_TAGGED(QtMetaTypePrivate::QPairVariantInterfaceImpl,
2733 QPairVariantInterfaceImpl, Q_CORE_EXPORT)
2734
2735#endif // QMETATYPE_H
2736

source code of qtbase/src/corelib/kernel/qmetatype.h