summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qmetatype.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qmetatype.cpp')
-rw-r--r--src/corelib/kernel/qmetatype.cpp2792
1 files changed, 2120 insertions, 672 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 1422e60a1c..387c0f49ab 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** 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"
@@ -43,23 +9,25 @@
#include "qdatetime.h"
#include "qbytearray.h"
#include "qreadwritelock.h"
+#include "qhash.h"
+#include "qmap.h"
#include "qstring.h"
#include "qstringlist.h"
#include "qlist.h"
#include "qlocale.h"
+#include "qdebug.h"
#if QT_CONFIG(easingcurve)
#include "qeasingcurve.h"
#endif
#include "quuid.h"
-#include "qvariant.h"
-#include "qdatastream.h"
-#include "qmetatypeswitcher_p.h"
#if QT_CONFIG(regularexpression)
# include "qregularexpression.h"
#endif
#ifndef QT_BOOTSTRAPPED
+# include "qdatastream.h"
+
# include "qbitarray.h"
# include "qurl.h"
# include "qvariant.h"
@@ -71,6 +39,10 @@
# include "qcborarray.h"
# include "qcbormap.h"
# include "qbytearraylist.h"
+# include "qmetaobject.h"
+# include "qsequentialiterable.h"
+# include "qassociativeiterable.h"
+# include "qobject.h"
#endif
#if QT_CONFIG(itemmodel)
@@ -84,52 +56,71 @@
# include "qline.h"
#endif
-#include <bitset>
#include <new>
+#include <cstring>
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
{
- QReadWriteLock lock;
- QList<QtPrivate::QMetaTypeInterface *> registry;
- QHash<QByteArray, QtPrivate::QMetaTypeInterface *> aliases;
-#ifndef QT_NO_DATASTREAM
- struct DataStreamOps
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ QMetaTypeCustomRegistry()
{
- QMetaType::SaveOperator saveOp;
- QMetaType::LoadOperator loadOp;
- };
- QHash<int, DataStreamOps> dataStreamOp;
+ /* 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(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();
@@ -142,11 +133,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)
@@ -159,20 +150,14 @@ 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;
firstEmpty = std::min(firstEmpty, idx);
}
- QtPrivate::QMetaTypeInterface *getCustomType(int id)
+ const QtPrivate::QMetaTypeInterface *getCustomType(int id)
{
QReadLocker l(&lock);
return registry.value(id - QMetaType::User - 1);
@@ -183,6 +168,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
@@ -239,13 +262,23 @@ 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
\li Classes that have a Q_GADGET macro
\endlist
+ \note This method also registers the stream and debug operators for the type if they
+ are visible at registration time. As this is done automatically in some places,
+ it is strongly recommended to declare the stream operators for a type directly
+ after the type itself. Because of the argument dependent lookup rules of C++, it is
+ also strongly recommended to declare the operators in the same namespace as the type itself.
+
+ The stream operators should have the following signatures:
+
+ \snippet code/src_corelib_kernel_qmetatype.cpp 6
+
\sa qRegisterMetaType()
*/
@@ -319,14 +352,20 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry)
\value LongLong LongLong
\value Short \c{short}
\value Char \c{char}
+ \value Char16 \c{char16_t}
+ \value Char32 \c{char32_t}
\value ULong \c{unsigned long}
\value ULongLong ULongLong
\value UShort \c{unsigned short}
\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
@@ -344,6 +383,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
@@ -384,13 +424,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()
*/
@@ -400,17 +440,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 MovableType An instance of a type having this attribute can be safely moved by memcpy.
+ \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 PointerToQObject This type is a pointer to a derived of QObject
+ \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 class derived from QObject.
+ \value IsPointer This type is a pointer to another type.
\omitvalue WeakPointerToQObject
\omitvalue TrackingPointerToQObject
- \omitvalue WasDeclaredAsMetaType
- \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.
*/
/*!
@@ -424,17 +478,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
@@ -452,6 +508,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
{
@@ -462,35 +520,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.
*/
-int QMetaType::id() const
+
+/*!
+ \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
+ Out-of-line path for registerType() and slow path id().
+ */
+int QMetaType::registerHelper(const QtPrivate::QMetaTypeInterface *iface)
{
- if (d_ptr) {
- if (d_ptr->typeId)
- return d_ptr->typeId;
- auto reg = customTypeRegistry();
- if (reg) {
- return reg->registerCustomType(d_ptr);
- }
+ Q_ASSERT(iface);
+ auto reg = customTypeRegistry();
+ if (reg) {
+ return reg->registerCustomType(iface);
}
return 0;
}
/*!
- \fn 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),
@@ -502,15 +574,9 @@ int QMetaType::id() const
\sa QMetaType::construct(), QMetaType::sizeOf(), QMetaType::alignOf()
*/
-int QMetaType::sizeOf() const
-{
- if (d_ptr)
- return d_ptr->size;
- return 0;
-}
/*!
- \fn int QMetaType::alignOf() const
+ \fn constexpr int QMetaType::alignOf() const
\since 6.0
Returns the alignment of the type in bytes (i.e. alignof(T),
@@ -523,55 +589,45 @@ int QMetaType::sizeOf() const
\sa QMetaType::construct(), QMetaType::sizeOf()
*/
-int QMetaType::alignOf() const
-{
- if (d_ptr)
- return d_ptr->alignment;
- return 0;
-}
/*!
- \fn TypeFlags QMetaType::flags() 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::typeFlags()
+ \sa QMetaType::TypeFlags, QMetaType::flags(), isDefaultConstructible(),
+ isCopyConstructible(), isMoveConstructible(), isDestructible(),
+ isEqualityComparable(), isOrdered()
*/
-QMetaType::TypeFlags QMetaType::flags() const
-{
- if (d_ptr)
- return TypeFlags(d_ptr->flags);
- return {};
-}
/*!
- \fn const QMetaObject *QMetaType::metaObject() const
+ \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::metaObjectForType(), QMetaType::flags()
+ \sa QMetaType::flags()
*/
-const QMetaObject *QMetaType::metaObject() const
-{
- return d_ptr ? d_ptr->metaObject : nullptr;
-}
/*!
- \fn void *QMetaType::create(const void *copy = 0) const
+ \fn void *QMetaType::create(const void *copy = nullptr) const
\since 5.0
Returns a copy of \a copy, assuming it is of the type that this
@@ -582,16 +638,17 @@ const QMetaObject *QMetaType::metaObject() 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();
}
/*!
@@ -605,18 +662,14 @@ void *QMetaType::create(const void *copy) const
*/
void QMetaType::destroy(void *data) const
{
- if (d_ptr && 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);
}
}
/*!
- \fn void *QMetaType::construct(void *where, const void *copy = 0) const
+ \fn void *QMetaType::construct(void *where, const void *copy = nullptr) const
\since 5.0
Constructs a value of the type that this QMetaType instance
@@ -645,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;
}
/*!
@@ -670,20 +718,28 @@ 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)
+{
+ std::less<const void *> less;
+ if (less(ptr1, ptr2))
+ return QPartialOrdering::Less;
+ if (less(ptr2, ptr1))
+ return QPartialOrdering::Greater;
+ return QPartialOrdering::Equivalent;
}
/*!
Compares the objects at \a lhs and \a rhs for ordering.
- Returns an empty optional if comparison is not supported or the values are unordered.
- Otherwise, returns -1, 0 or +1 according as \a lhs is less than, equal to or greater
- than \a rhs.
+ Returns QPartialOrdering::Unordered if comparison is not supported
+ or the values are unordered. Otherwise, returns
+ QPartialOrdering::Less, QPartialOrdering::Equivalent or
+ QPartialOrdering::Greater if \a lhs is less than, equivalent
+ to or greater than \a rhs, respectively.
Both objects must be of the type described by this metatype. If either \a lhs
or \a rhs is \nullptr, the values are unordered. Comparison is only supported
@@ -702,21 +758,24 @@ void QMetaType::destruct(void *data) const
\since 6.0
\sa equals(), isOrdered()
*/
-std::optional<int> QMetaType::compare(const void *lhs, const void *rhs) const
+QPartialOrdering QMetaType::compare(const void *lhs, const void *rhs) const
{
if (!lhs || !rhs)
- return std::optional<int>{};
+ return QPartialOrdering::Unordered;
+ 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) {
if (d_ptr->equals && d_ptr->equals(d_ptr, lhs, rhs))
- return 0;
+ return QPartialOrdering::Equivalent;
if (d_ptr->lessThan(d_ptr, lhs, rhs))
- return -1;
+ return QPartialOrdering::Less;
if (d_ptr->lessThan(d_ptr, rhs, lhs))
- return 1;
+ return QPartialOrdering::Greater;
if (!d_ptr->equals)
- return 0;
+ return QPartialOrdering::Equivalent;
}
- return std::optional<int>{};
+ return QPartialOrdering::Unordered;
}
/*!
@@ -740,6 +799,9 @@ bool QMetaType::equals(const void *lhs, const void *rhs) const
if (!lhs || !rhs)
return false;
if (d_ptr) {
+ if (d_ptr->flags & QMetaType::IsPointer)
+ return *reinterpret_cast<const void * const *>(lhs) == *reinterpret_cast<const void * const *>(rhs);
+
if (d_ptr->equals)
return d_ptr->equals(d_ptr, lhs, rhs);
if (d_ptr->lessThan && !d_ptr->lessThan(d_ptr, lhs, rhs) && !d_ptr->lessThan(d_ptr, rhs, lhs))
@@ -749,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.
@@ -756,7 +880,7 @@ bool QMetaType::equals(const void *lhs, const void *rhs) const
*/
bool QMetaType::isEqualityComparable() const
{
- return d_ptr && (d_ptr->equals != nullptr || d_ptr->lessThan != nullptr);
+ return d_ptr && (d_ptr->flags & QMetaType::IsPointer || d_ptr->equals != nullptr || d_ptr->lessThan != nullptr);
}
/*!
@@ -767,42 +891,31 @@ bool QMetaType::isEqualityComparable() const
*/
bool QMetaType::isOrdered() const
{
- return d_ptr && d_ptr->lessThan != nullptr;
+ return d_ptr && (d_ptr->flags & QMetaType::IsPointer || d_ptr->lessThan != nullptr);
}
-void QtMetaTypePrivate::derefAndDestroy(NS(QtPrivate::QMetaTypeInterface) *d_ptr)
-{
- if (d_ptr && !d_ptr->ref.deref()) {
- if (auto reg = customTypeRegistry())
- reg->unregisterDynamicType(d_ptr->typeId.loadRelaxed());
- Q_ASSERT(d_ptr->deleteSelf);
- d_ptr->deleteSelf(d_ptr);
- }
-}
/*!
- \fn QMetaType::~QMetaType()
-
- Destructs this object.
+ \internal
*/
-QMetaType::~QMetaType()
+void QMetaType::unregisterMetaType(QMetaType type)
{
- QtMetaTypePrivate::derefAndDestroy(d_ptr);
-}
+ const QtPrivate::QMetaTypeInterface *d_ptr = type.d_ptr;
+ if (!d_ptr)
+ return;
-QMetaType::QMetaType(QtPrivate::QMetaTypeInterface *d) : d_ptr(d)
-{
- if (d_ptr)
- d_ptr->ref.ref();
-}
+ const int typeId = d_ptr->typeId.loadRelaxed();
+ if (typeId < QMetaType::User)
+ return;
-QMetaType &QMetaType::operator=(const QMetaType &other)
-{
- if (d_ptr != other.d_ptr) {
- this->~QMetaType();
- new (this) QMetaType(other.d_ptr);
+ // this is a custom meta type (not read-only)
+
+ if (auto reg = customTypeRegistry()) {
+ Q_ASSERT(reg->getCustomType(typeId) == d_ptr);
+ reg->unregisterDynamicType(typeId);
}
- return *this;
+
+ const_cast<QtPrivate::QMetaTypeInterface *>(d_ptr)->typeId.storeRelease(0);
}
/*!
@@ -812,24 +925,28 @@ QMetaType &QMetaType::operator=(const QMetaType &other)
Returns the QMetaType corresponding to the type in the template parameter.
*/
-/*! \fn bool operator==(const QMetaType &a, const QMetaType &b)
+/*! \fn bool QMetaType::operator==(QMetaType a, QMetaType b)
\since 5.15
- \relates QMetaType
\overload
Returns \c true if the QMetaType \a a represents the same type
as the QMetaType \a b, otherwise returns \c false.
*/
-/*! \fn bool operator!=(const QMetaType &a, const QMetaType &b)
+/*! \fn bool QMetaType::operator!=(QMetaType a, QMetaType b)
\since 5.15
- \relates QMetaType
\overload
Returns \c true if the QMetaType \a a represents a different 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 },
@@ -845,11 +962,709 @@ static const struct { const char * typeName; int typeNameLength; int type; } typ
{nullptr, 0, QMetaType::UnknownType}
};
-Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper = nullptr;
-Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeWidgetsHelper = nullptr;
+// 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 *>>
+ static inline bool convertToBool(const T &source)
+ {
+ T str = source.toLower();
+ return !(str.isEmpty() || str == LiteralWrapper("0") || str == LiteralWrapper("false"));
+ }
+
+ const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override {
+ switch (type) {
+ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_CONVERT_ID_TO_TYPE)
+ QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_CONVERT_ID_TO_TYPE)
+ QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE)
+ QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_CONVERT_ID_TO_TYPE)
+ QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_CONVERT_ID_TO_TYPE)
+ default:
+ return nullptr;
+ }
+ }
+
+ bool convert(const void *from, int fromTypeId, void *to, int toTypeId) const override
+ {
+ Q_ASSERT(fromTypeId != toTypeId);
+
+ // canConvert calls with two nullptr
+ bool onlyCheck = (from == nullptr && to == nullptr);
+
+ // other callers must provide two valid pointers
+ Q_ASSERT(onlyCheck || (bool(from) && bool(to)));
+
+ using Char = char;
+ using SChar = signed char;
+ using UChar = unsigned char;
+ using Short = short;
+ using UShort = unsigned short;
+ using Int = int;
+ using UInt = unsigned int;
+ using Long = long;
+ using LongLong = qlonglong;
+ using ULong = unsigned long;
+ using ULongLong = qulonglong;
+ using Float = float;
+ 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;)
+#define QMETATYPE_CONVERTER_ASSIGN_NUMBER(To, From) \
+ QMETATYPE_CONVERTER(To, From, result = To::number(source); return true;)
+#ifndef QT_BOOTSTRAPPED
+#define CONVERT_CBOR_AND_JSON(To) \
+ QMETATYPE_CONVERTER(To, QCborValue, \
+ if constexpr(std::is_same_v<To, Bool>) { \
+ if (!source.isBool()) \
+ return false; \
+ result = source.toBool(); \
+ } else { \
+ if (!source.isInteger() && !source.isDouble()) \
+ return false; \
+ if constexpr(std::is_integral_v<To>) \
+ result = source.toInteger(); \
+ else \
+ result = source.toDouble(); \
+ } \
+ return true; \
+ ); \
+ QMETATYPE_CONVERTER(To, QJsonValue, \
+ if constexpr(std::is_same_v<To, Bool>) { \
+ if (!source.isBool()) \
+ return false; \
+ result = source.toBool(); \
+ } else { \
+ if (!source.isDouble()) \
+ return false; \
+ if constexpr(std::is_integral_v<To>) \
+ result = source.toInteger(); \
+ else \
+ result = source.toDouble(); \
+ } \
+ return true; \
+ )
+#else
+#define CONVERT_CBOR_AND_JSON(To)
+#endif
+
+#define INTEGRAL_CONVERTER(To) \
+ QMETATYPE_CONVERTER_ASSIGN(To, Bool); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Char); \
+ QMETATYPE_CONVERTER_ASSIGN(To, UChar); \
+ QMETATYPE_CONVERTER_ASSIGN(To, SChar); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Short); \
+ QMETATYPE_CONVERTER_ASSIGN(To, UShort); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Int); \
+ QMETATYPE_CONVERTER_ASSIGN(To, UInt); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Long); \
+ QMETATYPE_CONVERTER_ASSIGN(To, ULong); \
+ QMETATYPE_CONVERTER_ASSIGN(To, LongLong); \
+ QMETATYPE_CONVERTER_ASSIGN(To, ULongLong); \
+ QMETATYPE_CONVERTER(To, Float, result = qRound64(source); return true;); \
+ QMETATYPE_CONVERTER(To, Double, result = qRound64(source); return true;); \
+ QMETATYPE_CONVERTER(To, QChar, result = source.unicode(); return true;); \
+ QMETATYPE_CONVERTER(To, QString, \
+ bool ok = false; \
+ if constexpr(std::is_same_v<To, bool>) \
+ result = (ok = true, convertToBool(source)); \
+ else if constexpr(std::is_signed_v<To>) \
+ result = To(source.toLongLong(&ok)); \
+ else \
+ result = To(source.toULongLong(&ok)); \
+ return ok; \
+ ); \
+ QMETATYPE_CONVERTER(To, QByteArray, \
+ bool ok = false; \
+ if constexpr(std::is_same_v<To, bool>) \
+ result = (ok = true, convertToBool(source)); \
+ else if constexpr(std::is_signed_v<To>) \
+ result = To(source.toLongLong(&ok)); \
+ else \
+ result = To(source.toULongLong(&ok)); \
+ return ok; \
+ ); \
+ CONVERT_CBOR_AND_JSON(To)
+
+#define FLOAT_CONVERTER(To) \
+ QMETATYPE_CONVERTER_ASSIGN(To, Bool); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Char); \
+ QMETATYPE_CONVERTER_ASSIGN(To, UChar); \
+ QMETATYPE_CONVERTER_ASSIGN(To, SChar); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Short); \
+ QMETATYPE_CONVERTER_ASSIGN(To, UShort); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Int); \
+ QMETATYPE_CONVERTER_ASSIGN(To, UInt); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Long); \
+ QMETATYPE_CONVERTER_ASSIGN(To, ULong); \
+ QMETATYPE_CONVERTER_ASSIGN(To, LongLong); \
+ QMETATYPE_CONVERTER_ASSIGN(To, ULongLong); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Float); \
+ QMETATYPE_CONVERTER_ASSIGN(To, Double); \
+ QMETATYPE_CONVERTER(To, QString, \
+ bool ok = false; \
+ result = source.toDouble(&ok); \
+ return ok; \
+ ); \
+ QMETATYPE_CONVERTER(To, QByteArray, \
+ bool ok = false; \
+ result = source.toDouble(&ok); \
+ return ok; \
+ ); \
+ CONVERT_CBOR_AND_JSON(To)
+
+ switch (makePair(toTypeId, fromTypeId)) {
+
+ // integral conversions
+ INTEGRAL_CONVERTER(Bool);
+ INTEGRAL_CONVERTER(Char);
+ INTEGRAL_CONVERTER(UChar);
+ INTEGRAL_CONVERTER(SChar);
+ INTEGRAL_CONVERTER(Short);
+ INTEGRAL_CONVERTER(UShort);
+ INTEGRAL_CONVERTER(Int);
+ INTEGRAL_CONVERTER(UInt);
+ INTEGRAL_CONVERTER(Long);
+ INTEGRAL_CONVERTER(ULong);
+ INTEGRAL_CONVERTER(LongLong);
+ INTEGRAL_CONVERTER(ULongLong);
+ FLOAT_CONVERTER(Float);
+ FLOAT_CONVERTER(Double);
+
+#ifndef QT_BOOTSTRAPPED
+ QMETATYPE_CONVERTER_ASSIGN(QUrl, QString);
+ QMETATYPE_CONVERTER(QUrl, QCborValue,
+ if (source.isUrl()) {
+ result = source.toUrl();
+ return true;
+ }
+ return false;
+ );
+#endif
+#if QT_CONFIG(itemmodel)
+ QMETATYPE_CONVERTER_ASSIGN(QModelIndex, QPersistentModelIndex);
+ QMETATYPE_CONVERTER_ASSIGN(QPersistentModelIndex, QModelIndex);
+#endif // QT_CONFIG(itemmodel)
+
+ // QChar methods
+#define QMETATYPE_CONVERTER_ASSIGN_QCHAR(From) \
+ QMETATYPE_CONVERTER(QChar, From, result = QChar::fromUcs2(source); return true;)
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(Char);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(SChar);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(Short);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(Long);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(Int);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(LongLong);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(Float);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(UChar);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(UShort);
+ 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);
+ QMETATYPE_CONVERTER(QString, Bool,
+ result = source ? QStringLiteral("true") : QStringLiteral("false");
+ return true;
+ );
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QString, Short);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QString, Long);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QString, Int);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QString, LongLong);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QString, UShort);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QString, ULong);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QString, UInt);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QString, ULongLong);
+ QMETATYPE_CONVERTER(QString, Float,
+ result = QString::number(source, 'g', QLocale::FloatingPointShortest);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QString, Double,
+ result = QString::number(source, 'g', QLocale::FloatingPointShortest);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QString, Char,
+ result = QString::fromLatin1(&source, 1);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QString, SChar,
+ char s = source;
+ result = QString::fromLatin1(&s, 1);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QString, UChar,
+ char s = source;
+ 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;);
+ QMETATYPE_CONVERTER(QString, QDateTime, result = source.toString(Qt::ISODateWithMs); return true;);
+#endif
+ QMETATYPE_CONVERTER(QString, QByteArray, result = QString::fromUtf8(source); return true;);
+ QMETATYPE_CONVERTER(QString, QStringList,
+ return (source.size() == 1) ? (result = source.at(0), true) : false;
+ );
+#ifndef QT_BOOTSTRAPPED
+ QMETATYPE_CONVERTER(QString, QUrl, result = source.toString(); return true;);
+ QMETATYPE_CONVERTER(QString, QJsonValue,
+ if (source.isString() || source.isNull()) {
+ result = source.toString();
+ return true;
+ }
+ return false;
+ );
+#endif
+ QMETATYPE_CONVERTER(QString, Nullptr, Q_UNUSED(source); result = QString(); return true;);
+
+ // QByteArray
+ QMETATYPE_CONVERTER(QByteArray, QString, result = source.toUtf8(); return true;);
+ QMETATYPE_CONVERTER(QByteArray, Bool,
+ result = source ? "true" : "false";
+ return true;
+ );
+ QMETATYPE_CONVERTER(QByteArray, Char, result = QByteArray(source, 1); return true;);
+ QMETATYPE_CONVERTER(QByteArray, SChar, result = QByteArray(source, 1); return true;);
+ QMETATYPE_CONVERTER(QByteArray, UChar, result = QByteArray(source, 1); return true;);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QByteArray, Short);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QByteArray, Long);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QByteArray, Int);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QByteArray, LongLong);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QByteArray, UShort);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QByteArray, ULong);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QByteArray, UInt);
+ QMETATYPE_CONVERTER_ASSIGN_NUMBER(QByteArray, ULongLong);
+ QMETATYPE_CONVERTER(QByteArray, Float,
+ result = QByteArray::number(source, 'g', QLocale::FloatingPointShortest);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QByteArray, Double,
+ result = QByteArray::number(source, 'g', QLocale::FloatingPointShortest);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QByteArray, Nullptr, Q_UNUSED(source); result = QByteArray(); return true;);
+
+ QMETATYPE_CONVERTER(QString, QUuid, result = source.toString(); return true;);
+ QMETATYPE_CONVERTER(QUuid, QString, result = QUuid(source); return true;);
+ QMETATYPE_CONVERTER(QByteArray, QUuid, result = source.toByteArray(); return true;);
+ QMETATYPE_CONVERTER(QUuid, QByteArray, result = QUuid(source); return true;);
+
+#ifndef QT_NO_GEOM_VARIANT
+ QMETATYPE_CONVERTER(QSize, QSizeF, result = source.toSize(); return true;);
+ QMETATYPE_CONVERTER_ASSIGN(QSizeF, QSize);
+ QMETATYPE_CONVERTER(QLine, QLineF, result = source.toLine(); return true;);
+ QMETATYPE_CONVERTER_ASSIGN(QLineF, QLine);
+ QMETATYPE_CONVERTER(QRect, QRectF, result = source.toRect(); return true;);
+ QMETATYPE_CONVERTER_ASSIGN(QRectF, QRect);
+ QMETATYPE_CONVERTER(QPoint, QPointF, result = source.toPoint(); return true;);
+ QMETATYPE_CONVERTER_ASSIGN(QPointF, QPoint);
+#endif
+
+ QMETATYPE_CONVERTER(QStringList, QString, result = QStringList() << source; return true;);
+
+#ifndef QT_NO_VARIANT
+ QMETATYPE_CONVERTER(QByteArrayList, QVariantList,
+ result.reserve(source.size());
+ for (const auto &v: source)
+ result.append(v.toByteArray());
+ return true;
+ );
+ QMETATYPE_CONVERTER(QVariantList, QByteArrayList,
+ result.reserve(source.size());
+ for (const auto &v: source)
+ result.append(QVariant(v));
+ return true;
+ );
+
+ QMETATYPE_CONVERTER(QStringList, QVariantList,
+ result.reserve(source.size());
+ for (const auto &v: source)
+ result.append(v.toString());
+ return true;
+ );
+ QMETATYPE_CONVERTER(QVariantList, QStringList,
+ result.reserve(source.size());
+ for (const auto &v: source)
+ result.append(QVariant(v));
+ return true;
+ );
+
+ QMETATYPE_CONVERTER(QVariantHash, QVariantMap,
+ for (auto it = source.begin(); it != source.end(); ++it)
+ result.insert(it.key(), it.value());
+ return true;
+ );
+ QMETATYPE_CONVERTER(QVariantMap, QVariantHash,
+ for (auto it = source.begin(); it != source.end(); ++it)
+ result.insert(it.key(), it.value());
+ return true;
+ );
+#endif // !QT_NO_VARIANT
+#ifndef QT_BOOTSTRAPPED
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, QString);
+ QMETATYPE_CONVERTER(QString, QCborValue,
+ if (source.isContainer() || source.isTag())
+ return false;
+ result = source.toVariant().toString();
+ return true;
+ );
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, QByteArray);
+ QMETATYPE_CONVERTER(QByteArray, QCborValue,
+ if (source.isByteArray()) {
+ result = source.toByteArray();
+ return true;
+ }
+ return false;
+ );
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, QUuid);
+ QMETATYPE_CONVERTER(QUuid, QCborValue,
+ if (!source.isUuid())
+ return false;
+ result = source.toUuid();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborValue, QVariantList, result = QCborArray::fromVariantList(source); return true;);
+ QMETATYPE_CONVERTER(QVariantList, QCborValue,
+ if (!source.isArray())
+ return false;
+ result = source.toArray().toVariantList();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborValue, QVariantMap, result = QCborMap::fromVariantMap(source); return true;);
+ QMETATYPE_CONVERTER(QVariantMap, QCborValue,
+ if (!source.isMap())
+ return false;
+ result = source.toMap().toVariantMap();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborValue, QVariantHash, result = QCborMap::fromVariantHash(source); return true;);
+ QMETATYPE_CONVERTER(QVariantHash, QCborValue,
+ if (!source.isMap())
+ return false;
+ result = source.toMap().toVariantHash();
+ return true;
+ );
+#if QT_CONFIG(regularexpression)
+ QMETATYPE_CONVERTER(QCborValue, QRegularExpression, result = QCborValue(source); return true;);
+ QMETATYPE_CONVERTER(QRegularExpression, QCborValue,
+ if (!source.isRegularExpression())
+ return false;
+ result = source.toRegularExpression();
+ return true;
+ );
+#endif
+
+ QMETATYPE_CONVERTER(QCborValue, Nullptr,
+ Q_UNUSED(source);
+ result = QCborValue(QCborValue::Null);
+ return true;
+ );
+ QMETATYPE_CONVERTER(Nullptr, QCborValue,
+ result = nullptr;
+ return source.isNull();
+ );
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, Bool);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, Int);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, UInt);
+ QMETATYPE_CONVERTER(QCborValue, ULong, result = qlonglong(source); return true;);
+ QMETATYPE_CONVERTER(QCborValue, Long, result = qlonglong(source); return true;);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, LongLong);
+ QMETATYPE_CONVERTER(QCborValue, ULongLong, result = qlonglong(source); return true;);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, UShort);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, UChar);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, Char);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, SChar);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, Short);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, Double);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, Float);
+ QMETATYPE_CONVERTER(QCborValue, QStringList,
+ result = QCborArray::fromStringList(source);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborValue, QDate,
+ result = QCborValue(source.startOfDay());
+ return true;
+ );
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, QUrl);
+ QMETATYPE_CONVERTER(QCborValue, QJsonValue,
+ result = QCborValue::fromJsonValue(source);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborValue, QJsonObject,
+ result = QCborMap::fromJsonObject(source);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborValue, QJsonArray,
+ result = QCborArray::fromJsonArray(source);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborValue, QJsonDocument,
+ QJsonDocument doc = source;
+ if (doc.isArray())
+ result = QCborArray::fromJsonArray(doc.array());
+ else
+ result = QCborMap::fromJsonObject(doc.object());
+ return true;
+ );
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, QCborMap);
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, QCborArray);
+
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, QDateTime);
+ QMETATYPE_CONVERTER(QDateTime, QCborValue,
+ if (source.isDateTime()) {
+ result = source.toDateTime();
+ return true;
+ }
+ return false;
+ );
+
+ QMETATYPE_CONVERTER_ASSIGN(QCborValue, QCborSimpleType);
+ QMETATYPE_CONVERTER(QCborSimpleType, QCborValue,
+ if (source.isSimpleType()) {
+ result = source.toSimpleType();
+ return true;
+ }
+ return false;
+ );
+
+ QMETATYPE_CONVERTER(QCborArray, QVariantList, result = QCborArray::fromVariantList(source); return true;);
+ QMETATYPE_CONVERTER(QVariantList, QCborArray, result = source.toVariantList(); return true;);
+ QMETATYPE_CONVERTER(QCborArray, QStringList, result = QCborArray::fromStringList(source); return true;);
+ QMETATYPE_CONVERTER(QCborMap, QVariantMap, result = QCborMap::fromVariantMap(source); return true;);
+ QMETATYPE_CONVERTER(QVariantMap, QCborMap, result = source.toVariantMap(); return true;);
+ QMETATYPE_CONVERTER(QCborMap, QVariantHash, result = QCborMap::fromVariantHash(source); return true;);
+ QMETATYPE_CONVERTER(QVariantHash, QCborMap, result = source.toVariantHash(); return true;);
+
+ QMETATYPE_CONVERTER(QCborArray, QCborValue,
+ if (!source.isArray())
+ return false;
+ result = source.toArray();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborArray, QJsonDocument,
+ if (!source.isArray())
+ return false;
+ result = QCborArray::fromJsonArray(source.array());
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborArray, QJsonValue,
+ if (!source.isArray())
+ return false;
+ result = QCborArray::fromJsonArray(source.toArray());
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborArray, QJsonArray,
+ result = QCborArray::fromJsonArray(source);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborMap, QCborValue,
+ if (!source.isMap())
+ return false;
+ result = source.toMap();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborMap, QJsonDocument,
+ if (source.isArray())
+ return false;
+ result = QCborMap::fromJsonObject(source.object());
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborMap, QJsonValue,
+ if (!source.isObject())
+ return false;
+ result = QCborMap::fromJsonObject(source.toObject());
+ return true;
+ );
+ QMETATYPE_CONVERTER(QCborMap, QJsonObject,
+ result = QCborMap::fromJsonObject(source);
+ return true;
+ );
+
+
+ QMETATYPE_CONVERTER(QVariantList, QJsonValue,
+ if (!source.isArray())
+ return false;
+ result = source.toArray().toVariantList();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QVariantList, QJsonArray, result = source.toVariantList(); return true;);
+ QMETATYPE_CONVERTER(QVariantMap, QJsonValue,
+ if (!source.isObject())
+ return false;
+ result = source.toObject().toVariantMap();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QVariantMap, QJsonObject, result = source.toVariantMap(); return true;);
+ QMETATYPE_CONVERTER(QVariantHash, QJsonValue,
+ if (!source.isObject())
+ return false;
+ result = source.toObject().toVariantHash();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QVariantHash, QJsonObject, result = source.toVariantHash(); return true;);
+
+
+ QMETATYPE_CONVERTER(QJsonArray, QStringList, result = QJsonArray::fromStringList(source); return true;);
+ QMETATYPE_CONVERTER(QJsonArray, QVariantList, result = QJsonArray::fromVariantList(source); return true;);
+ QMETATYPE_CONVERTER(QJsonArray, QJsonValue,
+ if (!source.isArray())
+ return false;
+ result = source.toArray();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonArray, QJsonDocument,
+ if (!source.isArray())
+ return false;
+ result = source.array();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonArray, QCborValue,
+ if (!source.isArray())
+ return false;
+ result = source.toArray().toJsonArray();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonArray, QCborArray, result = source.toJsonArray(); return true;);
+ QMETATYPE_CONVERTER(QJsonObject, QVariantMap, result = QJsonObject::fromVariantMap(source); return true;);
+ QMETATYPE_CONVERTER(QJsonObject, QVariantHash, result = QJsonObject::fromVariantHash(source); return true;);
+ QMETATYPE_CONVERTER(QJsonObject, QJsonValue,
+ if (!source.isObject())
+ return false;
+ result = source.toObject();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonObject, QJsonDocument,
+ if (source.isArray())
+ return false;
+ result = source.object();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonObject, QCborValue,
+ if (!source.isMap())
+ return false;
+ result = source.toMap().toJsonObject();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonObject, QCborMap, result = source.toJsonObject(); return true; );
+
+ QMETATYPE_CONVERTER(QJsonValue, Nullptr,
+ Q_UNUSED(source);
+ result = QJsonValue(QJsonValue::Null);
+ return true;
+ );
+ QMETATYPE_CONVERTER(Nullptr, QJsonValue,
+ result = nullptr;
+ return source.isNull();
+ );
+ QMETATYPE_CONVERTER(QJsonValue, Bool,
+ result = QJsonValue(source);
+ return true;);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, Int);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, UInt);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, Double);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, Float);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, ULong);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, Long);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, LongLong);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, ULongLong);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, UShort);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, UChar);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, Char);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, SChar);
+ QMETATYPE_CONVERTER_ASSIGN_DOUBLE(QJsonValue, Short);
+ QMETATYPE_CONVERTER_ASSIGN(QJsonValue, QString);
+ QMETATYPE_CONVERTER(QJsonValue, QStringList,
+ result = QJsonValue(QJsonArray::fromStringList(source));
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QVariantList,
+ result = QJsonValue(QJsonArray::fromVariantList(source));
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QVariantMap,
+ result = QJsonValue(QJsonObject::fromVariantMap(source));
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QVariantHash,
+ result = QJsonValue(QJsonObject::fromVariantHash(source));
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QJsonObject,
+ result = source;
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QJsonArray,
+ result = source;
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QJsonDocument,
+ QJsonDocument doc = source;
+ result = doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object());
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QCborValue,
+ result = source.toJsonValue();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QCborMap,
+ result = source.toJsonObject();
+ return true;
+ );
+ QMETATYPE_CONVERTER(QJsonValue, QCborArray,
+ result = source.toJsonArray();
+ return true;
+ );
+
+#endif
+
+ QMETATYPE_CONVERTER(QDate, QDateTime, result = source.date(); return true;);
+ QMETATYPE_CONVERTER(QTime, QDateTime, result = source.time(); return true;);
+ QMETATYPE_CONVERTER(QDateTime, QDate, result = source.startOfDay(); return true;);
+#if QT_CONFIG(datestring)
+ QMETATYPE_CONVERTER(QDate, QString,
+ result = QDate::fromString(source, Qt::ISODate);
+ return result.isValid();
+ );
+ QMETATYPE_CONVERTER(QTime, QString,
+ result = QTime::fromString(source, Qt::ISODate);
+ return result.isValid();
+ );
+ QMETATYPE_CONVERTER(QDateTime, QString,
+ result = QDateTime::fromString(source, Qt::ISODate);
+ return result.isValid();
+ );
+#endif
+
+ }
+ return false;
+ }
+} metatypeHelper = {};
+
+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 &metatypeHelper;
if (type >= QMetaType::FirstGuiType && type <= QMetaType::LastGuiType)
return qMetaTypeGuiHelper;
else if (type >= QMetaType::FirstWidgetsType && type <= QMetaType::LastWidgetsType)
@@ -873,20 +1688,22 @@ public:
return map.contains(k);
}
- bool insertIfNotContains(Key k, const T *f)
+ bool insertIfNotContains(Key k, const T &f)
{
const QWriteLocker locker(&lock);
- const T* &fun = map[k];
- if (fun)
+ const qsizetype oldSize = map.size();
+ auto &e = map[k];
+ if (map.size() == oldSize) // already present
return false;
- fun = f;
+ e = f;
return true;
}
const T *function(Key k) const
{
const QReadLocker locker(&lock);
- return map.value(k, nullptr);
+ auto it = map.find(k);
+ return it == map.end() ? nullptr : std::addressof(*it);
}
void remove(int from, int to)
@@ -897,56 +1714,61 @@ public:
}
private:
mutable QReadWriteLock lock;
- QHash<Key, const T *> map;
+ QHash<Key, T> map;
};
-typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractConverterFunction,QPair<int,int> >
-QMetaTypeConverterRegistry;
-typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int>
-QMetaTypeDebugStreamRegistry;
+using QMetaTypeConverterRegistry
+ = QMetaTypeFunctionRegistry<QMetaType::ConverterFunction, std::pair<int,int>>;
Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry)
-Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
+
+using QMetaTypeMutableViewRegistry
+ = 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.
-*/
-#ifndef QT_NO_DEBUG_STREAM
-/*!
- \fn bool QMetaType::registerDebugStreamOperator()
- Registers the debug stream operator for the user-registered type T. This requires T to have
- an operator<<(QDebug dbg, T).
- 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
*/
-#endif
/*!
Registers function \a f as converter function from type id \a from to \a to.
@@ -955,228 +1777,917 @@ Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
\since 5.2
\internal
*/
-bool QMetaType::registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to)
+bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType from, QMetaType to)
{
- if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from, to), f)) {
+ if (!customTypesConversionRegistry()->insertIfNotContains({from.id(), to.id()}, f)) {
qWarning("Type conversion already registered from type %s to type %s",
- QMetaType::typeName(from), QMetaType::typeName(to));
+ from.name(), to.name());
return false;
}
return true;
}
/*!
+ \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
+ type \c {From} in the meta type system. Returns \c true if the registration succeeded, otherwise
+ \c false.
+*/
+
+/*!
+ \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
+ in the meta type system. Returns \c true if the registration succeeded, otherwise \c false.
+*/
+
+/*!
+ Registers function \a f as mutable view of type id \a to on type id \a from.
+ Returns \c true if the registration succeeded, otherwise \c false.
+ \since 6.0
+ \internal
+*/
+bool QMetaType::registerMutableViewFunction(const MutableViewFunction &f, QMetaType from, QMetaType to)
+{
+ 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;
+ }
+ return true;
+}
+
+/*!
+ \internal
+ */
+void QMetaType::unregisterMutableViewFunction(QMetaType from, QMetaType to)
+{
+ if (customTypesMutableViewRegistry.isDestroyed())
+ return;
+ customTypesMutableViewRegistry()->remove(from.id(), to.id());
+}
+
+/*!
\internal
Invoked automatically when a converter function object is destroyed.
*/
-void QMetaType::unregisterConverterFunction(int from, int to)
+void QMetaType::unregisterConverterFunction(QMetaType from, QMetaType to)
{
if (customTypesConversionRegistry.isDestroyed())
return;
- customTypesConversionRegistry()->remove(from, to);
+ customTypesConversionRegistry()->remove(from.id(), to.id());
}
#ifndef QT_NO_DEBUG_STREAM
-bool QMetaType::registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f,
- int type)
+
+/*!
+ \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)
{
- if (!customTypesDebugStreamRegistry()->insertIfNotContains(type, f)) {
- qWarning("Debug stream operator already registered for type %s", QMetaType::typeName(type));
- return false;
+ 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
+*/
+bool QMetaType::debugStream(QDebug& dbg, const void *rhs)
+{
+ if (d_ptr && d_ptr->flags & QMetaType::IsPointer) {
+ dbg << *reinterpret_cast<const void * const *>(rhs);
+ return true;
}
- return true;
+ if (d_ptr && d_ptr->debugStream) {
+ d_ptr->debugStream(d_ptr, dbg, rhs);
+ return true;
+ }
+ return false;
}
/*!
- \fn bool QMetaType::hasRegisteredDebugStreamOperator()
- Returns \c true, if the meta type system has a registered debug stream operator for type T.
+ \fn bool QMetaType::debugStream(QDebug& dbg, const void *rhs, int typeId)
+ \overload
+ \deprecated
+*/
+
+/*!
+ \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.
*/
/*!
+ \fn bool QMetaType::hasRegisteredDebugStreamOperator(int typeId)
+ \deprecated Use QMetaType::hasRegisteredDebugStreamOperator() instead.
+
Returns \c true, if the meta type system has a registered debug stream operator for type
id \a typeId.
\since 5.2
*/
-bool QMetaType::hasRegisteredDebugStreamOperator(int typeId)
+
+/*!
+ \since 6.0
+
+ Returns \c true, if the meta type system has a registered debug stream operator for this
+ meta type.
+*/
+bool QMetaType::hasRegisteredDebugStreamOperator() const
{
- return customTypesDebugStreamRegistry()->contains(typeId);
+ return d_ptr && d_ptr->debugStream != nullptr;
}
#endif
+#ifndef QT_NO_QOBJECT
/*!
- 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.
- \since 5.2
+ \internal
+ returns a QMetaEnum for a given meta tape type id if possible
*/
-bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId)
+static QMetaEnum metaEnumFromType(QMetaType t)
{
- const QtPrivate::AbstractConverterFunction * const f =
- customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId));
- return f && f->convert(f, from, to);
+ if (t.flags() & QMetaType::IsEnumeration) {
+ if (const QMetaObject *metaObject = t.metaObject()) {
+ 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();
}
+#endif
-/*!
- Streams the object at \a rhs of type \a typeId to the debug stream \a dbg. Returns \c true
- on success, otherwise false.
- \since 5.2
-*/
-bool QMetaType::debugStream(QDebug& dbg, const void *rhs, int typeId)
+static bool convertFromEnum(QMetaType fromType, const void *from, QMetaType toType, void *to)
+{
+ qlonglong ll;
+ if (fromType.flags() & QMetaType::IsUnsignedEnumeration) {
+ qulonglong ull;
+ switch (fromType.sizeOf()) {
+ case 1:
+ ull = *static_cast<const unsigned char *>(from);
+ break;
+ case 2:
+ ull = *static_cast<const unsigned short *>(from);
+ break;
+ case 4:
+ ull = *static_cast<const unsigned int *>(from);
+ break;
+ case 8:
+ ull = *static_cast<const quint64 *>(from);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ if (toType.id() == QMetaType::ULongLong) {
+ *static_cast<qulonglong *>(to) = ull;
+ return true;
+ }
+ if (toType.id() != QMetaType::QString && toType.id() != QMetaType::QByteArray)
+ return QMetaType::convert(QMetaType::fromType<qulonglong>(), &ull, toType, to);
+ ll = qlonglong(ull);
+ } else {
+ switch (fromType.sizeOf()) {
+ case 1:
+ ll = *static_cast<const signed char *>(from);
+ break;
+ case 2:
+ ll = *static_cast<const short *>(from);
+ break;
+ case 4:
+ ll = *static_cast<const int *>(from);
+ break;
+ case 8:
+ ll = *static_cast<const qint64 *>(from);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ if (toType.id() == QMetaType::LongLong) {
+ *static_cast<qlonglong *>(to) = ll;
+ return true;
+ }
+ if (toType.id() != QMetaType::QString && toType.id() != QMetaType::QByteArray)
+ return QMetaType::convert(QMetaType::fromType<qlonglong>(), &ll, toType, to);
+ }
+#ifndef QT_NO_QOBJECT
+ QMetaEnum en = metaEnumFromType(fromType);
+ if (en.isValid()) {
+ 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 = -1;
+ bool ok = false;
+#ifndef QT_NO_QOBJECT
+ if (fromTypeId == QMetaType::QString || fromTypeId == QMetaType::QByteArray) {
+ QMetaEnum en = metaEnumFromType(toType);
+ 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) {
+ if (fromTypeId == QMetaType::LongLong) {
+ value = *static_cast<const qlonglong *>(from);
+ ok = true;
+ } else {
+ ok = QMetaType::convert(fromType, from, QMetaType::fromType<qlonglong>(), &value);
+ }
+ }
+
+ if (!ok)
+ return false;
+
+ switch (toType.sizeOf()) {
+ case 1:
+ *static_cast<signed char *>(to) = value;
+ return true;
+ case 2:
+ *static_cast<qint16 *>(to) = value;
+ return true;
+ case 4:
+ *static_cast<qint32 *>(to) = value;
+ return true;
+ case 8:
+ *static_cast<qint64 *>(to) = value;
+ return true;
+ default:
+ Q_UNREACHABLE_RETURN(false);
+ }
+}
+
+#ifndef QT_BOOTSTRAPPED
+static bool convertIterableToVariantList(QMetaType fromType, const void *from, void *to)
+{
+ QSequentialIterable list;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<QSequentialIterable>(), &list))
+ return false;
+
+ QVariantList &l = *static_cast<QVariantList *>(to);
+ l.clear();
+ l.reserve(list.size());
+ auto end = list.end();
+ for (auto it = list.begin(); it != end; ++it)
+ l << *it;
+ return true;
+}
+
+static bool convertIterableToVariantMap(QMetaType fromType, const void *from, void *to)
{
- const QtPrivate::AbstractDebugStreamFunction * const f = customTypesDebugStreamRegistry()->function(typeId);
+ QAssociativeIterable map;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<QAssociativeIterable>(), &map))
+ return false;
+
+ QVariantMap &h = *static_cast<QVariantMap *>(to);
+ h.clear();
+ auto end = map.end();
+ for (auto it = map.begin(); it != end; ++it)
+ h.insert(it.key().toString(), it.value());
+ return true;
+}
+
+static bool convertIterableToVariantHash(QMetaType fromType, const void *from, void *to)
+{
+ QAssociativeIterable map;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<QAssociativeIterable>(), &map))
+ return false;
+
+ QVariantHash &h = *static_cast<QVariantHash *>(to);
+ h.clear();
+ h.reserve(map.size());
+ auto end = map.end();
+ for (auto it = map.begin(); it != end; ++it)
+ h.insert(it.key().toString(), it.value());
+ return true;
+}
+
+static bool convertIterableToVariantPair(QMetaType fromType, const void *from, void *to)
+{
+ const int targetId = qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
+ const auto f = customTypesConversionRegistry()->function({fromType.id(), targetId});
+
if (!f)
return false;
- f->stream(f, dbg, rhs);
+
+ QtMetaTypePrivate::QPairVariantInterfaceImpl pi;
+ (*f)(from, &pi);
+
+ QVariant v1(pi._metaType_first);
+ void *dataPtr;
+ if (pi._metaType_first == QMetaType::fromType<QVariant>())
+ dataPtr = &v1;
+ else
+ dataPtr = v1.data();
+ pi.first(dataPtr);
+
+ QVariant v2(pi._metaType_second);
+ if (pi._metaType_second == QMetaType::fromType<QVariant>())
+ dataPtr = &v2;
+ else
+ dataPtr = v2.data();
+ pi.second(dataPtr);
+
+ *static_cast<QVariantPair *>(to) = QVariantPair(v1, v2);
return true;
}
+static bool convertToSequentialIterable(QMetaType fromType, const void *from, void *to)
+{
+ using namespace QtMetaTypePrivate;
+ const int fromTypeId = fromType.id();
+
+ QSequentialIterable &i = *static_cast<QSequentialIterable *>(to);
+ switch (fromTypeId) {
+ case QMetaType::QVariantList:
+ i = QSequentialIterable(reinterpret_cast<const QVariantList *>(from));
+ return true;
+ case QMetaType::QStringList:
+ i = QSequentialIterable(reinterpret_cast<const QStringList *>(from));
+ return true;
+ case QMetaType::QByteArrayList:
+ i = QSequentialIterable(reinterpret_cast<const QByteArrayList *>(from));
+ return true;
+ case QMetaType::QString:
+ i = QSequentialIterable(reinterpret_cast<const QString *>(from));
+ return true;
+ case QMetaType::QByteArray:
+ i = QSequentialIterable(reinterpret_cast<const QByteArray *>(from));
+ return true;
+ default: {
+ QSequentialIterable impl;
+ if (QMetaType::convert(
+ fromType, from, QMetaType::fromType<QIterable<QMetaSequence>>(), &impl)) {
+ i = std::move(impl);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool canConvertToSequentialIterable(QMetaType fromType)
+{
+ switch (fromType.id()) {
+ case QMetaType::QVariantList:
+ case QMetaType::QStringList:
+ case QMetaType::QByteArrayList:
+ case QMetaType::QString:
+ case QMetaType::QByteArray:
+ return true;
+ default:
+ return QMetaType::canConvert(fromType, QMetaType::fromType<QIterable<QMetaSequence>>());
+ }
+}
+
+static bool canImplicitlyViewAsSequentialIterable(QMetaType fromType)
+{
+ switch (fromType.id()) {
+ case QMetaType::QVariantList:
+ case QMetaType::QStringList:
+ case QMetaType::QByteArrayList:
+ case QMetaType::QString:
+ case QMetaType::QByteArray:
+ return true;
+ default:
+ return QMetaType::canView(
+ fromType, QMetaType::fromType<QIterable<QMetaSequence>>());
+ }
+}
+
+static bool viewAsSequentialIterable(QMetaType fromType, void *from, void *to)
+{
+ using namespace QtMetaTypePrivate;
+ const int fromTypeId = fromType.id();
+
+ QSequentialIterable &i = *static_cast<QSequentialIterable *>(to);
+ switch (fromTypeId) {
+ case QMetaType::QVariantList:
+ i = QSequentialIterable(reinterpret_cast<QVariantList *>(from));
+ return true;
+ case QMetaType::QStringList:
+ i = QSequentialIterable(reinterpret_cast<QStringList *>(from));
+ return true;
+ case QMetaType::QByteArrayList:
+ i = QSequentialIterable(reinterpret_cast<QByteArrayList *>(from));
+ return true;
+ case QMetaType::QString:
+ i = QSequentialIterable(reinterpret_cast<QString *>(from));
+ return true;
+ case QMetaType::QByteArray:
+ i = QSequentialIterable(reinterpret_cast<QByteArray *>(from));
+ return true;
+ default: {
+ QIterable<QMetaSequence> j(QMetaSequence(), nullptr);
+ if (QMetaType::view(
+ fromType, from, QMetaType::fromType<QIterable<QMetaSequence>>(), &j)) {
+ i = std::move(j);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool convertToAssociativeIterable(QMetaType fromType, const void *from, void *to)
+{
+ using namespace QtMetaTypePrivate;
+
+ QAssociativeIterable &i = *static_cast<QAssociativeIterable *>(to);
+ if (fromType.id() == QMetaType::QVariantMap) {
+ i = QAssociativeIterable(reinterpret_cast<const QVariantMap *>(from));
+ return true;
+ }
+ if (fromType.id() == QMetaType::QVariantHash) {
+ i = QAssociativeIterable(reinterpret_cast<const QVariantHash *>(from));
+ return true;
+ }
+
+ QAssociativeIterable impl;
+ if (QMetaType::convert(
+ fromType, from, QMetaType::fromType<QIterable<QMetaAssociation>>(), &impl)) {
+ i = std::move(impl);
+ return true;
+ }
+
+ return false;
+}
+
+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) {
+ return f->inherits(t) || (t->inherits(f));
+ }
+ return false;
+}
+
+static bool canConvertToAssociativeIterable(QMetaType fromType)
+{
+ switch (fromType.id()) {
+ case QMetaType::QVariantMap:
+ case QMetaType::QVariantHash:
+ return true;
+ default:
+ return QMetaType::canConvert(fromType, QMetaType::fromType<QIterable<QMetaAssociation>>());
+ }
+}
+
+static bool canImplicitlyViewAsAssociativeIterable(QMetaType fromType)
+{
+ switch (fromType.id()) {
+ case QMetaType::QVariantMap:
+ case QMetaType::QVariantHash:
+ return true;
+ default:
+ return QMetaType::canView(
+ fromType, QMetaType::fromType<QIterable<QMetaAssociation>>());
+ }
+}
+
+static bool viewAsAssociativeIterable(QMetaType fromType, void *from, void *to)
+{
+ using namespace QtMetaTypePrivate;
+ int fromTypeId = fromType.id();
+
+ QAssociativeIterable &i = *static_cast<QAssociativeIterable *>(to);
+ if (fromTypeId == QMetaType::QVariantMap) {
+ i = QAssociativeIterable(reinterpret_cast<QVariantMap *>(from));
+ return true;
+ }
+ if (fromTypeId == QMetaType::QVariantHash) {
+ i = QAssociativeIterable(reinterpret_cast<QVariantHash *>(from));
+ return true;
+ }
+
+ QIterable<QMetaAssociation> j(QMetaAssociation(), nullptr);
+ if (QMetaType::view(
+ fromType, from, QMetaType::fromType<QIterable<QMetaAssociation>>(), &j)) {
+ i = std::move(j);
+ return true;
+ }
+
+ return false;
+}
+
+static bool convertMetaObject(QMetaType fromType, const void *from, QMetaType toType, void *to)
+{
+ // handle QObject conversion
+ if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) {
+ QObject *fromObject = *static_cast<QObject * const *>(from);
+ // use dynamic metatype of from if possible
+ if (fromObject && fromObject->metaObject()->inherits(toType.metaObject())) {
+ *static_cast<QObject **>(to) = toType.metaObject()->cast(fromObject);
+ return true;
+ } else if (!fromObject && fromType.metaObject()) {
+ // if fromObject is null, use static fromType to check if conversion works
+ *static_cast<void **>(to) = nullptr;
+ return fromType.metaObject()->inherits(toType.metaObject());
+ }
+ } 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 // !QT_BOOTSTRAPPED
+
/*!
- \fn bool QMetaType::hasRegisteredConverterFunction()
- Returns \c true, if the meta type system has a registered conversion from type From to type To.
+ \fn bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId)
+ \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.
+
+ Both \a from and \a to have to be valid pointers.
+
\since 5.2
- \overload
- */
+*/
/*!
- Returns \c true, if the meta type system has a registered conversion from meta type id \a fromTypeId
- to \a toTypeId
+ Converts the object at \a from from \a fromType to the preallocated space at \a to
+ typed \a toType. Returns \c true, if the conversion succeeded, otherwise false.
+
+ Both \a from and \a to have to be valid pointers.
+
\since 5.2
*/
-bool QMetaType::hasRegisteredConverterFunction(int fromTypeId, int toTypeId)
+bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType, void *to)
{
- return customTypesConversionRegistry()->contains(qMakePair(fromTypeId, toTypeId));
+ if (!fromType.isValid() || !toType.isValid())
+ return false;
+
+ if (fromType == toType) {
+ // just make a copy
+ fromType.destruct(to);
+ fromType.construct(to, from);
+ return true;
+ }
+
+ int fromTypeId = fromType.id();
+ int toTypeId = toType.id();
+
+ if (auto moduleHelper = qModuleHelperForType(qMax(fromTypeId, toTypeId))) {
+ if (moduleHelper->convert(from, fromTypeId, to, toTypeId))
+ return true;
+ }
+ const auto f = customTypesConversionRegistry()->function({fromTypeId, toTypeId});
+ if (f)
+ return (*f)(from, to);
+
+ if (fromType.flags() & QMetaType::IsEnumeration)
+ return convertFromEnum(fromType, from, toType, to);
+ if (toType.flags() & QMetaType::IsEnumeration)
+ return convertToEnum(fromType, from, toType, to);
+ if (toTypeId == Nullptr) {
+ *static_cast<std::nullptr_t *>(to) = nullptr;
+ if (fromType.flags() & QMetaType::IsPointer) {
+ if (*static_cast<const void * const *>(from) == nullptr)
+ return true;
+ }
+ }
+
+#ifndef QT_BOOTSTRAPPED
+# ifndef QT_NO_VARIANT
+ if (toTypeId == QVariantPair && convertIterableToVariantPair(fromType, from, to))
+ return true;
+
+ // handle iterables
+ if (toTypeId == QVariantList && convertIterableToVariantList(fromType, from, to))
+ return true;
+
+ if (toTypeId == QVariantMap && convertIterableToVariantMap(fromType, from, to))
+ return true;
+
+ if (toTypeId == QVariantHash && convertIterableToVariantHash(fromType, from, to))
+ return true;
+# endif
+
+ if (toTypeId == qMetaTypeId<QSequentialIterable>())
+ return convertToSequentialIterable(fromType, from, to);
+
+ if (toTypeId == qMetaTypeId<QAssociativeIterable>())
+ return convertToAssociativeIterable(fromType, from, to);
+
+ return convertMetaObject(fromType, from, toType, to);
+#else
+ return false;
+#endif
}
-#ifndef QT_NO_DATASTREAM
/*!
- \internal
+ Creates a mutable view on the object at \a from of \a fromType in the preallocated space at
+ \a to typed \a toType. Returns \c true if the conversion succeeded, otherwise false.
+ \since 6.0
*/
-void QMetaType::registerStreamOperators(const char *typeName, SaveOperator saveOp,
- LoadOperator loadOp)
+bool QMetaType::view(QMetaType fromType, void *from, QMetaType toType, void *to)
{
- registerStreamOperators(type(typeName), saveOp, loadOp);
+ if (!fromType.isValid() || !toType.isValid())
+ return false;
+
+ int fromTypeId = fromType.id();
+ int toTypeId = toType.id();
+
+ const auto f = customTypesMutableViewRegistry()->function({fromTypeId, toTypeId});
+ if (f)
+ return (*f)(from, to);
+
+#ifndef QT_BOOTSTRAPPED
+ if (toTypeId == qMetaTypeId<QSequentialIterable>())
+ return viewAsSequentialIterable(fromType, from, to);
+
+ if (toTypeId == qMetaTypeId<QAssociativeIterable>())
+ return viewAsAssociativeIterable(fromType, from, to);
+
+ return convertMetaObject(fromType, from, toType, to);
+#else
+ return false;
+#endif
}
/*!
- \internal
+ Returns \c true if QMetaType::view can create a mutable view of type \a toType
+ on type \a fromType.
+
+ Converting between pointers of types derived from QObject will return true for this
+ function if a qobject_cast from the type described by \a fromType to the type described
+ by \a toType would succeed.
+
+ You can create a mutable view of type QSequentialIterable on any container registered with
+ Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE().
+
+ Similarly you can create a mutable view of type QAssociativeIterable on any container
+ registered with Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE().
+
+ \sa convert(), QSequentialIterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(),
+ QAssociativeIterable, Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE()
*/
-void QMetaType::registerStreamOperators(int idx, SaveOperator saveOp,
- LoadOperator loadOp)
+bool QMetaType::canView(QMetaType fromType, QMetaType toType)
{
- if (idx < User)
- return; //builtin types should not be registered;
+ int fromTypeId = fromType.id();
+ int toTypeId = toType.id();
- if (auto reg = customTypeRegistry()) {
- QWriteLocker locker(&reg->lock);
- reg->dataStreamOp[idx] = { saveOp, loadOp };
- }
-}
-#endif // QT_NO_DATASTREAM
-
-// We don't officially support constexpr in MSVC 2015, but the limited support it
-// has is enough for the code below.
+ if (fromTypeId == UnknownType || toTypeId == UnknownType)
+ return false;
-#define STRINGIFY_TYPE_NAME(MetaTypeName, TypeId, RealName) \
- #RealName "\0"
-#define CALCULATE_TYPE_LEN(MetaTypeName, TypeId, RealName) \
- short(sizeof(#RealName)),
-#define MAP_TYPE_ID_TO_IDX(MetaTypeName, TypeId, RealName) \
- TypeId,
+ const auto f = customTypesMutableViewRegistry()->function({fromTypeId, toTypeId});
+ if (f)
+ return true;
-namespace {
-// All type names in one long string.
-constexpr char metaTypeStrings[] = QT_FOR_EACH_STATIC_TYPE(STRINGIFY_TYPE_NAME);
+#ifndef QT_BOOTSTRAPPED
+ if (toTypeId == qMetaTypeId<QSequentialIterable>())
+ return canImplicitlyViewAsSequentialIterable(fromType);
-// The sizes of the strings in the metaTypeStrings string (including terminating null)
-constexpr short metaTypeNameSizes[] = {
- QT_FOR_EACH_STATIC_TYPE(CALCULATE_TYPE_LEN)
-};
+ if (toTypeId == qMetaTypeId<QAssociativeIterable>())
+ return canImplicitlyViewAsAssociativeIterable(fromType);
-// The type IDs, in the order of the metaTypeStrings data
-constexpr short metaTypeIds[] = {
- QT_FOR_EACH_STATIC_TYPE(MAP_TYPE_ID_TO_IDX)
-};
+ if (canConvertMetaObject(fromType, toType))
+ return true;
+#endif
-constexpr int MetaTypeNameCount = sizeof(metaTypeNameSizes) / sizeof(metaTypeNameSizes[0]);
+ return false;
+}
-template <typename IntegerSequence> struct MetaTypeOffsets;
-template <int... TypeIds> struct MetaTypeOffsets<QtPrivate::IndexesList<TypeIds...>>
+/*!
+ Returns \c true if QMetaType::convert can convert from \a fromType to
+ \a toType.
+
+ The following conversions are supported by Qt:
+
+ \table
+ \header \li Type \li Automatically Cast To
+ \row \li \l QMetaType::Bool \li \l QMetaType::QChar, \l QMetaType::Double,
+ \l QMetaType::Int, \l QMetaType::LongLong, \l QMetaType::QString,
+ \l QMetaType::UInt, \l QMetaType::ULongLong
+ \row \li \l QMetaType::QByteArray \li \l QMetaType::Double,
+ \l QMetaType::Int, \l QMetaType::LongLong, \l QMetaType::QString,
+ \l QMetaType::UInt, \l QMetaType::ULongLong, \l QMetaType::QUuid
+ \row \li \l QMetaType::QChar \li \l QMetaType::Bool, \l QMetaType::Int,
+ \l QMetaType::UInt, \l QMetaType::LongLong, \l QMetaType::ULongLong
+ \row \li \l QMetaType::QColor \li \l QMetaType::QString
+ \row \li \l QMetaType::QDate \li \l QMetaType::QDateTime,
+ \l QMetaType::QString
+ \row \li \l QMetaType::QDateTime \li \l QMetaType::QDate,
+ \l QMetaType::QString, \l QMetaType::QTime
+ \row \li \l QMetaType::Double \li \l QMetaType::Bool, \l QMetaType::Int,
+ \l QMetaType::LongLong, \l QMetaType::QString, \l QMetaType::UInt,
+ \l QMetaType::ULongLong
+ \row \li \l QMetaType::QFont \li \l QMetaType::QString
+ \row \li \l QMetaType::Int \li \l QMetaType::Bool, \l QMetaType::QChar,
+ \l QMetaType::Double, \l QMetaType::LongLong, \l QMetaType::QString,
+ \l QMetaType::UInt, \l QMetaType::ULongLong
+ \row \li \l QMetaType::QKeySequence \li \l QMetaType::Int,
+ \l QMetaType::QString
+ \row \li \l QMetaType::QVariantList \li \l QMetaType::QStringList (if the
+ list's items can be converted to QStrings)
+ \row \li \l QMetaType::LongLong \li \l QMetaType::Bool,
+ \l QMetaType::QByteArray, \l QMetaType::QChar, \l QMetaType::Double,
+ \l QMetaType::Int, \l QMetaType::QString, \l QMetaType::UInt,
+ \l QMetaType::ULongLong
+ \row \li \l QMetaType::QPoint \li QMetaType::QPointF
+ \row \li \l QMetaType::QRect \li QMetaType::QRectF
+ \row \li \l QMetaType::QString \li \l QMetaType::Bool,
+ \l QMetaType::QByteArray, \l QMetaType::QChar, \l QMetaType::QColor,
+ \l QMetaType::QDate, \l QMetaType::QDateTime, \l QMetaType::Double,
+ \l QMetaType::QFont, \l QMetaType::Int, \l QMetaType::QKeySequence,
+ \l QMetaType::LongLong, \l QMetaType::QStringList, \l QMetaType::QTime,
+ \l QMetaType::UInt, \l QMetaType::ULongLong, \l QMetaType::QUuid
+ \row \li \l QMetaType::QStringList \li \l QMetaType::QVariantList,
+ \l QMetaType::QString (if the list contains exactly one item)
+ \row \li \l QMetaType::QTime \li \l QMetaType::QString
+ \row \li \l QMetaType::UInt \li \l QMetaType::Bool, \l QMetaType::QChar,
+ \l QMetaType::Double, \l QMetaType::Int, \l QMetaType::LongLong,
+ \l QMetaType::QString, \l QMetaType::ULongLong
+ \row \li \l QMetaType::ULongLong \li \l QMetaType::Bool,
+ \l QMetaType::QChar, \l QMetaType::Double, \l QMetaType::Int,
+ \l QMetaType::LongLong, \l QMetaType::QString, \l QMetaType::UInt
+ \row \li \l QMetaType::QUuid \li \l QMetaType::QByteArray, \l QMetaType::QString
+ \endtable
+
+ Casting between primitive type (int, float, bool etc.) is supported.
+
+ Converting between pointers of types derived from QObject will also return true for this
+ function if a qobject_cast from the type described by \a fromType to the type described
+ by \a toType would succeed.
+
+ A cast from a sequential container will also return true for this
+ function if the \a toType is QVariantList.
+
+ Similarly, a cast from an associative container will also return true for this
+ function the \a toType is QVariantHash or QVariantMap.
+
+ \sa convert(), QSequentialIterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(), QAssociativeIterable,
+ Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE()
+*/
+bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
{
- // This would have been a lot easier if the meta types that the macro
- // QT_FOR_EACH_STATIC_TYPE declared were in sorted, ascending order, but
- // they're not (i.e., the first one declared is QMetaType::Void == 43,
- // followed by QMetaType::Bool == 1)... As a consequence, we need to use
- // the C++11 constexpr function calculateOffsetForTypeId below in order to
- // create the offset array.
+ int fromTypeId = fromType.id();
+ int toTypeId = toType.id();
- static constexpr int findTypeId(int typeId, int i = 0)
- {
- return i >= MetaTypeNameCount ? -1 :
- metaTypeIds[i] == typeId ? i : findTypeId(typeId, i + 1);
- }
+ if (fromTypeId == UnknownType || toTypeId == UnknownType)
+ return false;
- static constexpr short calculateOffsetForIdx(int i)
- {
- return i < 0 ? -1 :
- i == 0 ? 0 : metaTypeNameSizes[i - 1] + calculateOffsetForIdx(i - 1);
+ if (fromTypeId == toTypeId)
+ return true;
+
+ if (auto moduleHelper = qModuleHelperForType(qMax(fromTypeId, toTypeId))) {
+ if (moduleHelper->convert(nullptr, fromTypeId, nullptr, toTypeId))
+ return true;
}
+ const ConverterFunction * const f =
+ customTypesConversionRegistry()->function(std::make_pair(fromTypeId, toTypeId));
+ if (f)
+ return true;
- static constexpr short calculateOffsetForTypeId(int typeId)
- {
- return calculateOffsetForIdx(findTypeId(typeId));
-#if 0
- // same as, but this is only valid in C++14:
- short offset = 0;
- for (int i = 0; i < MetaTypeNameCount; ++i) {
- if (metaTypeIds[i] == typeId)
- return offset;
- offset += metaTypeNameSizes[i];
- }
- return -1;
+#ifndef QT_BOOTSTRAPPED
+ if (toTypeId == qMetaTypeId<QSequentialIterable>())
+ return canConvertToSequentialIterable(fromType);
+
+ if (toTypeId == qMetaTypeId<QAssociativeIterable>())
+ return canConvertToAssociativeIterable(fromType);
#endif
+#ifndef QT_NO_VARIANT
+ if (toTypeId == QVariantList
+ && canConvert(fromType, QMetaType::fromType<QSequentialIterable>())) {
+ return true;
}
- short offsets[sizeof...(TypeIds)];
- constexpr MetaTypeOffsets() : offsets{calculateOffsetForTypeId(TypeIds)...} {}
+ if ((toTypeId == QVariantHash || toTypeId == QVariantMap)
+ && canConvert(fromType, QMetaType::fromType<QAssociativeIterable>())) {
+ return true;
+ }
- const char *operator[](int typeId) const noexcept
- {
- short o = offsets[typeId];
- return o < 0 ? nullptr : metaTypeStrings + o;
+ if (toTypeId == QVariantPair && hasRegisteredConverterFunction(
+ fromType, QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>()))
+ return true;
+#endif
+
+ if (fromType.flags() & IsEnumeration) {
+ if (toTypeId == QString || toTypeId == QByteArray)
+ return true;
+ return canConvert(QMetaType(LongLong), toType);
}
-};
-} // anonymous namespace
+ if (toType.flags() & IsEnumeration) {
+ if (fromTypeId == QString || fromTypeId == QByteArray)
+ return true;
+ return canConvert(fromType, QMetaType(LongLong));
+ }
+ if (toTypeId == Nullptr && fromType.flags() & IsPointer)
+ return true;
+#ifndef QT_BOOTSTRAPPED
+ if (canConvertMetaObject(fromType, toType))
+ return true;
+#endif
+
+ return false;
+}
+
+/*!
+ \fn bool QMetaType::compare(const void *lhs, const void *rhs, int typeId, int* result)
+ \deprecated Use the non-static compare method instead
+
+ Compares the objects at \a lhs and \a rhs. Both objects need to be of type \a typeId.
+ \a result is set to less than, equal to or greater than zero, if \a lhs is less than, equal to
+ or greater than \a rhs. Returns \c true, if the comparison succeeded, otherwise \c false.
+*/
-constexpr MetaTypeOffsets<QtPrivate::Indexes<QMetaType::HighestInternalId + 1>::Value> metaTypeNames {};
-#undef STRINGIFY_TYPE_NAME
-#undef CALCULATE_TYPE_LEN
-#undef MAP_TYPE_ID_TO_IDX
+/*!
+ \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
+ */
+
+/*!
+ Returns \c true, if the meta type system has a registered conversion from meta type id \a fromType
+ to \a toType
+ \since 5.2
+*/
+bool QMetaType::hasRegisteredConverterFunction(QMetaType fromType, QMetaType toType)
+{
+ return customTypesConversionRegistry()->contains({fromType.id(), toType.id()});
+}
/*!
+ \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
+*/
+
+/*!
+ Returns \c true, if the meta type system has a registered mutable view on meta type id
+ \a fromType of meta type id \a toType.
+ \since 5.2
+*/
+bool QMetaType::hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType)
+{
+ return customTypesMutableViewRegistry()->contains({fromType.id(), toType.id()});
+}
+
+/*!
+ \fn const char *QMetaType::typeName(int typeId)
+ \deprecated
+
Returns the type name associated with the given \a typeId, or a null
pointer if no matching type was found. The returned pointer must not be
deleted.
\sa type(), isRegistered(), Type, name()
*/
-const char *QMetaType::typeName(int typeId)
-{
- const uint type = typeId;
- if (Q_LIKELY(type <= QMetaType::HighestInternalId)) {
- return metaTypeNames[typeId];
- } else if (Q_UNLIKELY(type < QMetaType::User)) {
- return nullptr; // It can happen when someone cast int to QVariant::Type, we should not crash...
- }
-
- if (auto reg = customTypeRegistry()) {
- if (auto ti = reg->getCustomType(typeId))
- return ti->name;
- }
- return nullptr;
-}
/*!
+ \fn constexpr const char *QMetaType::name() const
\since 5.15
Returns the type name associated with this QMetaType, or a null
@@ -1185,10 +2696,6 @@ const char *QMetaType::typeName(int typeId)
\sa typeName()
*/
-QByteArray QMetaType::name() const
-{
- return d_ptr ? d_ptr->name : nullptr;
-}
/*
Similar to QMetaType::type(), but only looks in the static set of types.
@@ -1210,12 +2717,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;
@@ -1242,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.
@@ -1250,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>
@@ -1278,280 +2800,219 @@ static inline int qMetaTypeTypeImpl(const char *typeName, int length)
}
/*!
+ \fn int QMetaType::type(const char *typeName)
+ \deprecated
+
Returns a handle to the type called \a typeName, or QMetaType::UnknownType if there is
no such type.
\sa isRegistered(), typeName(), Type
*/
-int QMetaType::type(const char *typeName)
-{
- return qMetaTypeTypeImpl</*tryNormalizedType=*/true>(typeName, qstrlen(typeName));
-}
/*!
- \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
for type names in non-normalized form).
*/
-int qMetaTypeTypeInternal(const char *typeName)
+Q_CORE_EXPORT int qMetaTypeTypeInternal(const char *typeName)
{
- return qMetaTypeTypeImpl</*tryNormalizedType=*/false>(typeName, qstrlen(typeName));
+ return qMetaTypeTypeImpl</*tryNormalizedType=*/false>(typeName, int(qstrlen(typeName)));
}
/*!
+ \fn int QMetaType::type(const QT_PREPEND_NAMESPACE(QByteArray) &typeName)
+
\since 5.5
\overload
+ \deprecated
Returns a handle to the type called \a typeName, or 0 if there is
no such type.
\sa isRegistered(), typeName()
*/
-int QMetaType::type(const QT_PREPEND_NAMESPACE(QByteArray) &typeName)
-{
- return qMetaTypeTypeImpl</*tryNormalizedType=*/true>(typeName.constData(), typeName.size());
-}
#ifndef QT_NO_DATASTREAM
-namespace
-{
-
-template<typename T>
-class HasStreamOperator
-{
- struct Yes { char unused[1]; };
- struct No { char unused[2]; };
- static_assert(sizeof(Yes) != sizeof(No));
-
- template<class C> static decltype(std::declval<QDataStream&>().operator>>(std::declval<C&>()), Yes()) load(int);
- template<class C> static decltype(operator>>(std::declval<QDataStream&>(), std::declval<C&>()), Yes()) load(int);
- template<class C> static No load(...);
- template<class C> static decltype(operator<<(std::declval<QDataStream&>(), std::declval<const C&>()), Yes()) saveFunction(int);
- template<class C> static decltype(std::declval<QDataStream&>().operator<<(std::declval<const C&>()), Yes()) saveMethod(int);
- template<class C> static No saveMethod(...);
- template<class C> static No saveFunction(...);
- static constexpr bool LoadValue = QtMetaTypePrivate::TypeDefinition<T>::IsAvailable && (sizeof(load<T>(0)) == sizeof(Yes));
- static constexpr bool SaveValue = QtMetaTypePrivate::TypeDefinition<T>::IsAvailable &&
- ((sizeof(saveMethod<T>(0)) == sizeof(Yes)) || (sizeof(saveFunction<T>(0)) == sizeof(Yes)));
-public:
- static constexpr bool Value = LoadValue && SaveValue;
-};
-
-// Quick sanity checks
-static_assert(HasStreamOperator<NS(QJsonDocument)>::Value);
-static_assert(!HasStreamOperator<void*>::Value);
-static_assert(HasStreamOperator<qint8>::Value);
+/*!
+ Writes the object pointed to by \a data to the given \a stream.
+ Returns \c true if the object is saved successfully; otherwise
+ returns \c false.
-template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted && HasStreamOperator<T>::Value>
-struct FilteredOperatorSwitch
-{
- static bool load(QDataStream &stream, T *data, int)
- {
- stream >> *data;
- return true;
- }
- static bool save(QDataStream &stream, const T *data, int)
- {
- stream << *data;
- return true;
- }
-};
+ Normally, you should not need to call this function directly.
+ Instead, use QVariant's \c operator<<(), which relies on save()
+ to stream custom types.
-template<typename T>
-struct FilteredOperatorSwitch<T, /* IsAcceptedType = */ false>
+ \sa load()
+*/
+bool QMetaType::save(QDataStream &stream, const void *data) const
{
- static const QMetaTypeModuleHelper *getMetaTypeInterface()
- {
- if (QModulesPrivate::QTypeModuleInfo<T>::IsGui)
- return qMetaTypeGuiHelper;
- else if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget)
- return qMetaTypeWidgetsHelper;
- return nullptr;
- }
- static bool save(QDataStream &stream, const T *data, int type)
- {
- if (auto interface = getMetaTypeInterface()) {
- return interface->save(stream, type, data);
- }
+ if (!data || !isValid())
return false;
- }
- static bool load(QDataStream &stream, T *data, int type)
- {
- if (auto interface = getMetaTypeInterface()) {
- return interface->load(stream, type, data);
- }
- return false;
- }
-};
-class SaveOperatorSwitch
-{
-public:
- QDataStream &stream;
- int m_type;
-
- template<typename T>
- bool delegate(const T *data)
- {
- return FilteredOperatorSwitch<T>::save(stream, data, m_type);
- }
- bool delegate(const char *data)
- {
- // force a char to be signed
- stream << qint8(*data);
- return true;
- }
- bool delegate(const long *data)
- {
- stream << qlonglong(*data);
+ // keep compatibility for long/ulong
+ if (id() == QMetaType::Long) {
+ stream << qlonglong(*(long *)data);
return true;
- }
- bool delegate(const unsigned long *data)
- {
- stream << qulonglong(*data);
+ } else if (id() == QMetaType::ULong) {
+ stream << qlonglong(*(unsigned long *)data);
return true;
}
- bool delegate(const QMetaTypeSwitcher::NotBuiltinType *data)
- {
- auto ct = customTypeRegistry();
- if (!ct)
- return false;
- QMetaType::SaveOperator op = nullptr;
- {
- QReadLocker lock(&ct->lock);
- op = ct->dataStreamOp.value(m_type).saveOp;
- }
- if (!op)
- return false;
- op(stream, data);
- return true;
- }
- bool delegate(const void*) { return false; }
- bool delegate(const QMetaTypeSwitcher::UnknownType*) { return false; }
-};
-class LoadOperatorSwitch
-{
-public:
- QDataStream &stream;
- int m_type;
- template<typename T>
- bool delegate(const T *data)
- {
- return FilteredOperatorSwitch<T>::load(stream, const_cast<T*>(data), m_type);
- }
- bool delegate(const char *data)
- {
- // force a char to be signed
- qint8 c;
- stream >> c;
- *const_cast<char*>(data) = c;
- return true;
- }
- bool delegate(const long *data)
- {
- qlonglong l;
- stream >> l;
- *const_cast<long*>(data) = l;
- return true;
- }
- bool delegate(const unsigned long *data)
- {
- qlonglong l;
- stream >> l;
- *const_cast<unsigned long*>(data) = l;
- return true;
- }
- bool delegate(const QMetaTypeSwitcher::NotBuiltinType *data)
- {
- auto ct = customTypeRegistry();
- if (!ct)
- return false;
- QMetaType::LoadOperator op = nullptr;
- {
- QReadLocker lock(&ct->lock);
- op = ct->dataStreamOp.value(m_type).loadOp;
- }
- if (!op)
- return false;
- op(stream, const_cast<QMetaTypeSwitcher::NotBuiltinType *>(data));
- return true;
- }
- bool delegate(const void*) { return false; }
- bool delegate(const QMetaTypeSwitcher::UnknownType*) { return false; }
-};
-} // namespace
+ if (!d_ptr->dataStreamOut)
+ return false;
+
+ d_ptr->dataStreamOut(d_ptr, stream, data);
+ return true;
+}
/*!
- Writes the object pointed to by \a data with the ID \a type to
- the given \a stream. Returns \c true if the object is saved
- successfully; otherwise returns \c false.
+ \fn bool QMetaType::save(QDataStream &stream, int type, const void *data)
+ \overload
+ \deprecated
+*/
- The type must have been registered with qRegisterMetaType() and
- qRegisterMetaTypeStreamOperators() beforehand.
+/*!
+ Reads the object of this type from the given \a stream into \a data.
+ Returns \c true if the object is loaded successfully; otherwise
+ returns \c false.
Normally, you should not need to call this function directly.
- Instead, use QVariant's \c operator<<(), which relies on save()
+ Instead, use QVariant's \c operator>>(), which relies on load()
to stream custom types.
- \sa load(), qRegisterMetaTypeStreamOperators()
+ \sa save()
*/
-bool QMetaType::save(QDataStream &stream, int type, const void *data)
+bool QMetaType::load(QDataStream &stream, void *data) const
{
- if (!data)
+ if (!data || !isValid())
return false;
- SaveOperatorSwitch saveOp{stream, type};
- return QMetaTypeSwitcher::switcher<bool>(saveOp, type, data);
+
+ // keep compatibility for long/ulong
+ if (id() == QMetaType::Long) {
+ qlonglong ll;
+ stream >> ll;
+ *(long *)data = long(ll);
+ return true;
+ } else if (id() == QMetaType::ULong) {
+ qulonglong ull;
+ stream >> ull;
+ *(unsigned long *)data = (unsigned long)(ull);
+ return true;
+ }
+ if (!d_ptr->dataStreamIn)
+ return false;
+
+ d_ptr->dataStreamIn(d_ptr, stream, data);
+ return true;
}
/*!
- Reads the object of the specified \a type from the given \a
- stream into \a data. Returns \c true if the object is loaded
- successfully; otherwise returns \c false.
+ \since 6.1
- The type must have been registered with qRegisterMetaType() and
- qRegisterMetaTypeStreamOperators() beforehand.
+ Returns \c true, if the meta type system has registered data stream operators for this
+ meta type.
+*/
+bool QMetaType::hasRegisteredDataStreamOperators() const
+{
+ int type = id();
+ if (type == QMetaType::Long || type == QMetaType::ULong)
+ return true;
+ return d_ptr && d_ptr->dataStreamIn != nullptr && d_ptr->dataStreamOut != nullptr;
+}
- Normally, you should not need to call this function directly.
- Instead, use QVariant's \c operator>>(), which relies on load()
- to stream custom types.
+/*!
+ \since 6.6
- \sa save(), qRegisterMetaTypeStreamOperators()
-*/
-bool QMetaType::load(QDataStream &stream, int type, void *data)
+ 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 (!data)
- return false;
- LoadOperatorSwitch loadOp{stream, type};
- return QMetaTypeSwitcher::switcher<bool>(loadOp, type, data);
+ 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
+*/
#endif // QT_NO_DATASTREAM
/*!
+ Returns a QMetaType matching \a typeName. The returned object is
+ not valid if the typeName is not known to QMetaType
+ */
+QMetaType QMetaType::fromName(QByteArrayView typeName)
+{
+ return QMetaType(qMetaTypeTypeImpl</*tryNormalizedType=*/true>(typeName.data(), typeName.size()));
+}
+
+/*!
+ \fn void *QMetaType::create(int type, const void *copy)
+ \deprecated
+
Returns a copy of \a copy, assuming it is of type \a type. If \a
copy is zero, creates a default constructed instance.
\sa destroy(), isRegistered(), Type
*/
-void *QMetaType::create(int type, const void *copy)
-{
- return QMetaType(type).create(copy);
-}
/*!
+ \fn void QMetaType::destroy(int type, void *data)
+ \deprecated
Destroys the \a data, assuming it is of the \a type given.
\sa create(), isRegistered(), Type
*/
-void QMetaType::destroy(int type, void *data)
-{
- QMetaType(type).destroy(data);
-}
/*!
+ \fn void *QMetaType::construct(int type, void *where, const void *copy)
\since 5.0
+ \deprecated
Constructs a value of the given \a type in the existing memory
addressed by \a where, that is a copy of \a copy, and returns
@@ -1576,14 +3037,12 @@ void QMetaType::destroy(int type, void *data)
\sa destruct(), sizeOf()
*/
-void *QMetaType::construct(int type, void *where, const void *copy)
-{
- return QMetaType(type).construct(where, copy);
-}
/*!
+ \fn void QMetaType::destruct(int type, void *where)
\since 5.0
+ \deprecated
Destructs the value of the given \a type, located at \a where.
@@ -1592,13 +3051,11 @@ void *QMetaType::construct(int type, void *where, const void *copy)
\sa construct()
*/
-void QMetaType::destruct(int type, void *where)
-{
- return QMetaType(type).destruct(where);
-}
/*!
+ \fn int QMetaType::sizeOf(int type)
\since 5.0
+ \deprecated
Returns the size of the given \a type in bytes (i.e. sizeof(T),
where T is the actual type identified by the \a type argument).
@@ -1608,39 +3065,31 @@ void QMetaType::destruct(int type, void *where)
\sa construct(), QMetaType::alignOf()
*/
-int QMetaType::sizeOf(int type)
-{
- return QMetaType(type).sizeOf();
-}
/*!
+ \fn QMetaType::TypeFlags QMetaType::typeFlags(int type)
\since 5.0
+ \deprecated
Returns flags of the given \a type.
\sa QMetaType::TypeFlags
*/
-QMetaType::TypeFlags QMetaType::typeFlags(int type)
-{
- return QMetaType(type).flags();
-}
-
/*!
+ \fn const QMetaObject *QMetaType::metaObjectForType(int type)
\since 5.0
+ \deprecated
returns QMetaType::metaObject for \a type
\sa metaObject()
*/
-const QMetaObject *QMetaType::metaObjectForType(int type)
-{
- return QMetaType(type).metaObject();
-}
/*!
- \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
@@ -1668,67 +3117,67 @@ const QMetaObject *QMetaType::metaObjectForType(int type)
\warning This function is useful only for registering an alias (typedef)
for every other use case Q_DECLARE_METATYPE and qMetaTypeId() should be used instead.
- \sa {QMetaType::}{qRegisterMetaTypeStreamOperators()}, {QMetaType::}{isRegistered()},
- Q_DECLARE_METATYPE()
+ \sa {QMetaType::}{isRegistered()}, Q_DECLARE_METATYPE()
*/
/*!
- \fn void qRegisterMetaTypeStreamOperators(const char *typeName)
+ \fn template <typename T> int qRegisterMetaType()
\relates QMetaType
\threadsafe
+ \since 4.2
- Registers the stream operators for the type \c{T} called \a
- typeName.
+ Call this function to register the type \c T. Returns the meta type Id.
- Afterward, the type can be streamed using QMetaType::load() and
- QMetaType::save(). These functions are used when streaming a
- QVariant.
+ Example:
- \snippet code/src_corelib_kernel_qmetatype.cpp 5
+ \snippet code/src_corelib_kernel_qmetatype.cpp 7
- The stream operators should have the following signatures:
+ 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.
- \snippet code/src_corelib_kernel_qmetatype.cpp 6
+ To use the type \c T in QMetaType, QVariant, or with the
+ QObject::property() API, registration is not necessary.
- \sa qRegisterMetaType(), QMetaType::isRegistered(), Q_DECLARE_METATYPE()
-*/
+ 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().
+
+ \sa Q_DECLARE_METATYPE()
+ */
/*!
- \fn int qRegisterMetaType()
+ \fn int qRegisterMetaType(QMetaType meta)
\relates QMetaType
\threadsafe
- \since 4.2
+ \since 6.5
- Call this function to register the type \c T. \c T must be declared with
- Q_DECLARE_METATYPE(). Returns the meta type Id.
-
- Example:
-
- \snippet code/src_corelib_kernel_qmetatype.cpp 7
+ 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.
- 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 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 QMetaType, QVariant, or with the
+ QObject::property() API, registration is not necessary.
- 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.
+ 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.
- \sa Q_DECLARE_METATYPE()
+ After a type has been registered, it can be found by its name using
+ QMetaType::fromName().
*/
/*!
- \fn int qMetaTypeId()
+ \fn template <typename T> int qMetaTypeId()
\relates QMetaType
\threadsafe
\since 4.1
@@ -1749,52 +3198,51 @@ const QMetaObject *QMetaType::metaObjectForType(int type)
\sa Q_DECLARE_METATYPE(), QMetaType::type()
*/
-static QtPrivate::QMetaTypeInterface *interfaceForType(int typeId)
+static const QtPrivate::QMetaTypeInterface *interfaceForType(int typeId)
{
- if (typeId >= QMetaType::User) {
- if (auto reg = customTypeRegistry())
- return reg->getCustomType(typeId);
- }
- if (auto moduleHelper = qModuleHelperForType(typeId))
- return moduleHelper->interfaceForType(typeId);
-
- switch (typeId) {
- QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_CONVERT_ID_TO_TYPE)
- QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_CONVERT_ID_TO_TYPE)
- QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE)
- QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_CONVERT_ID_TO_TYPE)
- QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_CONVERT_ID_TO_TYPE)
- default:
- if (typeId != QMetaType::UnknownType)
- qWarning("Trying to construct an instance of an invalid type, type id: %i", typeId);
- return nullptr;
- }
+ 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);
+
+ return iface;
}
/*!
- \fn QMetaType::QMetaType(const int typeId)
+ \fn QMetaType::QMetaType()
+ \since 6.0
+
+ Constructs a default, invalid, QMetaType object.
+*/
+
+/*!
+ \fn QMetaType::QMetaType(int typeId)
\since 5.0
Constructs a QMetaType object that contains all information about type \a typeId.
-
- \note The default parameter was added in Qt 5.15.
*/
QMetaType::QMetaType(int typeId) : QMetaType(interfaceForType(typeId)) {}
-namespace QtMetaTypePrivate {
-const bool VectorBoolElements::true_element = true;
-const bool VectorBoolElements::false_element = false;
-}
+
+/*! \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 {
-#ifndef QT_BOOTSTRAPPED
+#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 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
#endif
}