diff options
Diffstat (limited to 'src/corelib/kernel/qmetatype.cpp')
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 794 |
1 files changed, 530 insertions, 264 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index bb4090129f..ae56de118c 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1,48 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +// Copyright (C) 2021 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qmetatype.h" #include "qmetatype_p.h" +#include "qobject.h" #include "qobjectdefs.h" #include "qdatetime.h" #include "qbytearray.h" #include "qreadwritelock.h" +#include "qhash.h" +#include "qmap.h" #include "qstring.h" #include "qstringlist.h" #include "qlist.h" @@ -52,14 +21,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" @@ -95,37 +64,64 @@ QT_BEGIN_NAMESPACE #define NS(x) QT_PREPEND_NAMESPACE(x) +QT_IMPL_METATYPE_EXTERN_TAGGED(QtMetaTypePrivate::QPairVariantInterfaceImpl, QPairVariantInterfaceImpl) + +using QtMetaTypePrivate::isInterfaceFor; namespace { -struct DefinedTypesFilter { - template<typename T> - struct Acceptor { - static const bool IsAccepted = QtMetaTypePrivate::TypeDefinition<T>::IsAvailable && QModulesPrivate::QTypeModuleInfo<T>::IsCore; - }; +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; // index of first empty (unregistered) type in registry, if any. int firstEmpty = 0; - int registerCustomType(const QtPrivate::QMetaTypeInterface *ti) + int registerCustomType(const QtPrivate::QMetaTypeInterface *cti) { + // we got here because cti->typeId is 0, so this is a custom meta type + // (not read-only) + auto ti = const_cast<QtPrivate::QMetaTypeInterface *>(cti); { QWriteLocker l(&lock); - if (ti->typeId) - return ti->typeId; + if (int id = ti->typeId.loadRelaxed()) + return id; QByteArray name = #ifndef QT_NO_QOBJECT QMetaObject::normalizedType #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(); @@ -138,11 +134,11 @@ struct QMetaTypeCustomRegistry registry.append(ti); firstEmpty = registry.size(); } - ti->typeId = firstEmpty + QMetaType::User; + ti->typeId.storeRelaxed(firstEmpty + QMetaType::User); } if (ti->legacyRegisterOp) ti->legacyRegisterOp(); - return ti->typeId; + return ti->typeId.loadRelaxed(); }; void unregisterDynamicType(int id) @@ -179,6 +175,44 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) } // namespace +// used by QVariant::save(): returns the name used in the Q_DECLARE_METATYPE +// macro (one of them, indetermine which one) +const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInterface *type_d) +{ + const char *name = nullptr; + if (!customTypeRegistry.exists()) + return name; + QMetaTypeCustomRegistry *r = &*customTypeRegistry; + + QByteArrayView officialName(type_d->name); + QReadLocker l(&r->lock); + auto it = r->aliases.constBegin(); + auto end = r->aliases.constEnd(); + for ( ; it != end; ++it) { + if (it.value() != type_d) + continue; + if (it.key() == officialName) + continue; // skip the official name + name = it.key().constData(); + ++it; + break; + } + +#ifndef QT_NO_DEBUG + QByteArrayList otherNames; + for ( ; it != end; ++it) { + if (it.value() == type_d && it.key() != officialName) + otherNames << it.key(); + } + l.unlock(); + if (!otherNames.isEmpty()) + qWarning("QMetaType: type %s has more than one typedef alias: %s, %s", + type_d->name, name, otherNames.join(", ").constData()); +#endif + + return name; +} + /*! \macro Q_DECLARE_OPAQUE_POINTER(PointerType) \relates QMetaType @@ -235,7 +269,7 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) \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 @@ -333,8 +367,12 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) \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 @@ -352,6 +390,7 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) \value QStringList QStringList \value QVariantMap QVariantMap \value QVariantHash QVariantHash + \value QVariantPair QVariantPair \value QIcon QIcon \value QPen QPen \value QLineF QLineF @@ -392,13 +431,13 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) \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() */ @@ -408,20 +447,31 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) 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 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. */ /*! @@ -435,17 +485,19 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) 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 @@ -463,6 +515,8 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry) Returns \c true if this QMetaType object contains valid information about a type, false otherwise. + + \sa isRegistered() */ bool QMetaType::isValid() const { @@ -473,37 +527,49 @@ 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; } /*! - \fn constexpr bool QMetaType::sizeOf() const + \fn constexpr qsizetype QMetaType::sizeOf() const \since 5.0 Returns the size of the type in bytes (i.e. sizeof(T), @@ -535,28 +601,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() */ @@ -573,16 +645,17 @@ int QMetaType::idHelper() const */ void *QMetaType::create(const void *copy) const { - if (d_ptr) { - 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(); } /*! @@ -596,14 +669,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); } } @@ -637,16 +705,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; } /*! @@ -662,12 +725,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) @@ -710,7 +769,7 @@ QPartialOrdering QMetaType::compare(const void *lhs, const void *rhs) const { if (!lhs || !rhs) return QPartialOrdering::Unordered; - if (d_ptr->flags & QMetaType::IsPointer) + if (d_ptr && d_ptr->flags & QMetaType::IsPointer) return threeWayCompare(*reinterpret_cast<const void * const *>(lhs), *reinterpret_cast<const void * const *>(rhs)); if (d_ptr && d_ptr->lessThan) { @@ -759,6 +818,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. @@ -786,11 +907,22 @@ bool QMetaType::isOrdered() const */ void QMetaType::unregisterMetaType(QMetaType type) { - if (type.d_ptr && type.d_ptr->typeId.loadRelaxed() >= QMetaType::User) { - if (auto reg = customTypeRegistry()) - reg->unregisterDynamicType(type.d_ptr->typeId.loadRelaxed()); - type.d_ptr->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); } /*! @@ -816,6 +948,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 }, @@ -831,10 +969,11 @@ 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>, QLatin1String, const char *>> + std::conditional_t<std::is_same_v<T, QString>, QLatin1StringView, const char *>> static inline bool convertToBool(const T &source) { T str = source.toLower(); @@ -1076,7 +1215,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;); @@ -1131,34 +1270,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) @@ -1170,7 +1311,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, @@ -1509,16 +1650,15 @@ static const struct : QMetaTypeModuleHelper } return false; } -} metatypeHelper; +} metatypeHelper = {}; -static const QMetaTypeModuleHelper *qMetaTypeCoreHelper = &metatypeHelper; -Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper = nullptr; -Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeWidgetsHelper = nullptr; +Q_CONSTINIT Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper = nullptr; +Q_CONSTINIT Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeWidgetsHelper = nullptr; static const QMetaTypeModuleHelper *qModuleHelperForType(int type) { if (type <= QMetaType::LastCoreType) - return qMetaTypeCoreHelper; + return &metatypeHelper; if (type >= QMetaType::FirstGuiType && type <= QMetaType::LastGuiType) return qMetaTypeGuiHelper; else if (type >= QMetaType::FirstWidgetsType && type <= QMetaType::LastWidgetsType) @@ -1545,9 +1685,11 @@ public: bool insertIfNotContains(Key k, const T &f) { const QWriteLocker locker(&lock); - if (map.contains(k)) + const qsizetype oldSize = map.size(); + auto &e = map[k]; + if (map.size() == oldSize) // already present return false; - map.insert(k, f); + e = f; return true; } @@ -1569,44 +1711,57 @@ 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. + + \snippet qmetatype/registerConverters.cpp implicit */ /*! - \fn template<typename MemberFunction, int> bool QMetaType::registerConverter(MemberFunction function) + \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 to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false. + + \snippet qmetatype/registerConverters.cpp member */ /*! - \fn template<typename MemberFunctionOk, char> bool QMetaType::registerConverter(MemberFunctionOk function) + \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 \c ok pointer can be used by the function to indicate whether the conversion succeeded. + \snippet qmetatype/registerConverters.cpp memberOk + */ /*! - \fn template<typename UnaryFunction> bool QMetaType::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 \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 */ /*! @@ -1618,7 +1773,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; @@ -1627,7 +1782,7 @@ bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType } /*! - \fn template<typename MemberFunction, int> bool QMetaType::registerMutableView(MemberFunction 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 @@ -1636,16 +1791,7 @@ bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType */ /*! - \fn template<typename MemberFunctionOk, char> bool QMetaType::registerMutableView(MemberFunctionOk function) - \since 6.0 - \overload - Registers a method \a function like To From::function(bool *ok) as mutable view of type To on - type From in the meta type system. Returns \c true if the registration succeeded, otherwise - \c false. -*/ - -/*! - \fn template<typename UnaryFunction> bool QMetaType::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 @@ -1660,7 +1806,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; @@ -1693,6 +1839,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 @@ -1713,12 +1870,12 @@ bool QMetaType::debugStream(QDebug& dbg, const void *rhs) /*! \fn bool QMetaType::debugStream(QDebug& dbg, const void *rhs, int typeId) \overload - \obsolete + \deprecated */ /*! - \fn bool QMetaType::hasRegisteredDebugStreamOperator() - \obsolete + \fn template<typename T> bool QMetaType::hasRegisteredDebugStreamOperator() + \deprecated \since 5.2 Returns \c true, if the meta type system has a registered debug stream operator for type T. @@ -1726,7 +1883,7 @@ bool QMetaType::debugStream(QDebug& dbg, const void *rhs) /*! \fn bool QMetaType::hasRegisteredDebugStreamOperator(int typeId) - \obsolete Use QMetaType::hasRegisteredDebugStreamOperator() instead. + \deprecated Use QMetaType::hasRegisteredDebugStreamOperator() instead. Returns \c true, if the meta type system has a registered debug stream operator for type id \a typeId. @@ -1754,10 +1911,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(); @@ -1816,35 +1979,44 @@ 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; } static bool convertToEnum(QMetaType fromType, const void *from, QMetaType toType, void *to) { int fromTypeId = fromType.id(); - qlonglong value; + qlonglong value = -1; bool ok = false; #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) { @@ -1873,8 +2045,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); } } @@ -1922,13 +2093,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; @@ -1954,7 +2124,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; @@ -2080,6 +2249,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) { @@ -2136,7 +2308,7 @@ static bool viewAsAssociativeIterable(QMetaType fromType, void *from, void *to) return false; } -static bool convertQObject(QMetaType fromType, const void *from, QMetaType toType, void *to) +static bool convertMetaObject(QMetaType fromType, const void *from, QMetaType toType, void *to) { // handle QObject conversion if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) { @@ -2149,17 +2321,24 @@ static bool convertQObject(QMetaType fromType, const void *from, QMetaType toTyp // if fromObject is null, use static fromType to check if conversion works *static_cast<void **>(to) = nullptr; return fromType.metaObject()->inherits(toType.metaObject()); - } else { - return false; + } + } 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)) { + toType.destruct(to); + toType.construct(to, from); + return true; } } return false; } -#endif +#endif // !QT_BOOTSTRAPPED /*! \fn bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId) - \obsolete + \deprecated Converts the object at \a from from \a fromTypeId to the preallocated space at \a to typed \a toTypeId. Returns \c true, if the conversion succeeded, otherwise false. @@ -2196,8 +2375,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); @@ -2213,10 +2391,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; @@ -2226,6 +2405,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); @@ -2233,7 +2413,7 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType, if (toTypeId == qMetaTypeId<QAssociativeIterable>()) return convertToAssociativeIterable(fromType, from, to); - return convertQObject(fromType, from, toType, to); + return convertMetaObject(fromType, from, toType, to); #else return false; #endif @@ -2252,8 +2432,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); @@ -2264,7 +2443,7 @@ bool QMetaType::view(QMetaType fromType, void *from, QMetaType toType, void *to) if (toTypeId == qMetaTypeId<QAssociativeIterable>()) return viewAsAssociativeIterable(fromType, from, to); - return convertQObject(fromType, from, toType, to); + return convertMetaObject(fromType, from, toType, to); #else return false; #endif @@ -2295,8 +2474,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; @@ -2401,7 +2579,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; @@ -2411,7 +2589,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; @@ -2421,11 +2600,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) @@ -2457,7 +2636,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 @@ -2470,11 +2649,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 @@ -2487,7 +2666,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()}); } /*! @@ -2532,12 +2711,13 @@ static inline int qMetaTypeStaticType(const char *typeName, int length) */ static int qMetaTypeCustomType_unlocked(const char *typeName, int length) { - if (auto reg = customTypeRegistry()) { + if (customTypeRegistry.exists()) { + auto reg = &*customTypeRegistry; #if QT_CONFIG(thread) Q_ASSERT(!reg->lock.tryLockForWrite()); #endif - if (auto ti = reg->aliases.value(QByteArray(typeName, length), nullptr)) { - return ti->typeId; + if (auto ti = reg->aliases.value(QByteArray::fromRawData(typeName, length), nullptr)) { + return ti->typeId.loadRelaxed(); } } return QMetaType::UnknownType; @@ -2564,6 +2744,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. @@ -2572,7 +2766,7 @@ void QMetaType::registerNormalizedTypedef(const NS(QByteArray) & normalizedTypeN */ bool QMetaType::isRegistered(int type) { - return QMetaType(type).isRegistered(); + return interfaceForTypeNoWarning(type) != nullptr; } template <bool tryNormalizedType> @@ -2610,7 +2804,7 @@ static inline int qMetaTypeTypeImpl(const char *typeName, int length) */ /*! - \a internal + \internal Similar to QMetaType::type(); the only difference is that this function doesn't attempt to normalize the type name (i.e., the lookup will fail @@ -2640,9 +2834,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. @@ -2673,7 +2864,7 @@ bool QMetaType::save(QDataStream &stream, const void *data) const /*! \fn bool QMetaType::save(QDataStream &stream, int type, const void *data) \overload - \obsolete + \deprecated */ /*! @@ -2681,9 +2872,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. @@ -2729,9 +2917,62 @@ 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 - \obsolete + \deprecated */ #endif // QT_NO_DATASTREAM @@ -2840,8 +3081,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 @@ -2873,13 +3115,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: @@ -2890,24 +3131,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 @@ -2930,15 +3194,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) static const QtPrivate::QMetaTypeInterface *interfaceForType(int typeId) { - const QtPrivate::QMetaTypeInterface *iface = nullptr; - if (typeId >= QMetaType::User) { - if (auto reg = customTypeRegistry()) - iface = reg->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); @@ -2946,6 +3202,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 @@ -2953,25 +3216,28 @@ static const QtPrivate::QMetaTypeInterface *interfaceForType(int typeId) */ QMetaType::QMetaType(int typeId) : QMetaType(interfaceForType(typeId)) {} -namespace QtPrivate { -#ifndef QT_BOOTSTRAPPED -#if defined(Q_CC_MSVC) && defined(QT_BUILD_CORE_LIB) -#define QT_METATYPE_TEMPLATE_EXPORT Q_CORE_EXPORT -#else -#define QT_METATYPE_TEMPLATE_EXPORT -#endif +/*! \fn size_t qHash(QMetaType type, size_t seed = 0) + \relates QMetaType + \since 6.4 + + Returns the hash value for the \a type, using \a seed to seed the calculation. +*/ + +namespace QtPrivate { +#if !defined(QT_BOOTSTRAPPED) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY) // Explicit instantiation definition -#define QT_METATYPE_DECLARE_TEMPLATE_ITER(TypeName, Id, Name) \ - template class QT_METATYPE_TEMPLATE_EXPORT QMetaTypeForType<Name>; -QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_DECLARE_TEMPLATE_ITER) +#define QT_METATYPE_DECLARE_TEMPLATE_ITER(TypeName, Id, Name) \ + template class QMetaTypeForType<Name>; \ + template struct QMetaTypeInterfaceWrapper<Name>; +QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(QT_METATYPE_DECLARE_TEMPLATE_ITER) 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 -#undef QT_METATYPE_TEMPLATE_EXPORT #endif } |