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

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