diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2022-07-19 12:31:07 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2022-07-26 20:12:30 -0700 |
commit | 74fac865cf7c55d3afba1043072ba6cc932d161d (patch) | |
tree | 4bb096785a07fb5986c2b1311de66fbd1a32c349 | |
parent | b1d9331c156b7ff5c724600eee21ac50f4565868 (diff) |
QMetaType: add registerType() and qRegisterMetaType(QMetaType)
This also rewrites QMetaType::id() on top of the helper, with the benefit
of calling a member static function, so QMetaType doesn't need to be
spilled onto the stack. In some upcoming changes I need to ensure that
QMetaTypes are registered so they can be found by name and I'd like to
have a dedicated function name for that, instead of calling .id().
Since I needed to add docs for the new function, I've updated for the
old one too.
[ChangeLog][QMetaType] Added QMetaType::registerType() and an overload
of qRegisterMetaType() taking QMetaType (the two functions do the same
thing). These two functions ensure a given QMetaType is registered with
the Qt global registry, so they can be found by name later. Using
qRegisterMetaType<T>() also accomplishes the same thing, but is slightly
better for completely generic code because it will avoid emitting the
registration for built-in types.
Change-Id: I3859764fed084846bcb0fffd170351d606034c22
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/corelib/compat/removed_api.cpp | 8 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 68 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 36 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp | 24 |
4 files changed, 112 insertions, 24 deletions
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp index c4fe85f84f..7ffefa027e 100644 --- a/src/corelib/compat/removed_api.cpp +++ b/src/corelib/compat/removed_api.cpp @@ -283,6 +283,14 @@ QT_WARNING_POP #if QT_CORE_REMOVED_SINCE(6, 5) +#include "qmetatype.h" + +int QMetaType::idHelper() const +{ + Q_ASSERT(d_ptr); + return registerHelper(d_ptr); +} + #include "qxmlstream.h" QXmlStreamReader::QXmlStreamReader(const QByteArray &data) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 4aed2edebb..ea7cd4a0c9 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -495,19 +495,28 @@ bool QMetaType::isRegistered() const \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; } @@ -2890,6 +2899,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) /*! \fn int qRegisterMetaType(const char *typeName) \relates QMetaType + \obsolete \threadsafe Registers the type name \a typeName for the type \c{T}. Returns @@ -2926,8 +2936,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) \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: @@ -2938,23 +2947,46 @@ 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 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 int qMetaTypeId() \relates QMetaType \threadsafe diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index f4d3c5b54d..e9599af5bb 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -426,6 +426,11 @@ public: bool isValid() const; bool isRegistered() const; + void registerType() const + { + // "register" is a reserved keyword + registerHelper(); + } #if QT_CORE_REMOVED_SINCE(6, 1) || defined(Q_QDOC) int id() const; #else @@ -434,12 +439,7 @@ public: int id(int = 0) const { // keep in sync with the version in removed_api.cpp - if (d_ptr) { - if (int id = d_ptr->typeId.loadRelaxed()) - return id; - return idHelper(); - } - return 0; + return registerHelper(); } #endif constexpr qsizetype sizeOf() const; @@ -722,7 +722,23 @@ public: const QtPrivate::QMetaTypeInterface *iface() const { return d_ptr; } private: +#if QT_CORE_REMOVED_SINCE(6, 5) int idHelper() const; +#endif + static int registerHelper(const QtPrivate::QMetaTypeInterface *iface); + int registerHelper() const + { + // keep in sync with the QMetaType::id() version in removed_api.cpp + if (d_ptr) { + if (int id = d_ptr->typeId.loadRelaxed()) + return id; + return registerHelper(d_ptr); + } + return 0; + } + + friend int qRegisterMetaType(QMetaType meta); + friend class QVariant; const QtPrivate::QMetaTypeInterface *d_ptr = nullptr; }; @@ -1285,6 +1301,9 @@ template <typename T> inline constexpr int qMetaTypeId() { if constexpr (bool(QMetaTypeId2<T>::IsBuiltIn)) { + // this has the same result as the below code, but avoids asking the + // compiler to load a global variable whose value we know at compile + // time return QMetaTypeId2<T>::MetaType; } else { return QMetaType::fromType<T>().id(); @@ -1298,6 +1317,11 @@ inline constexpr int qRegisterMetaType() return id; } +inline int qRegisterMetaType(QMetaType meta) +{ + return meta.registerHelper(); +} + #ifndef QT_NO_QOBJECT template <typename T> struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject> diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 9a3ab830cb..c25c5c6b16 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -1424,20 +1424,27 @@ void tst_QMetaType::typedefs() QCOMPARE(QMetaType::type("WhityDouble"), ::qMetaTypeId<WhityDouble>()); } +struct RegisterTypeType {}; + void tst_QMetaType::registerType() { // Built-in QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString)); QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString)); + qRegisterMetaType(QMetaType::fromType<QString>()); // Custom int fooId = qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo"); QVERIFY(fooId >= int(QMetaType::User)); QCOMPARE(qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo"), fooId); + qRegisterMetaType(QMetaType::fromType<TestSpace::Foo>()); int movableId = qRegisterMetaType<CustomMovable>("CustomMovable"); QVERIFY(movableId >= int(QMetaType::User)); QCOMPARE(qRegisterMetaType<CustomMovable>("CustomMovable"), movableId); + qRegisterMetaType(QMetaType::fromType<CustomMovable>()); + + // Aliases are deprecated // Alias to built-in typedef QString MyString; @@ -1460,6 +1467,23 @@ void tst_QMetaType::registerType() QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId); QCOMPARE(QMetaType::type("MyFoo"), fooId); + + // this portion of the test can only be run once + static bool typeWasRegistered = false; + if (!typeWasRegistered) { + QMetaType mt = QMetaType::fromType<RegisterTypeType>(); + QVERIFY(mt.isValid()); + QCOMPARE_NE(mt.name(), nullptr); + + QVERIFY(!mt.isRegistered()); + QVERIFY(!QMetaType::fromName(mt.name()).isValid()); + + QCOMPARE_GT(qRegisterMetaType(mt), 0); + typeWasRegistered = true; + + QVERIFY(mt.isRegistered()); + QVERIFY(QMetaType::fromName(mt.name()).isValid()); + } } class IsRegisteredDummyType { }; |