diff options
Diffstat (limited to 'src/corelib/kernel/qmetatype.h')
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 873 |
1 files changed, 607 insertions, 266 deletions
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 7c22ff1693..e956d497e9 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -46,11 +46,13 @@ #include <QtCore/qatomic.h> #include <QtCore/qbytearray.h> #include <QtCore/qvarlengtharray.h> +#include <QtCore/qrefcount.h> #ifndef QT_NO_QOBJECT #include <QtCore/qobjectdefs.h> #endif -#include <new> +#include <array> +#include <new> #include <vector> #include <list> #include <map> @@ -109,6 +111,13 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId(); #define QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F) #endif +#if QT_CONFIG(regularexpression) +# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \ + F(QRegularExpression, 44, QRegularExpression) +#else +# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) +#endif + #define QT_FOR_EACH_STATIC_CORE_CLASS(F)\ F(QChar, 7, QChar) \ F(QString, 10, QString) \ @@ -132,7 +141,7 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId(); QT_FOR_EACH_STATIC_EASINGCURVE(F) \ F(QUuid, 30, QUuid) \ F(QVariant, 41, QVariant) \ - F(QRegularExpression, 44, QRegularExpression) \ + QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \ F(QJsonValue, 45, QJsonValue) \ F(QJsonObject, 46, QJsonObject) \ F(QJsonArray, 47, QJsonArray) \ @@ -151,6 +160,13 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId(); F(QVariantHash, 28, QVariantHash) \ F(QByteArrayList, 49, QByteArrayList) \ +#if QT_CONFIG(shortcut) +#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)\ + F(QKeySequence, 75, QKeySequence) +#else +#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F) +#endif + #define QT_FOR_EACH_STATIC_GUI_CLASS(F)\ F(QFont, 64, QFont) \ F(QPixmap, 65, QPixmap) \ @@ -163,11 +179,10 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId(); F(QRegion, 72, QRegion) \ F(QBitmap, 73, QBitmap) \ F(QCursor, 74, QCursor) \ - F(QKeySequence, 75, QKeySequence) \ + QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F) \ F(QPen, 76, QPen) \ F(QTextLength, 77, QTextLength) \ F(QTextFormat, 78, QTextFormat) \ - F(QMatrix, 79, QMatrix) \ F(QTransform, 80, QTransform) \ F(QMatrix4x4, 81, QMatrix4x4) \ F(QVector2D, 82, QVector2D) \ @@ -181,10 +196,6 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId(); #define QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\ F(QSizePolicy, 121, QSizePolicy) \ -// ### FIXME kill that set -#define QT_FOR_EACH_STATIC_HACKS_TYPE(F)\ - F(QMetaTypeId2<qreal>::MetaType, -1, qreal) - // F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, AliasingType, "RealType") #define QT_FOR_EACH_STATIC_ALIAS_TYPE(F)\ F(ULong, -1, ulong, "unsigned long") \ @@ -201,10 +212,11 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId(); F(UInt, -1, uint, "quint32") \ F(LongLong, -1, qlonglong, "qint64") \ F(ULongLong, -1, qulonglong, "quint64") \ + F(QVariantList, -1, QVariantList, "QVector<QVariant>") \ F(QVariantList, -1, QVariantList, "QList<QVariant>") \ F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \ F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \ - F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \ + F(QByteArrayList, -1, QByteArrayList, "QVector<QByteArray>") \ #define QT_FOR_EACH_STATIC_TYPE(F)\ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\ @@ -219,7 +231,6 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId(); TypeName = Id, #define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \ - F(QList) \ F(QVector) \ F(QQueue) \ F(QStack) \ @@ -242,6 +253,9 @@ struct QMetaObject; namespace QtPrivate { + +class QMetaTypeInterface; + /*! This template is used for implicit conversion from type From to type To. \internal @@ -421,13 +435,6 @@ struct ConverterFunctor : public AbstractConverterFunction } class Q_CORE_EXPORT QMetaType { - enum ExtensionFlag { NoExtensionFlags, - CreateEx = 0x1, DestroyEx = 0x2, - ConstructEx = 0x4, DestructEx = 0x8, - NameEx = 0x10, SizeEx = 0x20, - CtorEx = 0x40, DtorEx = 0x80, - FlagsEx = 0x100, MetaObjectEx = 0x200 - }; public: #ifndef Q_CLANG_QDOC // The code that actually gets compiled. @@ -472,7 +479,7 @@ public: QFont = 64, QPixmap = 65, QBrush = 66, QColor = 67, QPalette = 68, QIcon = 69, QImage = 70, QPolygon = 71, QRegion = 72, QBitmap = 73, QCursor = 74, QKeySequence = 75, QPen = 76, QTextLength = 77, QTextFormat = 78, - QMatrix = 79, QTransform = 80, QMatrix4x4 = 81, QVector2D = 82, + QTransform = 80, QMatrix4x4 = 81, QVector2D = 82, QVector3D = 83, QVector4D = 84, QQuaternion = 85, QPolygonF = 86, QColorSpace = 87, // Widget types @@ -494,20 +501,11 @@ public: TrackingPointerToQObject = 0x80, WasDeclaredAsMetaType = 0x100, IsGadget = 0x200, - PointerToGadget = 0x400 + PointerToGadget = 0x400, + IsPointer = 0x800, }; Q_DECLARE_FLAGS(TypeFlags, TypeFlag) - typedef void (*Deleter)(void *); - typedef void *(*Creator)(const void *); - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - typedef void (*Destructor)(void *); - typedef void *(*Constructor)(void *, const void *); // TODO Qt6: remove me -#endif - typedef void (*TypedDestructor)(int, void *); - typedef void *(*TypedConstructor)(int, void *, const void *); - typedef void (*SaveOperator)(QDataStream &, const void *); typedef void (*LoadOperator)(QDataStream &, void *); #ifndef QT_NO_DATASTREAM @@ -516,41 +514,8 @@ public: static void registerStreamOperators(int type, SaveOperator saveOp, LoadOperator loadOp); #endif - static int registerType(const char *typeName, Deleter deleter, - Creator creator); - static int registerType(const char *typeName, Deleter deleter, - Creator creator, - Destructor destructor, - Constructor constructor, - int size, - QMetaType::TypeFlags flags, - const QMetaObject *metaObject); - static int registerType(const char *typeName, - TypedDestructor destructor, - TypedConstructor constructor, - int size, - QMetaType::TypeFlags flags, - const QMetaObject *metaObject); - static bool unregisterType(int type); - static int registerNormalizedType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, Deleter deleter, - Creator creator, - Destructor destructor, - Constructor constructor, - int size, - QMetaType::TypeFlags flags, - const QMetaObject *metaObject); - static int registerNormalizedType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, Destructor destructor, - Constructor constructor, - int size, - QMetaType::TypeFlags flags, - const QMetaObject *metaObject); - static int registerNormalizedType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, TypedDestructor destructor, - TypedConstructor constructor, - int size, - QMetaType::TypeFlags flags, - const QMetaObject *metaObject); - static int registerTypedef(const char *typeName, int aliasId); - static int registerNormalizedTypedef(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, int aliasId); + static void registerNormalizedTypedef(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, QMetaType type); + static int type(const char *typeName); static int type(const QT_PREPEND_NAMESPACE(QByteArray) &typeName); @@ -560,10 +525,6 @@ public: static const QMetaObject *metaObjectForType(int type); static bool isRegistered(int type); static void *create(int type, const void *copy = nullptr); -#if QT_DEPRECATED_SINCE(5, 0) - QT_DEPRECATED static void *construct(int type, const void *copy = nullptr) - { return create(type, copy); } -#endif static void destroy(int type, void *data); static void *construct(int type, void *where, const void *copy); static void destruct(int type, void *where); @@ -573,32 +534,37 @@ public: static bool load(QDataStream &stream, int type, void *data); #endif - explicit QMetaType(const int type = QMetaType::UnknownType); // ### Qt6: drop const - inline ~QMetaType(); + explicit QMetaType(int type); + explicit QMetaType(QtPrivate::QMetaTypeInterface *d); + QMetaType(); + ~QMetaType(); + QMetaType(const QMetaType &other); + QMetaType &operator=(const QMetaType &); + QMetaType(QMetaType &&other) : d_ptr(other.d_ptr) { other.d_ptr = nullptr; } + QMetaType &operator=(QMetaType &&other) + { + qSwap(d_ptr, other.d_ptr); + return *this; + } - inline bool isValid() const; - inline bool isRegistered() const; - inline int id() const; - inline int sizeOf() const; - inline TypeFlags flags() const; - inline const QMetaObject *metaObject() const; + bool isValid() const; + bool isRegistered() const; + int id() const; + int sizeOf() const; + TypeFlags flags() const; + const QMetaObject *metaObject() const; QT_PREPEND_NAMESPACE(QByteArray) name() const; - inline void *create(const void *copy = nullptr) const; - inline void destroy(void *data) const; - inline void *construct(void *where, const void *copy = nullptr) const; - inline void destruct(void *data) const; + void *create(const void *copy = nullptr) const; + void destroy(void *data) const; + void *construct(void *where, const void *copy = nullptr) const; + void destruct(void *data) const; template<typename T> - static QMetaType fromType() - { return QMetaType(qMetaTypeId<T>()); } - - friend bool operator==(const QMetaType &a, const QMetaType &b) - { return a.m_typeId == b.m_typeId; } - - friend bool operator!=(const QMetaType &a, const QMetaType &b) - { return a.m_typeId != b.m_typeId; } + static QMetaType fromType(); + friend bool operator==(const QMetaType &a, const QMetaType &b) { return a.id() == b.id(); } + friend bool operator!=(const QMetaType &a, const QMetaType &b) { return !(a == b); } public: template<typename T> @@ -716,41 +682,11 @@ public: static bool hasRegisteredConverterFunction(int fromTypeId, int toTypeId); -private: - static QMetaType typeInfo(const int type); - inline QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info, - TypedConstructor creator, - TypedDestructor deleter, - SaveOperator saveOp, - LoadOperator loadOp, - Constructor constructor, - Destructor destructor, - uint sizeOf, - uint theTypeFlags, - int typeId, - const QMetaObject *metaObject); - QMetaType(const QMetaType &other); - QMetaType &operator =(const QMetaType &); - inline bool isExtended(const ExtensionFlag flag) const { return m_extensionFlags & flag; } - - // Methods used for future binary compatible extensions - void ctor(const QMetaTypeInterface *info); - void dtor(); - uint sizeExtended() const; - QMetaType::TypeFlags flagsExtended() const; - const QMetaObject *metaObjectExtended() const; - void *createExtended(const void *copy = nullptr) const; - void destroyExtended(void *data) const; - void *constructExtended(void *where, const void *copy = nullptr) const; - void destructExtended(void *data) const; - static bool registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type); #ifndef QT_NO_DEBUG_STREAM static bool registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f, int type); #endif -// ### Qt6: FIXME: Remove the special Q_CC_MSVC handling, it was introduced to maintain BC. -#if !defined(Q_NO_TEMPLATE_FRIENDS) && !defined(Q_CC_MSVC) #ifndef Q_CLANG_QDOC template<typename, bool> friend struct QtPrivate::ValueTypeIsMetaType; template<typename, typename> friend struct QtPrivate::ConverterMemberFunction; @@ -760,25 +696,11 @@ private: template<typename, bool> friend struct QtPrivate::IsMetaTypePair; template<typename, typename> friend struct QtPrivate::MetaTypeSmartPointerHelper; #endif -#else -public: -#endif static bool registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to); static void unregisterConverterFunction(int from, int to); private: - - TypedConstructor m_typedConstructor; - TypedDestructor m_typedDestructor; - SaveOperator m_saveOp; - LoadOperator m_loadOp; - Constructor m_constructor; - Destructor m_destructor; - void *m_extension; // space reserved for future use - uint m_size; - uint m_typeFlags; - uint m_extensionFlags; - int m_typeId; - const QMetaObject *m_metaObject; + friend class QVariant; + QtPrivate::QMetaTypeInterface *d_ptr = nullptr; }; #undef QT_DEFINE_METATYPE_ID @@ -1052,10 +974,6 @@ struct ContainerAPI : CapabilitiesImpl<T> }; template<typename T> -struct ContainerAPI<QList<T> > : CapabilitiesImpl<QList<T> > -{ static int size(const QList<T> *t) { return t->size(); } }; - -template<typename T> struct ContainerAPI<QVector<T> > : CapabilitiesImpl<QVector<T> > { static int size(const QVector<T> *t) { return t->size(); } }; @@ -1085,7 +1003,7 @@ public: // uint _iteratorCapabilities:4; // uint _revision:3; // uint _containerCapabilities:4; - // uint _unused:21;*/ + // uint _unused:21; typedef int(*sizeFunc)(const void *p); typedef const void * (*atFunc)(const void *p, int); typedef void (*moveIteratorFunc)(const void *p, void **); @@ -1577,33 +1495,38 @@ namespace QtPrivate template<typename T, typename Enable = void> struct MetaObjectForType { - static inline const QMetaObject *value() { return nullptr; } + static constexpr inline const QMetaObject *value() { return nullptr; } }; +#ifndef QT_NO_QOBJECT template<> struct MetaObjectForType<void> { - static inline const QMetaObject *value() { return nullptr; } + static constexpr inline const QMetaObject *value() { return nullptr; } }; template<typename T> struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> { - static inline const QMetaObject *value() { return &T::staticMetaObject; } + static constexpr inline const QMetaObject *value() { return &T::staticMetaObject; } }; template<typename T> struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>::type> { - static inline const QMetaObject *value() { return &T::staticMetaObject; } + static constexpr inline const QMetaObject *value() { return &T::staticMetaObject; } }; template<typename T> struct MetaObjectForType<T, typename std::enable_if<IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom>::type> { - static inline const QMetaObject *value() { return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject; } + static constexpr inline const QMetaObject *value() + { + return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject; + } }; template<typename T> struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type > { - static inline const QMetaObject *value() { return qt_getEnumMetaObject(T()); } + static constexpr inline const QMetaObject *value() { return qt_getEnumMetaObject(T()); } }; +#endif template<typename T> struct IsSharedPointerToTypeDerivedFromQObject @@ -1810,6 +1733,7 @@ namespace QtPrivate { | (std::is_enum<T>::value ? QMetaType::IsEnumeration : 0) | (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0) | (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0) + | (QTypeInfo<T>::isPointer ? QMetaType::IsPointer : 0) }; }; @@ -1846,31 +1770,20 @@ namespace QtPrivate { template <typename T> int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName #ifndef Q_CLANG_QDOC - , T * dummy = 0 - , typename QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::DefinedType defined = QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::Defined + , T * = 0 + , typename QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::DefinedType = QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::Defined #endif ) { #ifndef QT_NO_QOBJECT Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), "qRegisterNormalizedMetaType", "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead."); #endif - const int typedefOf = dummy ? -1 : QtPrivate::QMetaTypeIdHelper<T>::qt_metatype_id(); - if (typedefOf != -1) - return QMetaType::registerNormalizedTypedef(normalizedTypeName, typedefOf); - - QMetaType::TypeFlags flags(QtPrivate::QMetaTypeTypeFlags<T>::Flags); - if (defined) - flags |= QMetaType::WasDeclaredAsMetaType; - - const int id = QMetaType::registerNormalizedType(normalizedTypeName, - QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct, - QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Construct, - int(sizeof(T)), - flags, - QtPrivate::MetaObjectForType<T>::value()); + const QMetaType metaType = QMetaType::fromType<T>(); + const int id = metaType.id(); if (id > 0) { + QMetaType::registerNormalizedTypedef(normalizedTypeName, metaType); QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id); QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id); QtPrivate::MetaTypePairHelper<T>::registerConverter(id); @@ -1913,8 +1826,11 @@ void qRegisterMetaTypeStreamOperators(const char *typeName template <typename T> inline Q_DECL_CONSTEXPR int qMetaTypeId() { - Q_STATIC_ASSERT_X(QMetaTypeId2<T>::Defined, "Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system"); - return QMetaTypeId2<T>::qt_metatype_id(); + if constexpr (bool(QMetaTypeId2<T>::IsBuiltIn)) { + return QMetaTypeId2<T>::MetaType; + } else { + return QMetaType::fromType<T>().id(); + } } template <typename T> @@ -2080,6 +1996,7 @@ inline int qRegisterMetaTypeStreamOperators() { \ enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID }; \ static inline Q_DECL_CONSTEXPR int qt_metatype_id() { return METATYPEID; } \ + static constexpr const char * const name = #NAME; \ }; \ QT_END_NAMESPACE @@ -2098,7 +2015,7 @@ typedef QHash<QString, QVariant> QVariantHash; #ifdef Q_CLANG_QDOC class QByteArrayList; #else -typedef QList<QByteArray> QByteArrayList; +typedef QVector<QByteArray> QByteArrayList; #endif #define Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE) \ @@ -2121,8 +2038,6 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \ typeName.reserve(int(sizeof(#SINGLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + 1); \ typeName.append(#SINGLE_ARG_TEMPLATE, int(sizeof(#SINGLE_ARG_TEMPLATE)) - 1) \ .append('<').append(tName, tNameLen); \ - if (typeName.endsWith('>')) \ - typeName.append(' '); \ typeName.append('>'); \ const int newId = qRegisterNormalizedMetaType< SINGLE_ARG_TEMPLATE<T> >( \ typeName, \ @@ -2163,8 +2078,6 @@ struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \ typeName.reserve(int(sizeof(#DOUBLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \ typeName.append(#DOUBLE_ARG_TEMPLATE, int(sizeof(#DOUBLE_ARG_TEMPLATE)) - 1) \ .append('<').append(tName, tNameLen).append(',').append(uName, uNameLen); \ - if (typeName.endsWith('>')) \ - typeName.append(' '); \ typeName.append('>'); \ const int newId = qRegisterNormalizedMetaType< DOUBLE_ARG_TEMPLATE<T, U> >(\ typeName, \ @@ -2298,104 +2211,6 @@ QT_BEGIN_NAMESPACE #undef Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER -inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info, - TypedConstructor creator, - TypedDestructor deleter, - SaveOperator saveOp, - LoadOperator loadOp, - Constructor constructor, - Destructor destructor, - uint size, - uint theTypeFlags, - int typeId, - const QMetaObject *_metaObject) - : m_typedConstructor(creator) - , m_typedDestructor(deleter) - , m_saveOp(saveOp) - , m_loadOp(loadOp) - , m_constructor(constructor) - , m_destructor(destructor) - , m_extension(nullptr) - , m_size(size) - , m_typeFlags(theTypeFlags) - , m_extensionFlags(extensionFlags) - , m_typeId(typeId) - , m_metaObject(_metaObject) -{ - if (Q_UNLIKELY(isExtended(CtorEx) || typeId == QMetaType::Void)) - ctor(info); -} - -inline QMetaType::~QMetaType() -{ - if (Q_UNLIKELY(isExtended(DtorEx))) - dtor(); -} - -inline bool QMetaType::isValid() const -{ - return m_typeId != UnknownType; -} - -inline bool QMetaType::isRegistered() const -{ - return isValid(); -} - -inline int QMetaType::id() const -{ - return m_typeId; -} - -inline void *QMetaType::create(const void *copy) const -{ - // ### TODO Qt6 remove the extension - return createExtended(copy); -} - -inline void QMetaType::destroy(void *data) const -{ - // ### TODO Qt6 remove the extension - destroyExtended(data); -} - -inline void *QMetaType::construct(void *where, const void *copy) const -{ - if (Q_UNLIKELY(isExtended(ConstructEx))) - return constructExtended(where, copy); - return m_constructor(where, copy); -} - -inline void QMetaType::destruct(void *data) const -{ - if (Q_UNLIKELY(isExtended(DestructEx))) - return destructExtended(data); - if (Q_UNLIKELY(!data)) - return; - m_destructor(data); -} - -inline int QMetaType::sizeOf() const -{ - if (Q_UNLIKELY(isExtended(SizeEx))) - return sizeExtended(); - return m_size; -} - -inline QMetaType::TypeFlags QMetaType::flags() const -{ - if (Q_UNLIKELY(isExtended(FlagsEx))) - return flagsExtended(); - return QMetaType::TypeFlags(m_typeFlags); -} - -inline const QMetaObject *QMetaType::metaObject() const -{ - if (Q_UNLIKELY(isExtended(MetaObjectEx))) - return metaObjectExtended(); - return m_metaObject; -} - QT_END_NAMESPACE @@ -2457,6 +2272,532 @@ namespace QtPrivate { }; } +namespace QtPrivate { + +class QMetaTypeInterface +{ +public: + uint revision; // 0 in Qt 6.0. Can increase if new field are added + uint size; + uint alignment; + uint flags; + const QMetaObject *metaObject; + const char *name; + + QBasicAtomicInt typeId; + QtPrivate::RefCount ref; + + // Called when the type is unregistered, to delete this + using DeleteSelf = void (*)(QMetaTypeInterface *); + DeleteSelf deleteSelf; + + using DefaultCtrFn = void (*)(const QMetaTypeInterface *, void *); + DefaultCtrFn defaultCtr; + using CopyCtrFn = void (*)(const QMetaTypeInterface *, void *, const void *); + CopyCtrFn copyCtr; + using MoveCtrFn = void (*)(const QMetaTypeInterface *, void *, void *); + MoveCtrFn moveCtr; + using DtorFn = void (*)(const QMetaTypeInterface *, void *); + DtorFn dtor; + + using LegacyRegisterOp = void (*)(); + LegacyRegisterOp legacyRegisterOp; +}; + +struct QTypeNormalizer +{ + char *output; + int len = 0; + char last = 0; + +private: + static constexpr bool is_ident_char(char s) + { + return ((s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || (s >= '0' && s <= '9') + || s == '_'); + } + static constexpr bool is_space(char s) { return (s == ' ' || s == '\t' || s == '\n'); } + static constexpr bool is_number(char s) { return s >= '0' && s <= '9'; }; + static constexpr bool starts_with_token(const char *b, const char *e, const char *token, + bool msvcKw = false) + { + while (b != e && *token && *b == *token) { + b++; + token++; + } + if (*token) + return false; +#ifdef Q_CC_MSVC + /// On MSVC, keywords like class or struct are not separated with spaces in constexpr + /// context + if (msvcKw) + return true; +#endif + Q_UNUSED(msvcKw); + return b == e || !is_ident_char(*b); + } + static constexpr bool skipToken(const char *&x, const char *e, const char *token, + bool msvcKw = false) + { + if (!starts_with_token(x, e, token, msvcKw)) + return false; + while (*token++) + x++; + while (x != e && is_space(*x)) + x++; + return true; + } + static constexpr const char *skipString(const char *x, const char *e) + { + char delim = *x; + x++; + while (x != e && *x != delim) { + if (*x == '\\') { + x++; + if (x == e) + return e; + } + x++; + } + if (x != e) + x++; + return x; + }; + static constexpr const char *skipTemplate(const char *x, const char *e, bool stopAtComa = false) + { + int scopeDepth = 0; + int templateDepth = 0; + while (x != e) { + switch (*x) { + case '<': + if (!scopeDepth) + templateDepth++; + break; + case ',': + if (stopAtComa && !scopeDepth && !templateDepth) + return x; + break; + case '>': + if (!scopeDepth) + if (--templateDepth < 0) + return x; + break; + case '(': + case '[': + case '{': + scopeDepth++; + break; + case '}': + case ']': + case ')': + scopeDepth--; + break; + case '\'': + if (is_number(x[-1])) + break; + Q_FALLTHROUGH(); + case '\"': + x = skipString(x, e); + continue; + } + x++; + } + return x; + }; + + constexpr void append(char x) + { + last = x; + len++; + if (output) + *output++ = x; + } + + constexpr void appendStr(const char *x) + { + while (*x) + append(*x++); + }; + +public: + constexpr int normalizeType(const char *begin, const char *end, bool adjustConst = true) + { + // Trim spaces + while (begin != end && is_space(*begin)) + begin++; + while (begin != end && is_space(*(end - 1))) + end--; + + // Convert 'char const *' into 'const char *'. Start at index 1, + // not 0, because 'const char *' is already OK. + const char *cst = begin + 1; + if (*begin == '\'' || *begin == '"') + cst = skipString(begin, end); + bool seenStar = false; + bool hasMiddleConst = false; + while (cst < end) { + if (*cst == '\"' || (*cst == '\'' && !is_number(cst[-1]))) { + cst = skipString(cst, end); + if (cst == end) + break; + } + + // We mustn't convert 'char * const *' into 'const char **' + // and we must beware of 'Bar<const Bla>'. + if (*cst == '&' || *cst == '*' || *cst == '[') { + seenStar = *cst != '&' || cst != (end - 1); + break; + } + if (*cst == '<') { + cst = skipTemplate(cst + 1, end); + if (cst == end) + break; + } + cst++; + const char *skipedCst = cst; + if (!is_ident_char(*(cst - 1)) && skipToken(skipedCst, end, "const")) { + const char *testEnd = end; + while (skipedCst < testEnd--) { + if (*testEnd == '*' || *testEnd == '[' + || (*testEnd == '&' && testEnd != (end - 1))) { + seenStar = true; + break; + } + if (*testEnd == '>') + break; + } + if (adjustConst && !seenStar) { + if (*(end - 1) == '&') + end--; + } else { + appendStr("const "); + } + normalizeType(begin, cst, false); + begin = skipedCst; + hasMiddleConst = true; + break; + } + } + if (skipToken(begin, end, "const")) { + if (adjustConst && !seenStar) { + if (*(end - 1) == '&') + end--; + } else { + appendStr("const "); + } + } + if (seenStar && adjustConst) { + const char *e = end; + if (*(end - 1) == '&' && *(end - 2) != '&') + e--; + while (begin != e && is_space(*(e - 1))) + e--; + const char *token = "tsnoc"; // 'const' reverse, to check if it ends with const + while (*token && begin != e && *(--e) == *token++) + ; + if (!*token && begin != e && !is_ident_char(*(e - 1))) { + while (begin != e && is_space(*(e - 1))) + e--; + end = e; + } + } + + // discard 'struct', 'class', and 'enum'; they are optional + // and we don't want them in the normalized signature + skipToken(begin, end, "struct", true) || skipToken(begin, end, "class", true) + || skipToken(begin, end, "enum", true); + +#ifdef QT_NAMESPACE + const char *nsbeg = begin; + if (skipToken(nsbeg, end, QT_STRINGIFY(QT_NAMESPACE)) && nsbeg + 2 < end && nsbeg[0] == ':' + && nsbeg[1] == ':') { + begin = nsbeg + 2; + while (begin != end && is_space(*begin)) + begin++; + } +#endif + + if (skipToken(begin, end, "QList")) { + // Replace QList by QVector + appendStr("QVector"); + } + if (!hasMiddleConst) { + // Normalize the integer types + int numLong = 0; + int numSigned = 0; + int numUnsigned = 0; + int numInt = 0; + int numShort = 0; + int numChar = 0; + while (begin < end) { + if (skipToken(begin, end, "long")) { + numLong++; + continue; + } + if (skipToken(begin, end, "int")) { + numInt++; + continue; + } + if (skipToken(begin, end, "short")) { + numShort++; + continue; + } + if (skipToken(begin, end, "unsigned")) { + numUnsigned++; + continue; + } + if (skipToken(begin, end, "signed")) { + numSigned++; + continue; + } + if (skipToken(begin, end, "char")) { + numChar++; + continue; + } + break; + } + if (numChar || numShort) { + if (numSigned && numChar) + appendStr("signed "); + if (numUnsigned) + appendStr("unsigned "); + if (numChar) + appendStr("char"); + else + appendStr("short"); + } else if (numLong) { + if (numLong == 1) { + if (numUnsigned) + append('u'); + appendStr("long"); + } else { + if (numUnsigned) + appendStr("unsigned "); + appendStr("long long"); + } + } else if (numUnsigned || numSigned || numInt) { + if (numUnsigned) + append('u'); + appendStr("int"); + } + } + + bool spaceSkiped = true; + while (begin != end) { + char c = *begin++; + if (is_space(c)) { + spaceSkiped = true; + } else if ((c == '\'' && !is_number(last)) || c == '\"') { + begin--; + auto x = skipString(begin, end); + while (begin < x) + append(*begin++); + } else { + if (spaceSkiped && is_ident_char(last) && is_ident_char(c)) + append(' '); + append(c); + spaceSkiped = false; + if (c == '<') { + do { + // template recursion + const char *tpl = skipTemplate(begin, end, true); + normalizeType(begin, tpl, false); + if (tpl == end) + return len; + append(*tpl); + begin = tpl; + } while (*begin++ == ','); + } + } + } + return len; + } +}; + +// Normalize the type between begin and end, and store the data in the output. Returns the length. +// The idea is to first run this function with nullptr as output to allocate the output with the +// size +constexpr int qNormalizeType(const char *begin, const char *end, char *output) +{ + return QTypeNormalizer { output }.normalizeType(begin, end); +} + +template<typename T> +constexpr auto typenameHelper() +{ + constexpr auto prefix = sizeof( +#ifdef QT_NAMESPACE + QT_STRINGIFY(QT_NAMESPACE) "::" +#endif +#ifdef Q_CC_MSVC + "auto __cdecl QtPrivate::typenameHelper<" +#elif defined(Q_CC_CLANG) + "auto QtPrivate::typenameHelper() [T = " +#else + "constexpr auto QtPrivate::typenameHelper() [with T = " +#endif + ) - 1; +#ifdef Q_CC_MSVC + constexpr int suffix = sizeof(">(void)"); +#else + constexpr int suffix = sizeof("]"); +#endif + +#if !(defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)) + constexpr auto func = Q_FUNC_INFO; + constexpr const char *begin = func + prefix; + constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix; + constexpr int len = qNormalizeType(begin, end, nullptr); +#else // GCC < 8.1 did not have Q_FUNC_INFO as constexpr, and GCC 9 has a precompiled header bug + auto func = Q_FUNC_INFO; + const char *begin = func + prefix; + const char *end = func + sizeof(Q_FUNC_INFO) - suffix; + // This is an upper bound of the size since the normalized signature should always be smaller + // (Unless there is a QList -> QVector change, but that should not happen) + constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix; +#endif + std::array<char, len + 1> result {}; + qNormalizeType(begin, end, result.data()); + return result; +} + +template<typename T, typename = void> +struct BuiltinMetaType : std::integral_constant<int, 0> +{ +}; +template<typename T> +struct BuiltinMetaType<T, std::enable_if_t<QMetaTypeId2<T>::IsBuiltIn>> + : std::integral_constant<int, QMetaTypeId2<T>::MetaType> +{ +}; + +template<typename T> +class QMetaTypeForType +{ + static const decltype(typenameHelper<T>()) name; + +public: + static QMetaTypeInterface metaType; +}; + +#ifdef Q_CC_CLANG +// Workaround for https://bugs.llvm.org/show_bug.cgi?id=44554 : Every lambda used for initializing +// static members need a different signature for explicit instentiation +#define QT_METATYPE_CONSTEXPRLAMDA(...) [](std::integral_constant<int, __COUNTER__> = {}) constexpr __VA_ARGS__ () +#elif defined(Q_CC_MSVC) +// Workaround a bug with 'if constexpr' not working in lambda that are not generic in MSVC +#define QT_METATYPE_CONSTEXPRLAMDA(...) [](auto) constexpr __VA_ARGS__ (0) +#else +#define QT_METATYPE_CONSTEXPRLAMDA(...) []() constexpr __VA_ARGS__ () +#endif + +template<typename T> +QMetaTypeInterface QMetaTypeForType<T>::metaType = { + /*.revision=*/ 0, + /*.size=*/ sizeof(T), + /*.alignment=*/ alignof(T), + /*.flags=*/ QMetaTypeTypeFlags<T>::Flags, + /*.metaObject=*/ MetaObjectForType<T>::value(), + /*.name=*/ QT_METATYPE_CONSTEXPRLAMDA( -> const char * { + if constexpr (bool(QMetaTypeId2<T>::IsBuiltIn)) { + return QMetaTypeId2<T>::name; + } else { + return name.data(); + } + }), + /*.typeId=*/ BuiltinMetaType<T>::value, + /*.ref=*/ Q_REFCOUNT_INITIALIZE_STATIC, + /*.deleteSelf=*/ nullptr, + /*.defaultCtr=*/ QT_METATYPE_CONSTEXPRLAMDA( -> QMetaTypeInterface::DefaultCtrFn { + if constexpr (std::is_default_constructible_v<T>) { + return [](const QMetaTypeInterface *, void *addr) { new (addr) T(); }; + } else { + return nullptr; + } + }), + /*.copyCtr=*/ QT_METATYPE_CONSTEXPRLAMDA( -> QMetaTypeInterface::CopyCtrFn { + if constexpr (std::is_copy_constructible_v<T>) { + return [](const QMetaTypeInterface *, void *addr, const void *other) { + new (addr) T(*reinterpret_cast<const T *>(other)); + }; + } else { + return nullptr; + } + }), + /*.moveCtr=*/ QT_METATYPE_CONSTEXPRLAMDA( -> QMetaTypeInterface::MoveCtrFn { + if constexpr (std::is_move_constructible_v<T>) { + return [](const QMetaTypeInterface *, void *addr, void *other) { + new (addr) T(std::move(*reinterpret_cast<T *>(other))); + }; + } else { + return nullptr; + } + }), + /*.dtor=*/ QT_METATYPE_CONSTEXPRLAMDA( -> QMetaTypeInterface::DtorFn { + if constexpr (std::is_destructible_v<T>) + return [](const QMetaTypeInterface *, void *addr) { reinterpret_cast<T *>(addr)->~T(); }; + else + return nullptr; + }), + /*.legacyRegisterOp=*/ QT_METATYPE_CONSTEXPRLAMDA( -> QMetaTypeInterface::LegacyRegisterOp { + if constexpr (QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn) { + return []() { QMetaTypeId2<T>::qt_metatype_id(); }; + } else { + return nullptr; + } + }) +}; +#undef QT_METATYPE_CONSTEXPRLAMDA + +template<typename T> +constexpr const decltype(typenameHelper<T>()) QMetaTypeForType<T>::name = typenameHelper<T>(); + +template<> +class QMetaTypeForType<void> +{ +}; + +#ifndef QT_BOOTSTRAPPED +#define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \ + extern template class Q_CORE_EXPORT QMetaTypeForType<Name>; +QT_WARNING_PUSH +QT_WARNING_DISABLE_MSVC(4910) // '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wattributes") // false positive because of QMetaTypeForType<void> +QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) +QT_WARNING_POP +QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) +QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) +QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) +QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) +QT_WARNING_POP +#undef QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER +#endif + +template<typename T> +constexpr QMetaTypeInterface *qMetaTypeInterfaceForType() +{ + using Ty = std::remove_cv_t<std::remove_reference_t<T>>; + if constexpr (std::is_same_v<Ty, void>) { + return nullptr; + } else { + return &QMetaTypeForType<Ty>::metaType; + } +} + +} // namespace QtPrivate + +template<typename T> +QMetaType QMetaType::fromType() +{ + return QMetaType(QtPrivate::qMetaTypeInterfaceForType<T>()); +} + +template<typename... T> +QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = { + QtPrivate::qMetaTypeInterfaceForType<T>()... +}; + QT_END_NAMESPACE #endif // QMETATYPE_H |