diff options
Diffstat (limited to 'src/corelib/kernel/qmetatype.cpp')
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 628 |
1 files changed, 440 insertions, 188 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 780ae10396..387c0f49ab 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -20,14 +20,14 @@ #include "qeasingcurve.h" #endif #include "quuid.h" -#include "qvariant.h" -#include "qdatastream.h" #if QT_CONFIG(regularexpression) # include "qregularexpression.h" #endif #ifndef QT_BOOTSTRAPPED +# include "qdatastream.h" + # include "qbitarray.h" # include "qurl.h" # include "qvariant.h" @@ -42,6 +42,7 @@ # include "qmetaobject.h" # include "qsequentialiterable.h" # include "qassociativeiterable.h" +# include "qobject.h" #endif #if QT_CONFIG(itemmodel) @@ -55,7 +56,6 @@ # include "qline.h" #endif -#include <bitset> #include <new> #include <cstring> @@ -65,10 +65,38 @@ QT_BEGIN_NAMESPACE QT_IMPL_METATYPE_EXTERN_TAGGED(QtMetaTypePrivate::QPairVariantInterfaceImpl, QPairVariantInterfaceImpl) +using QtMetaTypePrivate::isInterfaceFor; + namespace { +struct QMetaTypeDeleter +{ + const QtPrivate::QMetaTypeInterface *iface; + void operator()(void *data) + { + if (iface->alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { + operator delete(data, std::align_val_t(iface->alignment)); + } else { + operator delete(data); + } + } +}; struct QMetaTypeCustomRegistry { + +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) + QMetaTypeCustomRegistry() + { + /* qfloat16 was neither a builtin, nor unconditionally registered + in QtCore in Qt <= 6.2. + Inserting it as an alias ensures that a QMetaType::id call + will get the correct built-in type-id (the interface pointers + might still not match, but we already deal with that case. + */ + aliases.insert("qfloat16", QtPrivate::qMetaTypeInterfaceForType<qfloat16>()); + } +#endif + QReadWriteLock lock; QList<const QtPrivate::QMetaTypeInterface *> registry; QHash<QByteArray, const QtPrivate::QMetaTypeInterface *> aliases; @@ -90,8 +118,9 @@ struct QMetaTypeCustomRegistry #endif (ti->name); if (auto ti2 = aliases.value(name)) { - ti->typeId.storeRelaxed(ti2->typeId.loadRelaxed()); - return ti2->typeId; + const auto id = ti2->typeId.loadRelaxed(); + ti->typeId.storeRelaxed(id); + return id; } aliases[name] = ti; int size = registry.size(); @@ -121,13 +150,7 @@ struct QMetaTypeCustomRegistry auto &ti = registry[idx]; // We must unregister all names. - auto it = aliases.begin(); - while (it != aliases.end()) { - if (it.value() == ti) - it = aliases.erase(it); - else - ++it; - } + aliases.removeIf([ti] (const auto &kv) { return kv.value() == ti; }); ti = nullptr; @@ -150,9 +173,9 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInterface *type_d) { const char *name = nullptr; - QMetaTypeCustomRegistry *r = customTypeRegistry; - if (!r) + if (!customTypeRegistry.exists()) return name; + QMetaTypeCustomRegistry *r = &*customTypeRegistry; QByteArrayView officialName(type_d->name); QReadLocker l(&r->lock); @@ -239,7 +262,7 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte \li Pointers to classes derived from QObject \li QList<T>, QQueue<T>, QStack<T> or QSet<T> where T is a registered meta type - \li QHash<T1, T2>, QMap<T1, T2> or QPair<T1, T2> where T1 and T2 are + \li QHash<T1, T2>, QMap<T1, T2> or std::pair<T1, T2> where T1 and T2 are registered meta types \li QPointer<T>, QSharedPointer<T>, QWeakPointer<T>, where T is a class that derives from QObject \li Enumerations registered with Q_ENUM or Q_FLAG @@ -337,8 +360,12 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte \value SChar \c{signed char} \value UChar \c{unsigned char} \value Float \c float + \value Float16 qfloat16 + \omitvalue Float128 + \omitvalue BFloat16 + \omitvalue Int128 + \omitvalue UInt128 \value QObjectStar QObject * - \value QVariant QVariant \value QCursor QCursor \value QDate QDate @@ -356,6 +383,7 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte \value QStringList QStringList \value QVariantMap QVariantMap \value QVariantHash QVariantHash + \value QVariantPair QVariantPair \value QIcon QIcon \value QPen QPen \value QLineF QLineF @@ -396,13 +424,13 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte \value QPersistentModelIndex QPersistentModelIndex (introduced in Qt 5.5) \value QUuid QUuid \value QByteArrayList QByteArrayList + \value QVariant QVariant \value User Base value for user types \value UnknownType This is an invalid type id. It is returned from QMetaType for types that are not registered - \omitvalue LastCoreType - \omitvalue LastGuiType - Additional types can be registered using Q_DECLARE_METATYPE(). + Additional types can be registered using qRegisterMetaType() or by calling + registerType(). \sa type(), typeName() */ @@ -412,21 +440,31 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte The enum describes attributes of a type supported by QMetaType. - \value NeedsConstruction This type has non-trivial constructors. If the flag is not set instances can be safely initialized with memset to 0. - \value NeedsDestruction This type has a non-trivial destructor. If the flag is not set calls to the destructor are not necessary before discarding objects. + \value NeedsConstruction This type has a default constructor. If the flag is not set, instances can be safely initialized with memset to 0. + \value NeedsCopyConstruction (since 6.5) This type has a non-trivial copy constructor. If the flag is not set, instances can be copied with memcpy. + \value NeedsMoveConstruction (since 6.5) This type has a non-trivial move constructor. If the flag is not set, instances can be moved with memcpy. + \value NeedsDestruction This type has a non-trivial destructor. If the flag is not set, calls to the destructor are not necessary before discarding objects. \value RelocatableType An instance of a type having this attribute can be safely moved to a different memory location using memcpy. \omitvalue MovableType \omitvalue SharedPointerToQObject \value IsEnumeration This type is an enumeration. \value IsUnsignedEnumeration If the type is an Enumeration, its underlying type is unsigned. - \value PointerToQObject This type is a pointer to a derived of QObject. + \value PointerToQObject This type is a pointer to a class derived from QObject. \value IsPointer This type is a pointer to another type. \omitvalue WeakPointerToQObject \omitvalue TrackingPointerToQObject - \omitvalue IsGadget \omit This type is a Q_GADGET and it's corresponding QMetaObject can be accessed with QMetaType::metaObject Since 5.5. \endomit + \omitvalue IsGadget \omit (since Qt 5.5) This type is a Q_GADGET and its corresponding QMetaObject can be accessed with QMetaType::metaObject. \endomit \omitvalue PointerToGadget \omitvalue IsQmlList - \value IsConst Indicates that values of this types are immutable; for instance because they are pointers to const objects. + \value IsConst Indicates that values of this type are immutable; for instance, because they are pointers to const objects. + + \note Before Qt 6.5, both the NeedsConstruction and NeedsDestruction flags + were incorrectly set if the either copy construtor or destructor were + non-trivial (that is, if the type was not trivial). + + Note that the Needs flags may be set but the meta type may not have a + publicly-accessible constructor of the relevant type or a + publicly-accessible destructor. */ /*! @@ -440,17 +478,19 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte The class is used as a helper to marshall types in QVariant and in queued signals and slots connections. It associates a type name to a type so that it can be created and destructed - dynamically at run-time. Declare new types with Q_DECLARE_METATYPE() - to make them available to QVariant and other template-based functions. - Call qRegisterMetaType() to make types available to non-template based - functions, such as the queued signal and slot connections. + dynamically at run-time. - Any class or struct that has a public default - constructor, a public copy constructor, and a public destructor - can be registered. + Type names can be registered with QMetaType by using either + qRegisterMetaType() or registerType(). Registration is not required for + most operations; it's only required for operations that attempt to resolve + a type name in string form back to a QMetaType object or the type's ID. + Those include some old-style signal-slot connections using + QObject::connect(), reading user-types from \l QDataStream to \l QVariant, + or binding to other languages and IPC mechanisms, like QML, D-Bus, + JavaScript, etc. - The following code allocates and destructs an instance of - \c{MyClass}: + The following code allocates and destructs an instance of \c{MyClass} by + its name, which requires that \c{MyClass} have been previously registered: \snippet code/src_corelib_kernel_qmetatype.cpp 3 @@ -468,6 +508,8 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte Returns \c true if this QMetaType object contains valid information about a type, false otherwise. + + \sa isRegistered() */ bool QMetaType::isValid() const { @@ -478,31 +520,43 @@ bool QMetaType::isValid() const \fn bool QMetaType::isRegistered() const \since 5.0 - Returns \c true if this QMetaType object contains valid - information about a type, false otherwise. + Returns \c true if this QMetaType object has been registered with the Qt + global metatype registry. Registration allows the type to be found by its + name (using QMetaType::fromName()) or by its ID (using the constructor). + + \sa qRegisterMetaType(), isValid() */ bool QMetaType::isRegistered() const { - return d_ptr; + return d_ptr && d_ptr->typeId.loadRelaxed(); } /*! \fn int QMetaType::id() const \since 5.13 - Returns id type hold by this QMetatype instance. + Returns id type held by this QMetatype instance. */ /*! + \fn void QMetaType::registerType() const + \since 6.5 + + Registers this QMetaType with the type registry so it can be found by name, + using QMetaType::fromName(). + + \sa qRegisterMetaType() + */ +/*! \internal - The slowpath of id(). Precondition: d_ptr != nullptr -*/ -int QMetaType::idHelper() const + Out-of-line path for registerType() and slow path id(). + */ +int QMetaType::registerHelper(const QtPrivate::QMetaTypeInterface *iface) { - Q_ASSERT(d_ptr); + Q_ASSERT(iface); auto reg = customTypeRegistry(); if (reg) { - return reg->registerCustomType(d_ptr); + return reg->registerCustomType(iface); } return 0; } @@ -540,28 +594,34 @@ int QMetaType::idHelper() const \fn constexpr TypeFlags QMetaType::flags() const \since 5.0 - Returns flags of the type for which this QMetaType instance was constructed. + Returns flags of the type for which this QMetaType instance was + constructed. To inspect specific type traits, prefer using one of the "is-" + functions rather than the flags directly. - \sa QMetaType::TypeFlags, QMetaType::flags() + \sa QMetaType::TypeFlags, QMetaType::flags(), isDefaultConstructible(), + isCopyConstructible(), isMoveConstructible(), isDestructible(), + isEqualityComparable(), isOrdered() */ /*! \fn constexpr const QMetaObject *QMetaType::metaObject() const \since 5.5 - return a QMetaObject relative to this type. + Returns a QMetaObject relative to this type. If the type is a pointer type to a subclass of QObject, flags() contains - QMetaType::PointerToQObject and this function returns the corresponding QMetaObject. This can - be used to in combinaison with QMetaObject::construct to create QObject of this type. + QMetaType::PointerToQObject and this function returns the corresponding QMetaObject. + This can be used in combination with QMetaObject::newInstance() to create QObjects of this type. - If the type is a Q_GADGET, flags() contains QMetaType::IsGadget, and this function returns its - QMetaObject. This can be used to retrieve QMetaMethod and QMetaProperty and use them on a - pointer of this type. (given by QVariant::data for example) + If the type is a Q_GADGET, flags() contains QMetaType::IsGadget. + If the type is a pointer to a Q_GADGET, flags() contains QMetaType::PointerToGadget. + In both cases, this function returns its QMetaObject. + This can be used to retrieve QMetaMethod and QMetaProperty and use them on a + pointer of this type for example, as given by QVariant::data(). - If the type is an enumeration, flags() contains QMetaType::IsEnumeration, and this function - returns the QMetaObject of the enclosing object if the enum was registered as a Q_ENUM or - \nullptr otherwise + If the type is an enumeration, flags() contains QMetaType::IsEnumeration. + In this case, this function returns the QMetaObject of the enclosing + object if the enum was registered as a Q_ENUM or \nullptr otherwise. \sa QMetaType::flags() */ @@ -578,16 +638,17 @@ int QMetaType::idHelper() const */ void *QMetaType::create(const void *copy) const { - if (d_ptr && (copy ? !!d_ptr->copyCtr : !!d_ptr->defaultCtr)) { - void *where = -#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__ - d_ptr->alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__ ? - operator new(d_ptr->size, std::align_val_t(d_ptr->alignment)) : -#endif - operator new(d_ptr->size); - return construct(where, copy); - } - return nullptr; + if (copy ? !isCopyConstructible() : !isDefaultConstructible()) + return nullptr; + + std::unique_ptr<void, QMetaTypeDeleter> where(nullptr, {d_ptr}); + if (d_ptr->alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + where.reset(operator new(d_ptr->size, std::align_val_t(d_ptr->alignment))); + else + where.reset(operator new(d_ptr->size)); + + QtMetaTypePrivate::construct(d_ptr, where.get(), copy); + return where.release(); } /*! @@ -601,14 +662,9 @@ void *QMetaType::create(const void *copy) const */ void QMetaType::destroy(void *data) const { - if (d_ptr) { - if (d_ptr->dtor) - d_ptr->dtor(d_ptr, data); - if (d_ptr->alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { - operator delete(data, std::align_val_t(d_ptr->alignment)); - } else { - operator delete(data); - } + if (data && isDestructible()) { + QtMetaTypePrivate::destruct(d_ptr, data); + QMetaTypeDeleter{d_ptr}(data); } } @@ -642,16 +698,11 @@ void *QMetaType::construct(void *where, const void *copy) const { if (!where) return nullptr; - if (d_ptr) { - if (copy && d_ptr->copyCtr) { - d_ptr->copyCtr(d_ptr, where, copy); - return where; - } else if (!copy && d_ptr->defaultCtr) { - d_ptr->defaultCtr(d_ptr, where); - return where; - } - } - return nullptr; + if (copy ? !isCopyConstructible() : !isDefaultConstructible()) + return nullptr; + + QtMetaTypePrivate::construct(d_ptr, where, copy); + return where; } /*! @@ -667,12 +718,8 @@ void *QMetaType::construct(void *where, const void *copy) const */ void QMetaType::destruct(void *data) const { - if (!data) - return; - if (d_ptr && d_ptr->dtor) { - d_ptr->dtor(d_ptr, data); - return; - } + if (data && isDestructible()) + QtMetaTypePrivate::destruct(d_ptr, data); } static QPartialOrdering threeWayCompare(const void *ptr1, const void *ptr2) @@ -764,6 +811,68 @@ bool QMetaType::equals(const void *lhs, const void *rhs) const } /*! + \fn bool QMetaType::isDefaultConstructible() const noexcept + \since 6.5 + + Returns true if this type can be default-constructed. If it can be, then + construct() and create() can be used with a \c{copy} parameter that is + null. + + \sa flags(), isCopyConstructible(), isMoveConstructible(), isDestructible() + */ + +/*! + \fn bool QMetaType::isCopyConstructible() const noexcept + \since 6.5 + + Returns true if this type can be copy-constructed. If it can be, then + construct() and create() can be used with a \c{copy} parameter that is + not null. + + \sa flags(), isDefaultConstructible(), isMoveConstructible(), isDestructible() + */ + +/*! + \fn bool QMetaType::isMoveConstructible() const noexcept + \since 6.5 + + Returns true if this type can be move-constructed. QMetaType currently does + not have an API to make use of this trait. + + \sa flags(), isDefaultConstructible(), isCopyConstructible(), isDestructible() + */ + +/*! + \fn bool QMetaType::isDestructible() const noexcept + \since 6.5 + + Returns true if this type can be destroyed. If it can be, then destroy() + and destruct() can be called. + + \sa flags(), isDefaultConstructible(), isCopyConstructible(), isMoveConstructible() + */ + +bool QMetaType::isDefaultConstructible(const QtPrivate::QMetaTypeInterface *iface) noexcept +{ + return !isInterfaceFor<void>(iface) && QtMetaTypePrivate::isDefaultConstructible(iface); +} + +bool QMetaType::isCopyConstructible(const QtPrivate::QMetaTypeInterface *iface) noexcept +{ + return !isInterfaceFor<void>(iface) && QtMetaTypePrivate::isCopyConstructible(iface); +} + +bool QMetaType::isMoveConstructible(const QtPrivate::QMetaTypeInterface *iface) noexcept +{ + return !isInterfaceFor<void>(iface) && QtMetaTypePrivate::isMoveConstructible(iface); +} + +bool QMetaType::isDestructible(const QtPrivate::QMetaTypeInterface *iface) noexcept +{ + return !isInterfaceFor<void>(iface) && QtMetaTypePrivate::isDestructible(iface); +} + +/*! Returns \c true if a less than or equality operator for the type described by this metatype was visible to the metatype declaration, otherwise \c false. @@ -791,13 +900,22 @@ bool QMetaType::isOrdered() const */ void QMetaType::unregisterMetaType(QMetaType type) { - if (type.d_ptr && type.d_ptr->typeId.loadRelaxed() >= QMetaType::User) { - // this is a custom meta type (not read-only) - auto d = const_cast<QtPrivate::QMetaTypeInterface *>(type.d_ptr); - if (auto reg = customTypeRegistry()) - reg->unregisterDynamicType(d->typeId.loadRelaxed()); - d->typeId.storeRelease(0); + const QtPrivate::QMetaTypeInterface *d_ptr = type.d_ptr; + if (!d_ptr) + return; + + const int typeId = d_ptr->typeId.loadRelaxed(); + if (typeId < QMetaType::User) + return; + + // this is a custom meta type (not read-only) + + if (auto reg = customTypeRegistry()) { + Q_ASSERT(reg->getCustomType(typeId) == d_ptr); + reg->unregisterDynamicType(typeId); } + + const_cast<QtPrivate::QMetaTypeInterface *>(d_ptr)->typeId.storeRelease(0); } /*! @@ -823,6 +941,12 @@ void QMetaType::unregisterMetaType(QMetaType type) than the QMetaType \a b, otherwise returns \c false. */ +/*! \internal */ +bool QMetaTypeModuleHelper::convert(const void *, int, void *, int) const +{ + return false; +} + #define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \ { #RealName, sizeof(#RealName) - 1, MetaTypeId }, @@ -838,7 +962,8 @@ static const struct { const char * typeName; int typeNameLength; int type; } typ {nullptr, 0, QMetaType::UnknownType} }; -static const struct : QMetaTypeModuleHelper +// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class +static constexpr struct : QMetaTypeModuleHelper { template<typename T, typename LiteralWrapper = std::conditional_t<std::is_same_v<T, QString>, QLatin1StringView, const char *>> @@ -885,6 +1010,8 @@ static const struct : QMetaTypeModuleHelper using Double = double; using Bool = bool; using Nullptr = std::nullptr_t; + using Char16 = char16_t; + using Char32 = char32_t; #define QMETATYPE_CONVERTER_ASSIGN_DOUBLE(To, From) \ QMETATYPE_CONVERTER(To, From, result = double(source); return true;) @@ -1039,6 +1166,9 @@ static const struct : QMetaTypeModuleHelper QMETATYPE_CONVERTER_ASSIGN_QCHAR(ULong); QMETATYPE_CONVERTER_ASSIGN_QCHAR(UInt); QMETATYPE_CONVERTER_ASSIGN_QCHAR(ULongLong); + QMETATYPE_CONVERTER_ASSIGN_QCHAR(Char16); + + QMETATYPE_CONVERTER(Char16, QChar, result = source.unicode(); return true;) // conversions to QString QMETATYPE_CONVERTER_ASSIGN(QString, QChar); @@ -1076,6 +1206,14 @@ static const struct : QMetaTypeModuleHelper result = QString::fromLatin1(&s, 1); return true; ); + QMETATYPE_CONVERTER(QString, Char16, + result = QChar(source); + return true; + ); + QMETATYPE_CONVERTER(QString, Char32, + result = QChar::fromUcs4(source).operator QStringView().toString(); + return true; + ); #if QT_CONFIG(datestring) QMETATYPE_CONVERTER(QString, QDate, result = source.toString(Qt::ISODate); return true;); QMETATYPE_CONVERTER(QString, QTime, result = source.toString(Qt::ISODateWithMs); return true;); @@ -1083,7 +1221,7 @@ static const struct : QMetaTypeModuleHelper #endif QMETATYPE_CONVERTER(QString, QByteArray, result = QString::fromUtf8(source); return true;); QMETATYPE_CONVERTER(QString, QStringList, - return (source.count() == 1) ? (result = source.at(0), true) : false; + return (source.size() == 1) ? (result = source.at(0), true) : false; ); #ifndef QT_BOOTSTRAPPED QMETATYPE_CONVERTER(QString, QUrl, result = source.toString(); return true;); @@ -1138,34 +1276,36 @@ static const struct : QMetaTypeModuleHelper QMETATYPE_CONVERTER_ASSIGN(QRectF, QRect); QMETATYPE_CONVERTER(QPoint, QPointF, result = source.toPoint(); return true;); QMETATYPE_CONVERTER_ASSIGN(QPointF, QPoint); - #endif +#endif + + QMETATYPE_CONVERTER(QStringList, QString, result = QStringList() << source; return true;); +#ifndef QT_NO_VARIANT QMETATYPE_CONVERTER(QByteArrayList, QVariantList, result.reserve(source.size()); - for (auto v: source) + for (const auto &v: source) result.append(v.toByteArray()); return true; ); QMETATYPE_CONVERTER(QVariantList, QByteArrayList, result.reserve(source.size()); - for (auto v: source) + for (const auto &v: source) result.append(QVariant(v)); return true; ); QMETATYPE_CONVERTER(QStringList, QVariantList, result.reserve(source.size()); - for (auto v: source) + for (const auto &v: source) result.append(v.toString()); return true; ); QMETATYPE_CONVERTER(QVariantList, QStringList, result.reserve(source.size()); - for (auto v: source) + for (const auto &v: source) result.append(QVariant(v)); return true; ); - QMETATYPE_CONVERTER(QStringList, QString, result = QStringList() << source; return true;); QMETATYPE_CONVERTER(QVariantHash, QVariantMap, for (auto it = source.begin(); it != source.end(); ++it) @@ -1177,7 +1317,7 @@ static const struct : QMetaTypeModuleHelper result.insert(it.key(), it.value()); return true; ); - +#endif // !QT_NO_VARIANT #ifndef QT_BOOTSTRAPPED QMETATYPE_CONVERTER_ASSIGN(QCborValue, QString); QMETATYPE_CONVERTER(QString, QCborValue, @@ -1577,17 +1717,17 @@ private: QHash<Key, T> map; }; -typedef QMetaTypeFunctionRegistry<QMetaType::ConverterFunction,QPair<int,int> > -QMetaTypeConverterRegistry; +using QMetaTypeConverterRegistry + = QMetaTypeFunctionRegistry<QMetaType::ConverterFunction, std::pair<int,int>>; Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry) using QMetaTypeMutableViewRegistry - = QMetaTypeFunctionRegistry<QMetaType::MutableViewFunction, QPair<int,int>>; + = QMetaTypeFunctionRegistry<QMetaType::MutableViewFunction, std::pair<int,int>>; Q_GLOBAL_STATIC(QMetaTypeMutableViewRegistry, customTypesMutableViewRegistry) /*! - \fn bool QMetaType::registerConverter() + \fn template<typename From, typename To> bool QMetaType::registerConverter() \since 5.2 Registers the possibility of an implicit conversion from type From to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false. @@ -1596,7 +1736,7 @@ Q_GLOBAL_STATIC(QMetaTypeMutableViewRegistry, customTypesMutableViewRegistry) */ /*! - \fn template<typename From, typename To> static bool registerConverter(To(From::*function)() const) + \fn template<typename From, typename To> static bool QMetaType::registerConverter(To(From::*function)() const) \since 5.2 \overload Registers a method \a function like To From::function() const as converter from type From @@ -1606,26 +1746,27 @@ Q_GLOBAL_STATIC(QMetaTypeMutableViewRegistry, customTypesMutableViewRegistry) */ /*! - \fn template<typename From, typename To> static bool registerConverter(To(From::*function)(bool*) const) + \fn template<typename From, typename To> static bool QMetaType::registerConverter(To(From::*function)(bool*) const) \since 5.2 \overload Registers a method \a function like To From::function(bool *ok) const as converter from type From to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false. - The \a ok pointer can be used by the function to indicate whether the conversion succeeded. + The \c ok pointer can be used by the function to indicate whether the conversion succeeded. \snippet qmetatype/registerConverters.cpp memberOk */ /*! - \fn template<typename From, typename To, typename UnaryFunction> static bool registerConverter(UnaryFunction function) + \fn template<typename From, typename To, typename UnaryFunction> static bool QMetaType::registerConverter(UnaryFunction function) \since 5.2 \overload Registers a unary function object \a function as converter from type From to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false. - \a function must take an instance of type \a From and return an instance of \a To. It can be a function - pointer, a lambda or a functor object. + \a function must take an instance of type \c From and return an instance of \c To. It can be a function + pointer, a lambda or a functor object. Since Qt 6.5, the \a function can also return an instance of + \c std::optional<To> to be able to indicate failed conversions. \snippet qmetatype/registerConverters.cpp unaryfunc */ @@ -1638,7 +1779,7 @@ Q_GLOBAL_STATIC(QMetaTypeMutableViewRegistry, customTypesMutableViewRegistry) */ bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType from, QMetaType to) { - if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from.id(), to.id()), f)) { + if (!customTypesConversionRegistry()->insertIfNotContains({from.id(), to.id()}, f)) { qWarning("Type conversion already registered from type %s to type %s", from.name(), to.name()); return false; @@ -1647,7 +1788,7 @@ bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType } /*! - \fn template<typename From, typename To> static bool registerMutableView(To(From::*function)()) + \fn template<typename From, typename To> static bool QMetaType::registerMutableView(To(From::*function)()) \since 6.0 \overload Registers a method \a function like \c {To From::function()} as mutable view of type \c {To} on @@ -1656,7 +1797,7 @@ bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType */ /*! - \fn template<typename From, typename To, typename UnaryFunction> static bool registerMutableView(UnaryFunction function) + \fn template<typename From, typename To, typename UnaryFunction> static bool QMetaType::registerMutableView(UnaryFunction function) \since 6.0 \overload Registers a unary function object \a function as mutable view of type To on type From @@ -1671,7 +1812,7 @@ bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType */ bool QMetaType::registerMutableViewFunction(const MutableViewFunction &f, QMetaType from, QMetaType to) { - if (!customTypesMutableViewRegistry()->insertIfNotContains(qMakePair(from.id(), to.id()), f)) { + if (!customTypesMutableViewRegistry()->insertIfNotContains({from.id(), to.id()}, f)) { qWarning("Mutable view on type already registered from type %s to type %s", from.name(), to.name()); return false; @@ -1704,6 +1845,17 @@ void QMetaType::unregisterConverterFunction(QMetaType from, QMetaType to) #ifndef QT_NO_DEBUG_STREAM /*! + \fn QDebug QMetaType::operator<<(QDebug d, QMetaType m) + \since 6.5 + Writes the QMetaType \a m to the stream \a d, and returns the stream. +*/ +QDebug operator<<(QDebug d, QMetaType m) +{ + const QDebugStateSaver saver(d); + return d.nospace() << "QMetaType(" << m.name() << ")"; +} + +/*! Streams the object at \a rhs to the debug stream \a dbg. Returns \c true on success, otherwise false. \since 5.2 @@ -1728,7 +1880,7 @@ bool QMetaType::debugStream(QDebug& dbg, const void *rhs) */ /*! - \fn bool QMetaType::hasRegisteredDebugStreamOperator() + \fn template<typename T> bool QMetaType::hasRegisteredDebugStreamOperator() \deprecated \since 5.2 @@ -1765,10 +1917,16 @@ static QMetaEnum metaEnumFromType(QMetaType t) { if (t.flags() & QMetaType::IsEnumeration) { if (const QMetaObject *metaObject = t.metaObject()) { - const QByteArray enumName = t.name(); - const char *lastColon = std::strrchr(enumName, ':'); - return metaObject->enumerator(metaObject->indexOfEnumerator( - lastColon ? lastColon + 1 : enumName.constData())); + QByteArrayView qflagsNamePrefix = "QFlags<"; + QByteArray enumName = t.name(); + if (enumName.endsWith('>') && enumName.startsWith(qflagsNamePrefix)) { + // extract the template argument + enumName.chop(1); + enumName = enumName.sliced(qflagsNamePrefix.size()); + } + if (qsizetype lastColon = enumName.lastIndexOf(':'); lastColon != -1) + enumName = enumName.sliced(lastColon + 1); + return metaObject->enumerator(metaObject->indexOfEnumerator(enumName)); } } return QMetaEnum(); @@ -1827,18 +1985,27 @@ static bool convertFromEnum(QMetaType fromType, const void *from, QMetaType toTy if (toType.id() != QMetaType::QString && toType.id() != QMetaType::QByteArray) return QMetaType::convert(QMetaType::fromType<qlonglong>(), &ll, toType, to); } - Q_ASSERT(toType.id() == QMetaType::QString || toType.id() == QMetaType::QByteArray); #ifndef QT_NO_QOBJECT QMetaEnum en = metaEnumFromType(fromType); if (en.isValid()) { - const char *key = en.valueToKey(ll); - if (toType.id() == QMetaType::QString) - *static_cast<QString *>(to) = QString::fromUtf8(key); - else - *static_cast<QByteArray *>(to) = key; + if (en.isFlag()) { + const QByteArray keys = en.valueToKeys(static_cast<int>(ll)); + if (toType.id() == QMetaType::QString) + *static_cast<QString *>(to) = QString::fromUtf8(keys); + else + *static_cast<QByteArray *>(to) = keys; + } else { + const char *key = en.valueToKey(static_cast<int>(ll)); + if (toType.id() == QMetaType::QString) + *static_cast<QString *>(to) = QString::fromUtf8(key); + else + *static_cast<QByteArray *>(to) = key; + } return true; } #endif + if (toType.id() == QMetaType::QString || toType.id() == QMetaType::QByteArray) + return QMetaType::convert(QMetaType::fromType<qlonglong>(), &ll, toType, to); return false; } @@ -1850,12 +2017,12 @@ static bool convertToEnum(QMetaType fromType, const void *from, QMetaType toType #ifndef QT_NO_QOBJECT if (fromTypeId == QMetaType::QString || fromTypeId == QMetaType::QByteArray) { QMetaEnum en = metaEnumFromType(toType); - if (!en.isValid()) - return false; - QByteArray keys = (fromTypeId == QMetaType::QString) - ? static_cast<const QString *>(from)->toUtf8() - : *static_cast<const QByteArray *>(from); - value = en.keysToValue(keys.constData(), &ok); + if (en.isValid()) { + QByteArray keys = (fromTypeId == QMetaType::QString) + ? static_cast<const QString *>(from)->toUtf8() + : *static_cast<const QByteArray *>(from); + value = en.keysToValue(keys.constData(), &ok); + } } #endif if (!ok) { @@ -1884,8 +2051,7 @@ static bool convertToEnum(QMetaType fromType, const void *from, QMetaType toType *static_cast<qint64 *>(to) = value; return true; default: - Q_UNREACHABLE(); - return false; + Q_UNREACHABLE_RETURN(false); } } @@ -1933,13 +2099,12 @@ static bool convertIterableToVariantHash(QMetaType fromType, const void *from, v h.insert(it.key().toString(), it.value()); return true; } -#endif static bool convertIterableToVariantPair(QMetaType fromType, const void *from, void *to) { - const QMetaType::ConverterFunction * const f = - customTypesConversionRegistry()->function(qMakePair(fromType.id(), - qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>())); + const int targetId = qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>(); + const auto f = customTypesConversionRegistry()->function({fromType.id(), targetId}); + if (!f) return false; @@ -1965,7 +2130,6 @@ static bool convertIterableToVariantPair(QMetaType fromType, const void *from, v return true; } -#ifndef QT_BOOTSTRAPPED static bool convertToSequentialIterable(QMetaType fromType, const void *from, void *to) { using namespace QtMetaTypePrivate; @@ -2091,6 +2255,9 @@ static bool convertToAssociativeIterable(QMetaType fromType, const void *from, v static bool canConvertMetaObject(QMetaType fromType, QMetaType toType) { + if ((fromType.flags() & QMetaType::IsPointer) != (toType.flags() & QMetaType::IsPointer)) + return false; // Can not convert between pointer and value + const QMetaObject *f = fromType.metaObject(); const QMetaObject *t = toType.metaObject(); if (f && t) { @@ -2161,7 +2328,8 @@ static bool convertMetaObject(QMetaType fromType, const void *from, QMetaType to *static_cast<void **>(to) = nullptr; return fromType.metaObject()->inherits(toType.metaObject()); } - } else { + } else if ((fromType.flags() & QMetaType::IsPointer) == (toType.flags() & QMetaType::IsPointer)) { + // fromType and toType are of same 'pointedness' const QMetaObject *f = fromType.metaObject(); const QMetaObject *t = toType.metaObject(); if (f && t && f->inherits(t)) { @@ -2172,7 +2340,7 @@ static bool convertMetaObject(QMetaType fromType, const void *from, QMetaType to } return false; } -#endif +#endif // !QT_BOOTSTRAPPED /*! \fn bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId) @@ -2213,8 +2381,7 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType, if (moduleHelper->convert(from, fromTypeId, to, toTypeId)) return true; } - const QMetaType::ConverterFunction * const f = - customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId)); + const auto f = customTypesConversionRegistry()->function({fromTypeId, toTypeId}); if (f) return (*f)(from, to); @@ -2230,10 +2397,11 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType, } } +#ifndef QT_BOOTSTRAPPED +# ifndef QT_NO_VARIANT if (toTypeId == QVariantPair && convertIterableToVariantPair(fromType, from, to)) return true; -#ifndef QT_BOOTSTRAPPED // handle iterables if (toTypeId == QVariantList && convertIterableToVariantList(fromType, from, to)) return true; @@ -2243,6 +2411,7 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType, if (toTypeId == QVariantHash && convertIterableToVariantHash(fromType, from, to)) return true; +# endif if (toTypeId == qMetaTypeId<QSequentialIterable>()) return convertToSequentialIterable(fromType, from, to); @@ -2269,8 +2438,7 @@ bool QMetaType::view(QMetaType fromType, void *from, QMetaType toType, void *to) int fromTypeId = fromType.id(); int toTypeId = toType.id(); - const QMetaType::MutableViewFunction * const f = - customTypesMutableViewRegistry()->function(qMakePair(fromTypeId, toTypeId)); + const auto f = customTypesMutableViewRegistry()->function({fromTypeId, toTypeId}); if (f) return (*f)(from, to); @@ -2312,8 +2480,7 @@ bool QMetaType::canView(QMetaType fromType, QMetaType toType) if (fromTypeId == UnknownType || toTypeId == UnknownType) return false; - const MutableViewFunction * const f = - customTypesMutableViewRegistry()->function(qMakePair(fromTypeId, toTypeId)); + const auto f = customTypesMutableViewRegistry()->function({fromTypeId, toTypeId}); if (f) return true; @@ -2418,7 +2585,7 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType) return true; } const ConverterFunction * const f = - customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId)); + customTypesConversionRegistry()->function(std::make_pair(fromTypeId, toTypeId)); if (f) return true; @@ -2428,7 +2595,8 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType) if (toTypeId == qMetaTypeId<QAssociativeIterable>()) return canConvertToAssociativeIterable(fromType); - +#endif +#ifndef QT_NO_VARIANT if (toTypeId == QVariantList && canConvert(fromType, QMetaType::fromType<QSequentialIterable>())) { return true; @@ -2438,11 +2606,11 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType) && canConvert(fromType, QMetaType::fromType<QAssociativeIterable>())) { return true; } -#endif if (toTypeId == QVariantPair && hasRegisteredConverterFunction( fromType, QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>())) return true; +#endif if (fromType.flags() & IsEnumeration) { if (toTypeId == QString || toTypeId == QByteArray) @@ -2474,7 +2642,7 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType) */ /*! - \fn bool QMetaType::hasRegisteredConverterFunction() + \fn template<typename From, typename To> bool QMetaType::hasRegisteredConverterFunction() Returns \c true, if the meta type system has a registered conversion from type From to type To. \since 5.2 \overload @@ -2487,11 +2655,11 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType) */ bool QMetaType::hasRegisteredConverterFunction(QMetaType fromType, QMetaType toType) { - return customTypesConversionRegistry()->contains(qMakePair(fromType.id(), toType.id())); + return customTypesConversionRegistry()->contains({fromType.id(), toType.id()}); } /*! - \fn bool QMetaType::hasRegisteredMutableViewFunction() + \fn template<typename From, typename To> bool QMetaType::hasRegisteredMutableViewFunction() Returns \c true, if the meta type system has a registered mutable view on type From of type To. \since 6.0 \overload @@ -2504,7 +2672,7 @@ bool QMetaType::hasRegisteredConverterFunction(QMetaType fromType, QMetaType toT */ bool QMetaType::hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType) { - return customTypesMutableViewRegistry()->contains(qMakePair(fromType.id(), toType.id())); + return customTypesMutableViewRegistry()->contains({fromType.id(), toType.id()}); } /*! @@ -2555,7 +2723,7 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length) Q_ASSERT(!reg->lock.tryLockForWrite()); #endif if (auto ti = reg->aliases.value(QByteArray::fromRawData(typeName, length), nullptr)) { - return ti->typeId; + return ti->typeId.loadRelaxed(); } } return QMetaType::UnknownType; @@ -2582,6 +2750,20 @@ void QMetaType::registerNormalizedTypedef(const NS(QByteArray) & normalizedTypeN } } + +static const QtPrivate::QMetaTypeInterface *interfaceForTypeNoWarning(int typeId) +{ + const QtPrivate::QMetaTypeInterface *iface = nullptr; + if (typeId >= QMetaType::User) { + if (customTypeRegistry.exists()) + iface = customTypeRegistry->getCustomType(typeId); + } else { + if (auto moduleHelper = qModuleHelperForType(typeId)) + iface = moduleHelper->interfaceForType(typeId); + } + return iface; +} + /*! Returns \c true if the datatype with ID \a type is registered; otherwise returns \c false. @@ -2590,7 +2772,7 @@ void QMetaType::registerNormalizedTypedef(const NS(QByteArray) & normalizedTypeN */ bool QMetaType::isRegistered(int type) { - return QMetaType(type).isRegistered(); + return interfaceForTypeNoWarning(type) != nullptr; } template <bool tryNormalizedType> @@ -2658,9 +2840,6 @@ Q_CORE_EXPORT int qMetaTypeTypeInternal(const char *typeName) Returns \c true if the object is saved successfully; otherwise returns \c false. - The type must have been registered with Q_DECLARE_METATYPE() - beforehand. - Normally, you should not need to call this function directly. Instead, use QVariant's \c operator<<(), which relies on save() to stream custom types. @@ -2699,9 +2878,6 @@ bool QMetaType::save(QDataStream &stream, const void *data) const Returns \c true if the object is loaded successfully; otherwise returns \c false. - The type must have been registered with Q_DECLARE_METATYPE() - beforehand. - Normally, you should not need to call this function directly. Instead, use QVariant's \c operator>>(), which relies on load() to stream custom types. @@ -2747,6 +2923,59 @@ bool QMetaType::hasRegisteredDataStreamOperators() const } /*! + \since 6.6 + + If this metatype represents an enumeration, this method returns a + metatype of a numeric class of the same signedness and size as the + enums underlying type. + If it represents a QFlags type, it returns QMetaType::Int. + In all other cases an invalid QMetaType is returned. + */ +QMetaType QMetaType::underlyingType() const +{ + if (!d_ptr || !(flags() & IsEnumeration)) + return {}; + /* QFlags has enumeration set so that's handled here (qint32 + case), as QFlags uses int as the underlying type + Note that we do some approximation here, as we cannot + differentiate between different underlying types of the + same size and signedness (consider char <-> (un)signed char, + int <-> long <-> long long). + + ### TODO PENDING: QTBUG-111926 - QFlags supporting >32 bit int + */ + if (flags() & IsUnsignedEnumeration) { + switch (sizeOf()) { + case 1: + return QMetaType::fromType<quint8>(); + case 2: + return QMetaType::fromType<quint16>(); + case 4: + return QMetaType::fromType<quint32>(); + case 8: + return QMetaType::fromType<quint64>(); + default: + break; + } + } else { + switch (sizeOf()) { + case 1: + return QMetaType::fromType<qint8>(); + case 2: + return QMetaType::fromType<qint16>(); + case 4: + return QMetaType::fromType<qint32>(); + case 8: + return QMetaType::fromType<qint64>(); + default: + break; + } + } + // int128 can be handled above once we have qint128 + return QMetaType(); +} + +/*! \fn bool QMetaType::load(QDataStream &stream, int type, void *data) \overload \deprecated @@ -2858,8 +3087,9 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) */ /*! - \fn int qRegisterMetaType(const char *typeName) + \fn template <typename T> int qRegisterMetaType(const char *typeName) \relates QMetaType + \obsolete \threadsafe Registers the type name \a typeName for the type \c{T}. Returns @@ -2891,13 +3121,12 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) */ /*! - \fn int qRegisterMetaType() + \fn template <typename T> int qRegisterMetaType() \relates QMetaType \threadsafe \since 4.2 - Call this function to register the type \c T. \c T must be declared with - Q_DECLARE_METATYPE(). Returns the meta type Id. + Call this function to register the type \c T. Returns the meta type Id. Example: @@ -2908,24 +3137,47 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able to register pointers to forward declared types. - After a type has been registered, you can create and destroy - objects of that type dynamically at run-time. + To use the type \c T in QMetaType, QVariant, or with the + QObject::property() API, registration is not necessary. - To use the type \c T in QVariant, using Q_DECLARE_METATYPE() is - sufficient. To use the type \c T in queued signal and slot connections, - \c{qRegisterMetaType<T>()} must be called before the first connection - is established. + To use the type \c T in queued signal and slot connections, + \c{qRegisterMetaType<T>()} must be called before the first connection is + established. That is typically done in the constructor of the class that + uses \c T, or in the \c{main()} function. - Also, to use type \c T with the QObject::property() API, - \c{qRegisterMetaType<T>()} must be called before it is used, typically - in the constructor of the class that uses \c T, or in the \c{main()} - function. + After a type has been registered, it can be found by its name using + QMetaType::fromName(). \sa Q_DECLARE_METATYPE() */ /*! - \fn int qMetaTypeId() + \fn int qRegisterMetaType(QMetaType meta) + \relates QMetaType + \threadsafe + \since 6.5 + + Registers the meta type \a meta and returns its type Id. + + This function requires that \c{T} is a fully defined type at the point + where the function is called. For pointer types, it also requires that the + pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able + to register pointers to forward declared types. + + To use the type \c T in QMetaType, QVariant, or with the + QObject::property() API, registration is not necessary. + + To use the type \c T in queued signal and slot connections, + \c{qRegisterMetaType<T>()} must be called before the first connection is + established. That is typically done in the constructor of the class that + uses \c T, or in the \c{main()} function. + + After a type has been registered, it can be found by its name using + QMetaType::fromName(). + */ + +/*! + \fn template <typename T> int qMetaTypeId() \relates QMetaType \threadsafe \since 4.1 @@ -2948,15 +3200,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) static const QtPrivate::QMetaTypeInterface *interfaceForType(int typeId) { - const QtPrivate::QMetaTypeInterface *iface = nullptr; - if (typeId >= QMetaType::User) { - if (customTypeRegistry.exists()) - iface = customTypeRegistry->getCustomType(typeId); - } else { - if (auto moduleHelper = qModuleHelperForType(typeId)) - iface = moduleHelper->interfaceForType(typeId); - } - + const QtPrivate::QMetaTypeInterface *iface = interfaceForTypeNoWarning(typeId); if (!iface && typeId != QMetaType::UnknownType) qWarning("Trying to construct an instance of an invalid type, type id: %i", typeId); @@ -2964,6 +3208,13 @@ static const QtPrivate::QMetaTypeInterface *interfaceForType(int typeId) } /*! + \fn QMetaType::QMetaType() + \since 6.0 + + Constructs a default, invalid, QMetaType object. +*/ + +/*! \fn QMetaType::QMetaType(int typeId) \since 5.0 @@ -2991,6 +3242,7 @@ QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_TEMPLATE_ITER) QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_TEMPLATE_ITER) QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_TEMPLATE_ITER) QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_TEMPLATE_ITER) + #undef QT_METATYPE_DECLARE_TEMPLATE_ITER #endif } |