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