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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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