summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qmetatype.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qmetatype.h')
-rw-r--r--src/corelib/kernel/qmetatype.h1215
1 files changed, 790 insertions, 425 deletions
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 971388fabd..e3ef1474da 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
-** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
-** 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) 2018 Intel Corporation.
+// Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMETATYPE_H
#define QMETATYPE_H
@@ -45,21 +9,24 @@
#include <QtCore/qglobal.h>
#include <QtCore/qatomic.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qrefcount.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qdatastream.h>
+#include <QtCore/qfloat16.h>
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterable.h>
#ifndef QT_NO_QOBJECT
#include <QtCore/qobjectdefs.h>
#endif
+#include <QtCore/qscopeguard.h>
#include <array>
#include <new>
#include <vector>
#include <list>
#include <map>
-#include <optional>
#include <functional>
+#include <optional>
+#include <QtCore/q20type_traits.h>
#ifdef Bool
#error qmetatype.h must be included before any header file that defines Bool
@@ -77,8 +44,7 @@ template <typename T>
inline constexpr int qMetaTypeId();
// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
-#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
- F(Void, 43, void) \
+#define QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F)\
F(Bool, 1, bool) \
F(Int, 2, int) \
F(UInt, 3, uint) \
@@ -98,7 +64,11 @@ inline constexpr int qMetaTypeId();
F(Nullptr, 51, std::nullptr_t) \
F(QCborSimpleType, 52, QCborSimpleType) \
-#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
+#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \
+ QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F) \
+ F(Void, 43, void) \
+
+#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F) \
F(VoidStar, 31, void*) \
#if QT_CONFIG(easingcurve)
@@ -122,6 +92,12 @@ inline constexpr int qMetaTypeId();
#else
# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F)
#endif
+#ifndef QT_NO_VARIANT
+# define QT_FOR_EACH_STATIC_QVARIANT(F) \
+ F(QVariant, 41, QVariant)
+#else
+# define QT_FOR_EACH_STATIC_QVARIANT(F)
+#endif
#define QT_FOR_EACH_STATIC_CORE_CLASS(F)\
F(QChar, 7, QChar) \
@@ -143,7 +119,7 @@ inline constexpr int qMetaTypeId();
F(QPointF, 26, QPointF) \
QT_FOR_EACH_STATIC_EASINGCURVE(F) \
F(QUuid, 30, QUuid) \
- F(QVariant, 41, QVariant) \
+ QT_FOR_EACH_STATIC_QVARIANT(F) \
QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
F(QJsonValue, 45, QJsonValue) \
F(QJsonObject, 46, QJsonObject) \
@@ -152,18 +128,26 @@ inline constexpr int qMetaTypeId();
F(QCborValue, 53, QCborValue) \
F(QCborArray, 54, QCborArray) \
F(QCborMap, 55, QCborMap) \
+ F(Float16, 63, qfloat16) \
QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
#define QT_FOR_EACH_STATIC_CORE_POINTER(F)\
F(QObjectStar, 39, QObject*)
-#define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
+#ifndef QT_NO_VARIANT
+# define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
F(QVariantMap, 8, QVariantMap) \
F(QVariantList, 9, QVariantList) \
F(QVariantHash, 28, QVariantHash) \
F(QVariantPair, 58, QVariantPair) \
F(QByteArrayList, 49, QByteArrayList) \
F(QStringList, 11, QStringList) \
+ /**/
+#else
+# define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
+ F(QByteArrayList, 49, QByteArrayList) \
+ F(QStringList, 11, QStringList)
+#endif
#if QT_CONFIG(shortcut)
#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)\
@@ -217,12 +201,20 @@ inline constexpr int qMetaTypeId();
F(UInt, -1, uint, "quint32") \
F(LongLong, -1, qlonglong, "qint64") \
F(ULongLong, -1, qulonglong, "quint64") \
+ F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
+ F(QStringList, -1, QStringList, "QList<QString>") \
+ QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F)
+
+#ifndef QT_NO_VARIANT
+#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F) \
F(QVariantList, -1, QVariantList, "QList<QVariant>") \
F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
F(QVariantPair, -1, QVariantPair, "QPair<QVariant,QVariant>") \
- F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
- F(QStringList, -1, QStringList, "QList<QString>") \
+ /**/
+#else
+#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F)
+#endif
#define QT_FOR_EACH_STATIC_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
@@ -260,6 +252,63 @@ namespace QtPrivate
class QMetaTypeInterface;
+// MSVC is the only supported compiler that includes the type of a variable in
+// its mangled form, so it's not binary-compatible to drop the const in
+// QMetaTypeInterfaceWrapper::metaType for it, which means we must keep the
+// mutable field until Qt 7.
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || !defined(Q_CC_MSVC)
+# define QMTI_MUTABLE
+using NonConstMetaTypeInterface = QMetaTypeInterface;
+#else
+# define QMTI_MUTABLE mutable
+using NonConstMetaTypeInterface = const QMetaTypeInterface;
+#endif
+
+class QMetaTypeInterface
+{
+public:
+
+ /* Revision: Can increase if new field are added, or if semantics changes
+ 0: Initial Revision
+ 1: the meaning of the NeedsDestruction flag changed
+ */
+ static inline constexpr ushort CurrentRevision = 1;
+
+ ushort revision;
+ ushort alignment;
+ uint size;
+ uint flags;
+ QMTI_MUTABLE QBasicAtomicInt typeId;
+
+ using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
+ MetaObjectFn metaObjectFn;
+
+ const char *name;
+
+ using DefaultCtrFn = void (*)(const QMetaTypeInterface *, void *);
+ DefaultCtrFn defaultCtr;
+ using CopyCtrFn = void (*)(const QMetaTypeInterface *, void *, const void *);
+ CopyCtrFn copyCtr;
+ using MoveCtrFn = void (*)(const QMetaTypeInterface *, void *, void *);
+ MoveCtrFn moveCtr;
+ using DtorFn = void (*)(const QMetaTypeInterface *, void *);
+ DtorFn dtor;
+ using EqualsFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
+ EqualsFn equals;
+ using LessThanFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
+ LessThanFn lessThan;
+ using DebugStreamFn = void (*)(const QMetaTypeInterface *, QDebug &, const void *);
+ DebugStreamFn debugStream;
+ using DataStreamOutFn = void (*)(const QMetaTypeInterface *, QDataStream &, const void *);
+ DataStreamOutFn dataStreamOut;
+ using DataStreamInFn = void (*)(const QMetaTypeInterface *, QDataStream &, void *);
+ DataStreamInFn dataStreamIn;
+
+ using LegacyRegisterOp = void (*)();
+ LegacyRegisterOp legacyRegisterOp;
+};
+#undef QMTI_MUTABLE
+
/*!
This template is used for implicit conversion from type From to type To.
\internal
@@ -291,14 +340,14 @@ To convertImplicit(const From& from)
class Q_CORE_EXPORT QMetaType {
public:
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
// The code that actually gets compiled.
enum Type {
// these are merged with QVariant
QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
FirstCoreType = Bool,
- LastCoreType = QVariantPair,
+ LastCoreType = Float16,
FirstGuiType = QFont,
LastGuiType = QColorSpace,
FirstWidgetsType = QSizePolicy,
@@ -327,9 +376,10 @@ public:
QByteArrayList = 49, QObjectStar = 39, SChar = 40,
Void = 43,
Nullptr = 51,
- QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
+ QVariantMap = 8, QVariantList = 9, QVariantHash = 28, QVariantPair = 58,
QCborSimpleType = 52, QCborValue = 53, QCborArray = 54, QCborMap = 55,
Char16 = 56, Char32 = 57,
+ Int128 = 59, UInt128 = 60, Float128 = 61, BFloat16 = 62, Float16 = 63,
// Gui types
QFont = 0x1000, QPixmap = 0x1001, QBrush = 0x1002, QColor = 0x1003, QPalette = 0x1004,
@@ -340,8 +390,8 @@ public:
// Widget types
QSizePolicy = 0x2000,
- LastCoreType = Char32,
- LastGuiType = QColorSpace,
+
+ // Start-point for client-code types:
User = 65536
};
#endif
@@ -349,7 +399,10 @@ public:
enum TypeFlag {
NeedsConstruction = 0x1,
NeedsDestruction = 0x2,
- MovableType = 0x4,
+ RelocatableType = 0x4,
+#if QT_DEPRECATED_SINCE(6, 0)
+ MovableType Q_DECL_ENUMERATOR_DEPRECATED_X("Use RelocatableType instead.") = RelocatableType,
+#endif
PointerToQObject = 0x8,
IsEnumeration = 0x10,
SharedPointerToQObject = 0x20,
@@ -359,6 +412,11 @@ public:
IsGadget = 0x200,
PointerToGadget = 0x400,
IsPointer = 0x800,
+ IsQmlList =0x1000, // used in the QML engine to recognize QQmlListProperty<T> and list<T>
+ IsConst = 0x2000,
+ // since 6.5:
+ NeedsCopyConstruction = 0x4000,
+ NeedsMoveConstruction = 0x8000,
};
Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
@@ -376,7 +434,7 @@ public:
{ return QMetaType(type).name(); }
QT_DEPRECATED_VERSION_6_0
static int sizeOf(int type)
- { return QMetaType(type).sizeOf(); }
+ { return int(QMetaType(type).sizeOf()); }
QT_DEPRECATED_VERSION_6_0
static TypeFlags typeFlags(int type)
{ return QMetaType(type).flags(); }
@@ -399,31 +457,51 @@ public:
static bool isRegistered(int type);
explicit QMetaType(int type);
- explicit constexpr QMetaType(QtPrivate::QMetaTypeInterface *d) : d_ptr(d) {}
+ explicit constexpr QMetaType(const QtPrivate::QMetaTypeInterface *d) : d_ptr(d) {}
constexpr QMetaType() = default;
bool isValid() const;
bool isRegistered() const;
+ void registerType() const
+ {
+ // "register" is a reserved keyword
+ registerHelper();
+ }
+#if QT_CORE_REMOVED_SINCE(6, 1) || defined(Q_QDOC)
int id() const;
- qsizetype sizeOf() const;
- qsizetype alignOf() const;
- TypeFlags flags() const;
- const QMetaObject *metaObject() const;
- const char *name() const;
+#else
+ // ### Qt 7: Remove traces of out of line version
+ // unused int parameter is used to avoid ODR violation
+ int id(int = 0) const
+ {
+ // keep in sync with the version in removed_api.cpp
+ return registerHelper();
+ }
+#endif
+ constexpr qsizetype sizeOf() const;
+ constexpr qsizetype alignOf() const;
+ constexpr TypeFlags flags() const;
+ constexpr const QMetaObject *metaObject() const;
+ constexpr const char *name() const;
void *create(const void *copy = nullptr) const;
void destroy(void *data) const;
void *construct(void *where, const void *copy = nullptr) const;
void destruct(void *data) const;
- std::optional<int> compare(const void *lhs, const void *rhs) const;
+ QPartialOrdering compare(const void *lhs, const void *rhs) const;
bool equals(const void *lhs, const void *rhs) const;
+ bool isDefaultConstructible() const noexcept { return d_ptr && isDefaultConstructible(d_ptr); }
+ bool isCopyConstructible() const noexcept { return d_ptr && isCopyConstructible(d_ptr); }
+ bool isMoveConstructible() const noexcept { return d_ptr && isMoveConstructible(d_ptr); }
+ bool isDestructible() const noexcept { return d_ptr && isDestructible(d_ptr); }
bool isEqualityComparable() const;
bool isOrdered() const;
#ifndef QT_NO_DATASTREAM
bool save(QDataStream &stream, const void *data) const;
bool load(QDataStream &stream, void *data) const;
+ bool hasRegisteredDataStreamOperators() const;
#if QT_DEPRECATED_SINCE(6, 0)
QT_DEPRECATED_VERSION_6_0
@@ -435,16 +513,29 @@ public:
#endif
#endif
+ QMetaType underlyingType() const;
+
template<typename T>
- static QMetaType fromType();
+ constexpr static QMetaType fromType();
static QMetaType fromName(QByteArrayView name);
- friend bool operator==(QMetaType a, QMetaType b) { return a.d_ptr == b.d_ptr || a.id() == b.id(); }
+ friend bool operator==(QMetaType a, QMetaType b)
+ {
+ if (a.d_ptr == b.d_ptr)
+ return true;
+ if (!a.d_ptr || !b.d_ptr)
+ return false; // one type is undefined, the other is defined
+ // avoid id call if we already have the id
+ const int aId = a.id();
+ const int bId = b.id();
+ return aId == bId;
+ }
friend bool operator!=(QMetaType a, QMetaType b) { return !(a == b); }
-public:
-
#ifndef QT_NO_DEBUG_STREAM
+private:
+ friend Q_CORE_EXPORT QDebug operator<<(QDebug d, QMetaType m);
+public:
bool debugStream(QDebug& dbg, const void *rhs);
bool hasRegisteredDebugStreamOperator() const;
@@ -475,21 +566,6 @@ public:
return registerConverter<From, To>(QtPrivate::convertImplicit<From, To>);
}
-#ifdef Q_CLANG_QDOC
- template<typename MemberFunction, int>
- static bool registerConverter(MemberFunction function);
- template<typename MemberFunctionOk, char>
- static bool registerConverter(MemberFunctionOk function);
- template<typename UnaryFunction>
- static bool registerConverter(UnaryFunction function);
-
- template<typename MemberFunction, int>
- static bool registerMutableView(MemberFunction function);
- template<typename MemberFunctionOk, char>
- static bool registerMutableView(MemberFunctionOk function);
- template<typename UnaryFunction>
- static bool registerMutableView(UnaryFunction function);
-#else
// member function as in "QString QFont::toString() const"
template<typename From, typename To>
static bool registerConverter(To(From::*function)() const)
@@ -505,7 +581,7 @@ public:
*t = (f->*function)();
return true;
};
- return registerConverterFunction(converter, fromType, toType);
+ return registerConverterImpl<From, To>(converter, fromType, toType);
}
// member function
@@ -523,7 +599,7 @@ public:
*t = (f->*function)();
return true;
};
- return registerMutableViewFunction(view, fromType, toType);
+ return registerMutableViewImpl<From, To>(view, fromType, toType);
}
// member function as in "double QString::toDouble(bool *ok = nullptr) const"
@@ -544,7 +620,7 @@ public:
*t = To();
return result;
};
- return registerConverterFunction(converter, fromType, toType);
+ return registerConverterImpl<From, To>(converter, fromType, toType);
}
// functor or function pointer
@@ -556,13 +632,20 @@ public:
const QMetaType fromType = QMetaType::fromType<From>();
const QMetaType toType = QMetaType::fromType<To>();
- auto converter = [function](const void *from, void *to) -> bool {
+ auto converter = [function = std::move(function)](const void *from, void *to) -> bool {
const From *f = static_cast<const From *>(from);
To *t = static_cast<To *>(to);
- *t = function(*f);
+ auto &&r = function(*f);
+ if constexpr (std::is_same_v<q20::remove_cvref_t<decltype(r)>, std::optional<To>>) {
+ if (!r)
+ return false;
+ *t = *std::forward<decltype(r)>(r);
+ } else {
+ *t = std::forward<decltype(r)>(r);
+ }
return true;
};
- return registerConverterFunction(converter, fromType, toType);
+ return registerConverterImpl<From, To>(std::move(converter), fromType, toType);
}
// functor or function pointer
@@ -574,15 +657,42 @@ public:
const QMetaType fromType = QMetaType::fromType<From>();
const QMetaType toType = QMetaType::fromType<To>();
- auto view = [function](void *from, void *to) -> bool {
+ auto view = [function = std::move(function)](void *from, void *to) -> bool {
From *f = static_cast<From *>(from);
To *t = static_cast<To *>(to);
*t = function(*f);
return true;
};
- return registerMutableViewFunction(view, fromType, toType);
+ return registerMutableViewImpl<From, To>(std::move(view), fromType, toType);
+ }
+
+private:
+ template<typename From, typename To>
+ static bool registerConverterImpl(ConverterFunction converter, QMetaType fromType, QMetaType toType)
+ {
+ if (registerConverterFunction(std::move(converter), fromType, toType)) {
+ static const auto unregister = qScopeGuard([=] {
+ unregisterConverterFunction(fromType, toType);
+ });
+ return true;
+ } else {
+ return false;
+ }
}
-#endif
+
+ template<typename From, typename To>
+ static bool registerMutableViewImpl(MutableViewFunction view, QMetaType fromType, QMetaType toType)
+ {
+ if (registerMutableViewFunction(std::move(view), fromType, toType)) {
+ static const auto unregister = qScopeGuard([=] {
+ unregisterMutableViewFunction(fromType, toType);
+ });
+ return true;
+ } else {
+ return false;
+ }
+ }
+public:
static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to);
static bool canConvert(QMetaType fromType, QMetaType toType);
@@ -598,12 +708,19 @@ public:
{
QMetaType t(typeId);
auto c = t.compare(lhs, rhs);
- if (!c) {
+ if (c == QPartialOrdering::Unordered) {
*result = 0;
return false;
+ } else if (c == QPartialOrdering::Less) {
+ *result = -1;
+ return true;
+ } else if (c == QPartialOrdering::Equivalent) {
+ *result = 0;
+ return true;
+ } else {
+ *result = 1;
+ return true;
}
- *result = *c;
- return true;
}
QT_DEPRECATED_VERSION_6_0
static bool equals(const void *lhs, const void *rhs, int typeId, int *result)
@@ -634,7 +751,7 @@ public:
static bool hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType);
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template<typename, bool> friend struct QtPrivate::SequentialValueTypeIsMetaType;
template<typename, bool> friend struct QtPrivate::AssociativeValueTypeIsMetaType;
template<typename, bool> friend struct QtPrivate::IsMetaTypePair;
@@ -647,11 +764,37 @@ public:
static void unregisterMutableViewFunction(QMetaType from, QMetaType to);
static void unregisterMetaType(QMetaType type);
- QtPrivate::QMetaTypeInterface *iface() { return d_ptr; }
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ const QtPrivate::QMetaTypeInterface *iface() { return d_ptr; }
+#endif
+ const QtPrivate::QMetaTypeInterface *iface() const { return d_ptr; }
private:
+ static bool isDefaultConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
+ static bool isCopyConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
+ static bool isMoveConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
+ static bool isDestructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
+
+#if QT_CORE_REMOVED_SINCE(6, 5)
+ int idHelper() const;
+#endif
+ static int registerHelper(const QtPrivate::QMetaTypeInterface *iface);
+ int registerHelper() const
+ {
+ // keep in sync with the QMetaType::id() version in removed_api.cpp
+ if (d_ptr) {
+ if (int id = d_ptr->typeId.loadRelaxed())
+ return id;
+ return registerHelper(d_ptr);
+ }
+ return 0;
+ }
+
+ friend int qRegisterMetaType(QMetaType meta);
+
friend class QVariant;
- QtPrivate::QMetaTypeInterface *d_ptr = nullptr;
+ const QtPrivate::QMetaTypeInterface *d_ptr = nullptr;
};
#undef QT_DEFINE_METATYPE_ID
@@ -695,7 +838,7 @@ public:
{
}
- QPairVariantInterfaceImpl()
+ constexpr QPairVariantInterfaceImpl()
: _pair(nullptr)
, _getFirst(nullptr)
, _getSecond(nullptr)
@@ -705,7 +848,7 @@ public:
inline void first(void *dataPtr) const { _getFirst(&_pair, dataPtr); }
inline void second(void *dataPtr) const { _getSecond(&_pair, dataPtr); }
};
-QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QPairVariantInterfaceImpl, Q_MOVABLE_TYPE)
+QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QPairVariantInterfaceImpl, Q_RELOCATABLE_TYPE)
template<typename From>
struct QPairVariantInterfaceConvertFunctor;
@@ -730,6 +873,34 @@ QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(QT_FORWARD_DECLARE_SHARED_POINTER_T
namespace QtPrivate
{
+ namespace detail {
+ template<typename T, typename ODR_VIOLATION_PREVENTER>
+ struct is_complete_helper
+ {
+ template<typename U>
+ static auto check(U *) -> std::integral_constant<bool, sizeof(U) != 0>;
+ static auto check(...) -> std::false_type;
+ using type = decltype(check(static_cast<T *>(nullptr)));
+ };
+ } // namespace detail
+
+ template <typename T, typename ODR_VIOLATION_PREVENTER>
+ struct is_complete : detail::is_complete_helper<std::remove_reference_t<T>, ODR_VIOLATION_PREVENTER>::type {};
+
+ template <typename T> struct MetatypeDecay { using type = T; };
+ template <typename T> struct MetatypeDecay<const T> { using type = T; };
+ template <typename T> struct MetatypeDecay<const T &> { using type = T; };
+
+ template <typename T> struct IsPointerDeclaredOpaque :
+ std::disjunction<std::is_member_pointer<T>,
+ std::is_function<std::remove_pointer_t<T>>>
+ {};
+ template <> struct IsPointerDeclaredOpaque<void *> : std::true_type {};
+ template <> struct IsPointerDeclaredOpaque<const void *> : std::true_type {};
+
+ // Note: this does not check that T = U* isn't pointing to a
+ // forward-declared type. You may want to combine with
+ // checkTypeIsSuitableForMetaType().
template<typename T>
struct IsPointerToTypeDerivedFromQObject
{
@@ -761,9 +932,9 @@ namespace QtPrivate
#ifndef QT_NO_QOBJECT
static yes_type checkType(QObject* );
+ static yes_type checkType(const QObject* );
#endif
static no_type checkType(...);
- static_assert(sizeof(T), "Type argument of Q_DECLARE_METATYPE(T*) must be fully defined");
enum { Value = sizeof(checkType(static_cast<T*>(nullptr))) == sizeof(yes_type) };
};
@@ -782,6 +953,9 @@ namespace QtPrivate
};
};
+ template <typename T>
+ using IsRealGadget = std::bool_constant<IsGadgetHelper<T>::IsRealGadget>;
+
template<typename T, typename Enable = void>
struct IsPointerToGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
@@ -815,36 +989,42 @@ namespace QtPrivate
template<typename T, typename Enable = void>
struct MetaObjectForType
{
- static constexpr inline const QMetaObject *value() { return nullptr; }
+ static constexpr const QMetaObject *value() { return nullptr; }
+ using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
+ static constexpr MetaObjectFn metaObjectFunction = nullptr;
};
#ifndef QT_NO_QOBJECT
- template<>
- struct MetaObjectForType<void>
- {
- static constexpr inline const QMetaObject *value() { return nullptr; }
- };
template<typename T>
struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type>
{
- static constexpr inline const QMetaObject *value() { return &T::staticMetaObject; }
+ static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
+ static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
};
template<typename T>
- struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
- {
- static constexpr inline const QMetaObject *value() { return &T::staticMetaObject; }
+ struct MetaObjectForType<T, std::enable_if_t<
+ std::disjunction_v<
+ std::bool_constant<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>,
+ std::is_base_of<QObject, T>
+ >
+ >>
+ {
+ static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
+ static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
};
template<typename T>
struct MetaObjectForType<T, typename std::enable_if<IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
{
- static constexpr inline const QMetaObject *value()
+ static constexpr const QMetaObject *value()
{
return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject;
}
+ static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return value(); }
};
template<typename T>
struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type >
{
- static constexpr inline const QMetaObject *value() { return qt_getEnumMetaObject(T()); }
+ static constexpr const QMetaObject *value() { return qt_getEnumMetaObject(T()); }
+ static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return value(); }
};
#endif
@@ -1010,12 +1190,36 @@ namespace QtPrivate
static bool registerConverter() { return false; }
};
+#if QT_CONFIG(future)
+ template<typename T>
+ struct MetaTypeQFutureHelper
+ {
+ static bool registerConverter() { return false; }
+ };
+#endif
+
+ template <typename X> static constexpr bool checkTypeIsSuitableForMetaType()
+ {
+ using T = typename MetatypeDecay<X>::type;
+ static_assert(is_complete<T, void>::value || std::is_void_v<T>,
+ "Meta Types must be fully defined");
+ static_assert(!std::is_reference_v<T>,
+ "Meta Types cannot be non-const references or rvalue references.");
+ if constexpr (std::is_pointer_v<T> && !IsPointerDeclaredOpaque<T>::value) {
+ using Pointed = std::remove_pointer_t<T>;
+ static_assert(is_complete<Pointed, void>::value,
+ "Pointer Meta Types must either point to fully-defined types "
+ "or be declared with Q_DECLARE_OPAQUE_POINTER(T *)");
+ }
+ return true;
+ }
+
Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type);
} // namespace QtPrivate
template <typename T, int =
QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
- QtPrivate::IsGadgetHelper<T>::IsRealGadget ? QMetaType::IsGadget :
+ QtPrivate::IsRealGadget<T>::value ? QMetaType::IsGadget :
QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget :
QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0>
struct QMetaTypeIdQObject
@@ -1042,7 +1246,12 @@ template <typename T>
struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {};
template <typename T>
-struct QMetaTypeId2<T&> { enum {Defined = false }; };
+struct QMetaTypeId2<T&>
+{
+ using NameAsArrayType = void;
+ enum { Defined = false, IsBuiltIn = false };
+ static inline constexpr int qt_metatype_id() { return 0; }
+};
namespace QtPrivate {
template <typename T, bool Defined = QMetaTypeId2<T>::Defined>
@@ -1059,6 +1268,9 @@ namespace QtPrivate {
template <typename Result, typename... Args>
struct IsPointerToTypeDerivedFromQObject<Result(*)(Args...)> { enum { Value = false }; };
+ template<typename T>
+ inline constexpr bool IsQmlListType = false;
+
template<typename T, bool = std::is_enum<T>::value>
constexpr bool IsUnsignedEnum = false;
template<typename T>
@@ -1067,9 +1279,11 @@ namespace QtPrivate {
template<typename T>
struct QMetaTypeTypeFlags
{
- enum { Flags = (QTypeInfo<T>::isRelocatable ? QMetaType::MovableType : 0)
- | (QTypeInfo<T>::isComplex ? QMetaType::NeedsConstruction : 0)
- | (QTypeInfo<T>::isComplex ? QMetaType::NeedsDestruction : 0)
+ enum { Flags = (QTypeInfo<T>::isRelocatable ? QMetaType::RelocatableType : 0)
+ | ((!std::is_default_constructible_v<T> || !QTypeInfo<T>::isValueInitializationBitwiseZero) ? QMetaType::NeedsConstruction : 0)
+ | (!std::is_trivially_destructible_v<T> ? QMetaType::NeedsDestruction : 0)
+ | (!std::is_trivially_copy_constructible_v<T> ? QMetaType::NeedsCopyConstruction : 0)
+ | (!std::is_trivially_move_constructible_v<T> ? QMetaType::NeedsMoveConstruction : 0)
| (IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : 0)
| (IsSharedPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::SharedPointerToQObject : 0)
| (IsWeakPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::WeakPointerToQObject : 0)
@@ -1077,8 +1291,10 @@ namespace QtPrivate {
| (IsEnumOrFlags<T>::value ? QMetaType::IsEnumeration : 0)
| (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0)
| (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0)
- | (QTypeInfo<T>::isPointer ? QMetaType::IsPointer : 0)
+ | (std::is_pointer_v<T> ? QMetaType::IsPointer : 0)
| (IsUnsignedEnum<T> ? QMetaType::IsUnsignedEnumeration : 0)
+ | (IsQmlListType<T> ? QMetaType::IsQmlList : 0)
+ | (std::is_const_v<std::remove_pointer_t<T>> ? QMetaType::IsConst : 0)
};
};
@@ -1113,28 +1329,67 @@ namespace QtPrivate {
}
template <typename T>
-int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
+int qRegisterNormalizedMetaTypeImplementation(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
{
#ifndef QT_NO_QOBJECT
- Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), "qRegisterNormalizedMetaType", "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead.");
+ Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()),
+ "qRegisterNormalizedMetaType",
+ "qRegisterNormalizedMetaType was called with a not normalized type name, "
+ "please call qRegisterMetaType instead.");
#endif
const QMetaType metaType = QMetaType::fromType<T>();
const int id = metaType.id();
- if (id > 0) {
+ QtPrivate::SequentialContainerTransformationHelper<T>::registerConverter();
+ QtPrivate::SequentialContainerTransformationHelper<T>::registerMutableView();
+ QtPrivate::AssociativeContainerTransformationHelper<T>::registerConverter();
+ QtPrivate::AssociativeContainerTransformationHelper<T>::registerMutableView();
+ QtPrivate::MetaTypePairHelper<T>::registerConverter();
+ QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter();
+#if QT_CONFIG(future)
+ QtPrivate::MetaTypeQFutureHelper<T>::registerConverter();
+#endif
+
+ if (normalizedTypeName != metaType.name())
QMetaType::registerNormalizedTypedef(normalizedTypeName, metaType);
- QtPrivate::SequentialContainerTransformationHelper<T>::registerConverter();
- QtPrivate::SequentialContainerTransformationHelper<T>::registerMutableView();
- QtPrivate::AssociativeContainerTransformationHelper<T>::registerConverter();
- QtPrivate::AssociativeContainerTransformationHelper<T>::registerMutableView();
- QtPrivate::MetaTypePairHelper<T>::registerConverter();
- QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter();
- }
return id;
}
+// This primary template calls the -Implementation, like all other specialisations should.
+// But the split allows to
+// - in a header:
+// - define a specialization of this template calling an out-of-line function
+// (QT_DECL_METATYPE_EXTERN{,_TAGGED})
+// - in the .cpp file:
+// - define the out-of-line wrapper to call the -Implementation
+// (QT_IMPL_METATYPE_EXTERN{,_TAGGED})
+// The _TAGGED variants let you choose a tag (must be a C identifier) to disambiguate
+// the out-of-line function; the non-_TAGGED variants use the passed class name as tag.
+template <typename T>
+int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
+{
+ return qRegisterNormalizedMetaTypeImplementation<T>(normalizedTypeName);
+}
+
+#define QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TAG, EXPORT) \
+ QT_BEGIN_NAMESPACE \
+ EXPORT int qRegisterNormalizedMetaType_ ## TAG (const QByteArray &); \
+ template <> inline int qRegisterNormalizedMetaType< TYPE >(const QByteArray &name) \
+ { return qRegisterNormalizedMetaType_ ## TAG (name); } \
+ QT_END_NAMESPACE \
+ Q_DECLARE_METATYPE(TYPE) \
+ /* end */
+#define QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TAG) \
+ int qRegisterNormalizedMetaType_ ## TAG (const QByteArray &name) \
+ { return qRegisterNormalizedMetaTypeImplementation< TYPE >(name); } \
+ /* end */
+#define QT_DECL_METATYPE_EXTERN(TYPE, EXPORT) \
+ QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TYPE, EXPORT)
+#define QT_IMPL_METATYPE_EXTERN(TYPE) \
+ QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TYPE)
+
template <typename T>
int qRegisterMetaType(const char *typeName)
{
@@ -1150,6 +1405,9 @@ template <typename T>
inline constexpr int qMetaTypeId()
{
if constexpr (bool(QMetaTypeId2<T>::IsBuiltIn)) {
+ // this has the same result as the below code, but avoids asking the
+ // compiler to load a global variable whose value we know at compile
+ // time
return QMetaTypeId2<T>::MetaType;
} else {
return QMetaType::fromType<T>().id();
@@ -1163,6 +1421,11 @@ inline constexpr int qRegisterMetaType()
return id;
}
+inline int qRegisterMetaType(QMetaType meta)
+{
+ return meta.registerHelper();
+}
+
#ifndef QT_NO_QOBJECT
template <typename T>
struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
@@ -1173,14 +1436,14 @@ struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
static int qt_metatype_id()
{
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
- const char * const cName = T::staticMetaObject.className();
+ const char *const cName = T::staticMetaObject.className();
QByteArray typeName;
- typeName.reserve(int(strlen(cName)) + 1);
+ typeName.reserve(strlen(cName) + 1);
typeName.append(cName).append('*');
- const int newId = qRegisterNormalizedMetaType<T*>(typeName);
+ const int newId = qRegisterNormalizedMetaType<T *>(typeName);
metatype_id.storeRelease(newId);
return newId;
}
@@ -1195,10 +1458,10 @@ struct QMetaTypeIdQObject<T, QMetaType::IsGadget>
static int qt_metatype_id()
{
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
- const char * const cName = T::staticMetaObject.className();
+ const char *const cName = T::staticMetaObject.className();
const int newId = qRegisterNormalizedMetaType<T>(cName);
metatype_id.storeRelease(newId);
return newId;
@@ -1214,14 +1477,14 @@ struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget>
static int qt_metatype_id()
{
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
- const char * const cName = T::staticMetaObject.className();
+ const char *const cName = T::staticMetaObject.className();
QByteArray typeName;
- typeName.reserve(int(strlen(cName)) + 1);
+ typeName.reserve(strlen(cName) + 1);
typeName.append(cName).append('*');
- const int newId = qRegisterNormalizedMetaType<T*>(typeName);
+ const int newId = qRegisterNormalizedMetaType<T *>(typeName);
metatype_id.storeRelease(newId);
return newId;
}
@@ -1236,13 +1499,13 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
static int qt_metatype_id()
{
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char *eName = qt_getEnumName(T());
const char *cName = qt_getEnumMetaObject(T())->className();
QByteArray typeName;
- typeName.reserve(int(strlen(cName) + 2 + strlen(eName)));
+ typeName.reserve(strlen(cName) + 2 + strlen(eName));
typeName.append(cName).append("::").append(eName);
const int newId = qRegisterNormalizedMetaType<T>(typeName);
metatype_id.storeRelease(newId);
@@ -1253,11 +1516,8 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
#define Q_DECLARE_OPAQUE_POINTER(POINTER) \
QT_BEGIN_NAMESPACE namespace QtPrivate { \
- template <> \
- struct IsPointerToTypeDerivedFromQObject<POINTER > \
- { \
- enum { Value = false }; \
- }; \
+ template <> struct IsPointerDeclaredOpaque<POINTER> \
+ : std::true_type {}; \
} QT_END_NAMESPACE \
/**/
@@ -1269,11 +1529,19 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
struct QMetaTypeId< TYPE > \
{ \
enum { Defined = 1 }; \
+ static_assert(QtPrivate::checkTypeIsSuitableForMetaType<TYPE>()); \
static int qt_metatype_id() \
{ \
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (const int id = metatype_id.loadAcquire()) \
return id; \
+ constexpr auto arr = QtPrivate::typenameHelper<TYPE>(); \
+ auto name = arr.data(); \
+ if (QByteArrayView(name) == (#TYPE)) { \
+ const int id = qRegisterNormalizedMetaType<TYPE>(name); \
+ metatype_id.storeRelease(id); \
+ return id; \
+ } \
const int newId = qRegisterMetaType< TYPE >(#TYPE); \
metatype_id.storeRelease(newId); \
return newId; \
@@ -1302,16 +1570,6 @@ QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
#undef QT_FORWARD_DECLARE_STATIC_TYPES_ITER
-typedef QList<QVariant> QVariantList;
-typedef QMap<QString, QVariant> QVariantMap;
-typedef QHash<QString, QVariant> QVariantHash;
-typedef QPair<QVariant, QVariant> QVariantPair;
-#ifdef Q_CLANG_QDOC
-class QByteArrayList;
-#else
-using QByteArrayList = QList<QByteArray>;
-#endif
-
#define Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE) \
QT_BEGIN_NAMESPACE \
template <typename T> \
@@ -1322,14 +1580,14 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
}; \
static int qt_metatype_id() \
{ \
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (const int id = metatype_id.loadRelaxed()) \
return id; \
const char *tName = QMetaType::fromType<T>().name(); \
Q_ASSERT(tName); \
- const int tNameLen = int(qstrlen(tName)); \
+ const size_t tNameLen = qstrlen(tName); \
QByteArray typeName; \
- typeName.reserve(int(sizeof(#SINGLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + 1); \
+ typeName.reserve(sizeof(#SINGLE_ARG_TEMPLATE) + 1 + tNameLen + 1 + 1); \
typeName.append(#SINGLE_ARG_TEMPLATE, int(sizeof(#SINGLE_ARG_TEMPLATE)) - 1) \
.append('<').append(tName, tNameLen); \
typeName.append('>'); \
@@ -1338,13 +1596,6 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
return newId; \
} \
}; \
-namespace QtPrivate { \
-template<typename T> \
-struct IsSequentialContainer<SINGLE_ARG_TEMPLATE<T> > \
-{ \
- enum { Value = true }; \
-}; \
-} \
QT_END_NAMESPACE
#define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \
@@ -1357,17 +1608,17 @@ struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \
}; \
static int qt_metatype_id() \
{ \
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (const int id = metatype_id.loadAcquire()) \
return id; \
const char *tName = QMetaType::fromType<T>().name(); \
const char *uName = QMetaType::fromType<U>().name(); \
Q_ASSERT(tName); \
Q_ASSERT(uName); \
- const int tNameLen = int(qstrlen(tName)); \
- const int uNameLen = int(qstrlen(uName)); \
+ const size_t tNameLen = qstrlen(tName); \
+ const size_t uNameLen = qstrlen(uName); \
QByteArray typeName; \
- typeName.reserve(int(sizeof(#DOUBLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \
+ typeName.reserve(sizeof(#DOUBLE_ARG_TEMPLATE) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \
typeName.append(#DOUBLE_ARG_TEMPLATE, int(sizeof(#DOUBLE_ARG_TEMPLATE)) - 1) \
.append('<').append(tName, tNameLen).append(',').append(uName, uNameLen); \
typeName.append('>'); \
@@ -1405,12 +1656,12 @@ struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
}; \
static int qt_metatype_id() \
{ \
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (const int id = metatype_id.loadAcquire()) \
return id; \
const char * const cName = T::staticMetaObject.className(); \
QByteArray typeName; \
- typeName.reserve(int(sizeof(#SMART_POINTER) + 1 + strlen(cName) + 1)); \
+ typeName.reserve(sizeof(#SMART_POINTER) + 1 + strlen(cName) + 1); \
typeName.append(#SMART_POINTER, int(sizeof(#SMART_POINTER)) - 1) \
.append('<').append(cName).append('>'); \
const int newId = qRegisterNormalizedMetaType< SMART_POINTER<T> >(typeName); \
@@ -1420,7 +1671,7 @@ struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
}; \
template<typename T> \
struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \
- typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> \
+ typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value && !std::is_const_v<T>>::type> \
{ \
static bool registerConverter() \
{ \
@@ -1441,11 +1692,20 @@ struct QMetaTypeId< SMART_POINTER<T> > \
};\
QT_END_NAMESPACE
-#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER(TEMPLATENAME) \
+#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(SINGLE_ARG_TEMPLATE) \
QT_BEGIN_NAMESPACE \
- template <class T> class TEMPLATENAME; \
+ namespace QtPrivate { \
+ template<typename T> \
+ struct IsSequentialContainer<SINGLE_ARG_TEMPLATE<T> > \
+ { \
+ enum { Value = true }; \
+ }; \
+ } \
QT_END_NAMESPACE \
- Q_DECLARE_METATYPE_TEMPLATE_1ARG(TEMPLATENAME)
+ Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE)
+
+#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER(TEMPLATENAME) \
+ Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(TEMPLATENAME)
QT_END_NAMESPACE
@@ -1453,20 +1713,9 @@ QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER
#undef Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER
-#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE Q_DECLARE_METATYPE_TEMPLATE_1ARG
-
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::vector)
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::list)
-#define Q_FORWARD_DECLARE_METATYPE_TEMPLATE_2ARG_ITER(TEMPLATENAME, CPPTYPE) \
- QT_BEGIN_NAMESPACE \
- template <class T1, class T2> CPPTYPE TEMPLATENAME; \
- QT_END_NAMESPACE \
-
-QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(Q_FORWARD_DECLARE_METATYPE_TEMPLATE_2ARG_ITER)
-
-#undef Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER
-
#define Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(TEMPLATENAME) \
QT_BEGIN_NAMESPACE \
namespace QtPrivate { \
@@ -1488,7 +1737,6 @@ Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::pair)
#define Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER(TEMPLATENAME) \
Q_DECLARE_SMART_POINTER_METATYPE(TEMPLATENAME)
-
QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER)
QT_BEGIN_NAMESPACE
@@ -1497,10 +1745,8 @@ QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
-
QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
-Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl)
QT_BEGIN_NAMESPACE
@@ -1603,40 +1849,6 @@ struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T
}
};
-class QMetaTypeInterface
-{
-public:
- ushort revision; // 0 in Qt 6.0. Can increase if new field are added
- ushort alignment;
- uint size;
- uint flags;
- QBasicAtomicInt typeId;
- const QMetaObject *metaObject;
- const char *name;
-
- using DefaultCtrFn = void (*)(const QMetaTypeInterface *, void *);
- DefaultCtrFn defaultCtr;
- using CopyCtrFn = void (*)(const QMetaTypeInterface *, void *, const void *);
- CopyCtrFn copyCtr;
- using MoveCtrFn = void (*)(const QMetaTypeInterface *, void *, void *);
- MoveCtrFn moveCtr;
- using DtorFn = void (*)(const QMetaTypeInterface *, void *);
- DtorFn dtor;
- using EqualsFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
- EqualsFn equals;
- using LessThanFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
- LessThanFn lessThan;
- using DebugStreamFn = void (*)(const QMetaTypeInterface *, QDebug &, const void *);
- DebugStreamFn debugStream;
- using DataStreamOutFn = void (*)(const QMetaTypeInterface *, QDataStream &, const void *);
- DataStreamOutFn dataStreamOut;
- using DataStreamInFn = void (*)(const QMetaTypeInterface *, QDataStream &, void *);
- DataStreamInFn dataStreamIn;
-
- using LegacyRegisterOp = void (*)();
- LegacyRegisterOp legacyRegisterOp;
-};
-
struct QTypeNormalizer
{
char *output;
@@ -1663,7 +1875,7 @@ private:
#ifdef Q_CC_MSVC
/// On MSVC, keywords like class or struct are not separated with spaces in constexpr
/// context
- if (msvcKw)
+ if (msvcKw && !is_ident_char(*b))
return true;
#endif
Q_UNUSED(msvcKw);
@@ -1695,7 +1907,7 @@ private:
if (x != e)
x++;
return x;
- };
+ }
static constexpr const char *skipTemplate(const char *x, const char *e, bool stopAtComa = false)
{
int scopeDepth = 0;
@@ -1736,7 +1948,7 @@ private:
x++;
}
return x;
- };
+ }
constexpr void append(char x)
{
@@ -1746,13 +1958,156 @@ private:
*output++ = x;
}
+ constexpr void replaceLast(char x)
+ {
+ last = x;
+ if (output)
+ *(output - 1) = x;
+ }
+
constexpr void appendStr(const char *x)
{
while (*x)
append(*x++);
- };
+ }
+
+ constexpr void normalizeIntegerTypes(const char *&begin, const char *end)
+ {
+ int numLong = 0;
+ int numSigned = 0;
+ int numUnsigned = 0;
+ int numInt = 0;
+ int numShort = 0;
+ int numChar = 0;
+ while (begin < end) {
+ if (skipToken(begin, end, "long")) {
+ numLong++;
+ continue;
+ }
+ if (skipToken(begin, end, "int")) {
+ numInt++;
+ continue;
+ }
+ if (skipToken(begin, end, "short")) {
+ numShort++;
+ continue;
+ }
+ if (skipToken(begin, end, "unsigned")) {
+ numUnsigned++;
+ continue;
+ }
+ if (skipToken(begin, end, "signed")) {
+ numSigned++;
+ continue;
+ }
+ if (skipToken(begin, end, "char")) {
+ numChar++;
+ continue;
+ }
+#ifdef Q_CC_MSVC
+ if (skipToken(begin, end, "__int64")) {
+ numLong = 2;
+ continue;
+ }
+#endif
+ break;
+ }
+ if (numLong == 2)
+ append('q'); // q(u)longlong
+ if (numSigned && numChar)
+ appendStr("signed ");
+ else if (numUnsigned)
+ appendStr("u");
+ if (numChar)
+ appendStr("char");
+ else if (numShort)
+ appendStr("short");
+ else if (numLong == 1)
+ appendStr("long");
+ else if (numLong == 2)
+ appendStr("longlong");
+ else if (numUnsigned || numSigned || numInt)
+ appendStr("int");
+ }
+
+ constexpr void skipStructClassOrEnum(const char *&begin, const char *end)
+ {
+ // discard 'struct', 'class', and 'enum'; they are optional
+ // and we don't want them in the normalized signature
+ skipToken(begin, end, "struct", true) || skipToken(begin, end, "class", true)
+ || skipToken(begin, end, "enum", true);
+ }
+
+ constexpr void skipQtNamespace(const char *&begin, const char *end)
+ {
+#ifdef QT_NAMESPACE
+ const char *nsbeg = begin;
+ if (skipToken(nsbeg, end, QT_STRINGIFY(QT_NAMESPACE)) && nsbeg + 2 < end && nsbeg[0] == ':'
+ && nsbeg[1] == ':') {
+ begin = nsbeg + 2;
+ while (begin != end && is_space(*begin))
+ begin++;
+ }
+#else
+ Q_UNUSED(begin);
+ Q_UNUSED(end);
+#endif
+ }
public:
+#if defined(Q_CC_CLANG) || defined (Q_CC_GNU)
+ // this is much simpler than the full type normalization below
+ // the reason is that the signature returned by Q_FUNC_INFO is already
+ // normalized to the largest degree, and we need to do only small adjustments
+ constexpr int normalizeTypeFromSignature(const char *begin, const char *end)
+ {
+ // bail out if there is an anonymous struct
+ std::string_view name(begin, end-begin);
+#if defined (Q_CC_CLANG)
+ if (name.find("anonymous ") != std::string_view::npos)
+ return normalizeType(begin, end);
+#endif
+ if (name.find("unnamed ") != std::string_view::npos)
+ return normalizeType(begin, end);
+ while (begin < end) {
+ if (*begin == ' ') {
+ if (last == ',' || last == '>' || last == '<' || last == '*' || last == '&') {
+ ++begin;
+ continue;
+ }
+ }
+ if (last == ' ') {
+ if (*begin == '*' || *begin == '&' || *begin == '(') {
+ replaceLast(*begin);
+ ++begin;
+ continue;
+ }
+ }
+ if (!is_ident_char(last)) {
+ skipStructClassOrEnum(begin, end);
+ if (begin == end)
+ break;
+
+ skipQtNamespace(begin, end);
+ if (begin == end)
+ break;
+
+ normalizeIntegerTypes(begin, end);
+ if (begin == end)
+ break;
+ }
+ append(*begin);
+ ++begin;
+ }
+ return len;
+ }
+#else
+ // MSVC needs the full normalization, as it puts the const in a different
+ // place than we expect
+ constexpr int normalizeTypeFromSignature(const char *begin, const char *end)
+ { return normalizeType(begin, end); }
+#endif
+
constexpr int normalizeType(const char *begin, const char *end, bool adjustConst = true)
{
// Trim spaces
@@ -1835,20 +2190,8 @@ public:
}
}
- // discard 'struct', 'class', and 'enum'; they are optional
- // and we don't want them in the normalized signature
- skipToken(begin, end, "struct", true) || skipToken(begin, end, "class", true)
- || skipToken(begin, end, "enum", true);
-
-#ifdef QT_NAMESPACE
- const char *nsbeg = begin;
- if (skipToken(nsbeg, end, QT_STRINGIFY(QT_NAMESPACE)) && nsbeg + 2 < end && nsbeg[0] == ':'
- && nsbeg[1] == ':') {
- begin = nsbeg + 2;
- while (begin != end && is_space(*begin))
- begin++;
- }
-#endif
+ skipStructClassOrEnum(begin, end);
+ skipQtNamespace(begin, end);
if (skipToken(begin, end, "QVector")) {
// Replace QVector by QList
@@ -1860,66 +2203,9 @@ public:
appendStr("std::pair");
}
- if (!hasMiddleConst) {
+ if (!hasMiddleConst)
// Normalize the integer types
- int numLong = 0;
- int numSigned = 0;
- int numUnsigned = 0;
- int numInt = 0;
- int numShort = 0;
- int numChar = 0;
- while (begin < end) {
- if (skipToken(begin, end, "long")) {
- numLong++;
- continue;
- }
- if (skipToken(begin, end, "int")) {
- numInt++;
- continue;
- }
- if (skipToken(begin, end, "short")) {
- numShort++;
- continue;
- }
- if (skipToken(begin, end, "unsigned")) {
- numUnsigned++;
- continue;
- }
- if (skipToken(begin, end, "signed")) {
- numSigned++;
- continue;
- }
- if (skipToken(begin, end, "char")) {
- numChar++;
- continue;
- }
- break;
- }
- if (numChar || numShort) {
- if (numSigned && numChar)
- appendStr("signed ");
- if (numUnsigned)
- appendStr("unsigned ");
- if (numChar)
- appendStr("char");
- else
- appendStr("short");
- } else if (numLong) {
- if (numLong == 1) {
- if (numUnsigned)
- append('u');
- appendStr("long");
- } else {
- if (numUnsigned)
- appendStr("unsigned ");
- appendStr("long long");
- }
- } else if (numUnsigned || numSigned || numInt) {
- if (numUnsigned)
- append('u');
- appendStr("int");
- }
- }
+ normalizeIntegerTypes(begin, end);
bool spaceSkiped = true;
while (begin != end) {
@@ -1970,6 +2256,7 @@ struct is_std_pair<std::pair<T1_, T2_>> : std::true_type {
using T2 = T2_;
};
+namespace TypeNameHelper {
template<typename T>
constexpr auto typenameHelper()
{
@@ -1983,7 +2270,7 @@ constexpr auto typenameHelper()
} else {
t1Name = typenameHelper<T1>();
}
- if constexpr (bool (QMetaTypeId2<T2>::IsBuiltIn) ) {
+ if constexpr (bool(QMetaTypeId2<T2>::IsBuiltIn)) {
t2Name = QMetaTypeId2<T2>::nameAsArray;
} else {
t2Name = typenameHelper<T2>();
@@ -1995,7 +2282,7 @@ constexpr auto typenameHelper()
std::array<char, length + 1> result {};
constexpr auto prefix = "std::pair<";
int currentLength = 0;
- for (; currentLength < int(sizeof("std::pair<")-1); ++currentLength)
+ for (; currentLength < int(sizeof("std::pair<") - 1); ++currentLength)
result[currentLength] = prefix[currentLength];
for (int i = 0; i < int(t1Len); ++currentLength, ++i)
result[currentLength] = t1Name[i];
@@ -2010,38 +2297,43 @@ constexpr auto typenameHelper()
#ifdef QT_NAMESPACE
QT_STRINGIFY(QT_NAMESPACE) "::"
#endif
-#ifdef Q_CC_MSVC
- "auto __cdecl QtPrivate::typenameHelper<"
+#if defined(Q_CC_MSVC) && defined(Q_CC_CLANG)
+ "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper(void) [T = "
+#elif defined(Q_CC_MSVC)
+ "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper<"
#elif defined(Q_CC_CLANG)
- "auto QtPrivate::typenameHelper() [T = "
+ "auto QtPrivate::TypeNameHelper::typenameHelper() [T = "
+#elif defined(Q_CC_GHS)
+ "auto QtPrivate::TypeNameHelper::typenameHelper<T>()[with T="
#else
- "constexpr auto QtPrivate::typenameHelper() [with T = "
+ "constexpr auto QtPrivate::TypeNameHelper::typenameHelper() [with T = "
#endif
) - 1;
-#ifdef Q_CC_MSVC
+#if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
constexpr int suffix = sizeof(">(void)");
#else
constexpr int suffix = sizeof("]");
#endif
-#if !(defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG))
- constexpr auto func = Q_FUNC_INFO;
- constexpr const char *begin = func + prefix;
- constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
- constexpr int len = qNormalizeType(begin, end, nullptr);
-#else // GCC < 8.1 did not have Q_FUNC_INFO as constexpr, and GCC 9 has a precompiled header bug
+#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU_ONLY < 804
auto func = Q_FUNC_INFO;
const char *begin = func + prefix;
const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
// This is an upper bound of the size since the normalized signature should always be smaller
- // (Unless there is a QList -> QVector change, but that should not happen)
constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix;
+#else
+ constexpr auto func = Q_FUNC_INFO;
+ constexpr const char *begin = func + prefix;
+ constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
+ constexpr int len = QTypeNormalizer{ nullptr }.normalizeTypeFromSignature(begin, end);
#endif
std::array<char, len + 1> result {};
- qNormalizeType(begin, end, result.data());
+ QTypeNormalizer{ result.data() }.normalizeTypeFromSignature(begin, end);
return result;
}
}
+} // namespace TypeNameHelper
+using TypeNameHelper::typenameHelper;
template<typename T, typename = void>
struct BuiltinMetaType : std::integral_constant<int, 0>
@@ -2056,8 +2348,11 @@ struct BuiltinMetaType<T, std::enable_if_t<QMetaTypeId2<T>::IsBuiltIn>>
template<typename T, bool = (QTypeTraits::has_operator_equal_v<T> && !std::is_pointer_v<T>)>
struct QEqualityOperatorForType
{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_FLOAT_COMPARE
static bool equals(const QMetaTypeInterface *, const void *a, const void *b)
{ return *reinterpret_cast<const T *>(a) == *reinterpret_cast<const T *>(b); }
+QT_WARNING_POP
};
template<typename T>
@@ -2095,75 +2390,90 @@ struct QDebugStreamOperatorForType <T, false>
template<typename T, bool = QTypeTraits::has_stream_operator_v<QDataStream, T>>
struct QDataStreamOperatorForType
{
+ static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
+ static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
+};
+
+#ifndef QT_NO_DATASTREAM
+template<typename T>
+struct QDataStreamOperatorForType <T, true>
+{
static void dataStreamOut(const QMetaTypeInterface *, QDataStream &ds, const void *a)
{ ds << *reinterpret_cast<const T *>(a); }
static void dataStreamIn(const QMetaTypeInterface *, QDataStream &ds, void *a)
{ ds >> *reinterpret_cast<T *>(a); }
};
+#endif
-template<typename T>
-struct QDataStreamOperatorForType <T, false>
-{
- static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
- static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
-};
+// Performance optimization:
+//
+// Don't add all these symbols to the dynamic symbol tables on ELF systems and
+// on Darwin. Each library is going to have a copy anyway and QMetaType already
+// copes with some of these being "hidden" (see QMetaType::idHelper()). We may
+// as well let the linker know it can always use the local copy.
+//
+// This is currently not enabled for GCC due to
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106023
+
+#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
+# pragma GCC visibility push(hidden)
+#endif
template<typename S>
class QMetaTypeForType
{
- static const decltype(typenameHelper<S>()) name;
+public:
+ static constexpr decltype(typenameHelper<S>()) name = typenameHelper<S>();
+ static constexpr unsigned Flags = QMetaTypeTypeFlags<S>::Flags;
- template<typename T>
static constexpr QMetaTypeInterface::DefaultCtrFn getDefaultCtr()
{
- if constexpr (std::is_default_constructible_v<T>) {
- return [](const QMetaTypeInterface *, void *addr) { new (addr) T(); };
- } else {
- return nullptr;
- }
+ if constexpr (std::is_default_constructible_v<S> && !QTypeInfo<S>::isValueInitializationBitwiseZero) {
+ return [](const QMetaTypeInterface *, void *addr) { new (addr) S(); };
+ } else {
+ return nullptr;
+ }
}
- template<typename T>
static constexpr QMetaTypeInterface::CopyCtrFn getCopyCtr()
{
- if constexpr (std::is_copy_constructible_v<T>) {
- return [](const QMetaTypeInterface *, void *addr, const void *other) {
- new (addr) T(*reinterpret_cast<const T *>(other));
- };
- } else {
- return nullptr;
- }
+ if constexpr (std::is_copy_constructible_v<S> && !std::is_trivially_copy_constructible_v<S>) {
+ return [](const QMetaTypeInterface *, void *addr, const void *other) {
+ new (addr) S(*reinterpret_cast<const S *>(other));
+ };
+ } else {
+ return nullptr;
+ }
}
- template<typename T>
static constexpr QMetaTypeInterface::MoveCtrFn getMoveCtr()
{
- if constexpr (std::is_move_constructible_v<T>) {
- return [](const QMetaTypeInterface *, void *addr, void *other) {
- new (addr) T(std::move(*reinterpret_cast<T *>(other)));
- };
- } else {
- return nullptr;
- }
+ if constexpr (std::is_move_constructible_v<S> && !std::is_trivially_move_constructible_v<S>) {
+ return [](const QMetaTypeInterface *, void *addr, void *other) {
+ new (addr) S(std::move(*reinterpret_cast<S *>(other)));
+ };
+ } else {
+ return nullptr;
+ }
}
- template<typename T>
static constexpr QMetaTypeInterface::DtorFn getDtor()
{
- if constexpr (std::is_destructible_v<T>)
- return [](const QMetaTypeInterface *, void *addr) { reinterpret_cast<T *>(addr)->~T(); };
- else
- return nullptr;
+ if constexpr (std::is_destructible_v<S> && !std::is_trivially_destructible_v<S>)
+ return [](const QMetaTypeInterface *, void *addr) {
+ reinterpret_cast<S *>(addr)->~S();
+ };
+ else
+ return nullptr;
}
- template<typename T>
static constexpr QMetaTypeInterface::LegacyRegisterOp getLegacyRegister()
{
- if constexpr (QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn) {
- return []() { QMetaTypeId2<T>::qt_metatype_id(); };
- } else {
- return nullptr;
- }
+ if constexpr (QMetaTypeId2<S>::Defined && !QMetaTypeId2<S>::IsBuiltIn) {
+ return []() { QMetaTypeId2<S>::qt_metatype_id(); };
+ } else {
+ return nullptr;
+ }
}
static constexpr const char *getName()
@@ -2174,49 +2484,54 @@ class QMetaTypeForType
return name.data();
}
}
-
-public:
- static QMetaTypeInterface metaType;
};
template<typename T>
-QMetaTypeInterface QMetaTypeForType<T>::metaType = {
- /*.revision=*/ 0,
- /*.alignment=*/ alignof(T),
- /*.size=*/ sizeof(T),
- /*.flags=*/ QMetaTypeTypeFlags<T>::Flags,
- /*.typeId=*/ BuiltinMetaType<T>::value,
- /*.metaObject=*/ MetaObjectForType<T>::value(),
- /*.name=*/ getName(),
- /*.defaultCtr=*/ getDefaultCtr<T>(),
- /*.copyCtr=*/ getCopyCtr<T>(),
- /*.moveCtr=*/ getMoveCtr<T>(),
- /*.dtor=*/ getDtor<T>(),
- /*.equals=*/ QEqualityOperatorForType<T>::equals,
- /*.lessThan=*/ QLessThanOperatorForType<T>::lessThan,
- /*.debugStream=*/ QDebugStreamOperatorForType<T>::debugStream,
- /*.dataStreamOut=*/ QDataStreamOperatorForType<T>::dataStreamOut,
- /*.dataStreamIn=*/ QDataStreamOperatorForType<T>::dataStreamIn,
- /*.legacyRegisterOp=*/ getLegacyRegister<T>()
+struct QMetaTypeInterfaceWrapper
+{
+ // if the type ID for T is known at compile-time, then we can declare
+ // the QMetaTypeInterface object const; otherwise, we declare it as
+ // non-const and the .typeId is updated by QMetaType::idHelper().
+ static constexpr bool IsConstMetaTypeInterface = !!BuiltinMetaType<T>::value;
+ using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>;
+
+ static inline InterfaceType metaType = {
+ /*.revision=*/ QMetaTypeInterface::CurrentRevision,
+ /*.alignment=*/ alignof(T),
+ /*.size=*/ sizeof(T),
+ /*.flags=*/ QMetaTypeForType<T>::Flags,
+ /*.typeId=*/ BuiltinMetaType<T>::value,
+ /*.metaObjectFn=*/ MetaObjectForType<T>::metaObjectFunction,
+ /*.name=*/ QMetaTypeForType<T>::getName(),
+ /*.defaultCtr=*/ QMetaTypeForType<T>::getDefaultCtr(),
+ /*.copyCtr=*/ QMetaTypeForType<T>::getCopyCtr(),
+ /*.moveCtr=*/ QMetaTypeForType<T>::getMoveCtr(),
+ /*.dtor=*/ QMetaTypeForType<T>::getDtor(),
+ /*.equals=*/ QEqualityOperatorForType<T>::equals,
+ /*.lessThan=*/ QLessThanOperatorForType<T>::lessThan,
+ /*.debugStream=*/ QDebugStreamOperatorForType<T>::debugStream,
+ /*.dataStreamOut=*/ QDataStreamOperatorForType<T>::dataStreamOut,
+ /*.dataStreamIn=*/ QDataStreamOperatorForType<T>::dataStreamIn,
+ /*.legacyRegisterOp=*/ QMetaTypeForType<T>::getLegacyRegister()
+ };
};
-template<typename T>
-constexpr const decltype(typenameHelper<T>()) QMetaTypeForType<T>::name = typenameHelper<T>();
+#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
+# pragma GCC visibility pop
+#endif
template<>
-class QMetaTypeForType<void>
+class QMetaTypeInterfaceWrapper<void>
{
- static const decltype(typenameHelper<void>()) name;
-
public:
- static inline QMetaTypeInterface metaType =
+ static constexpr QMetaTypeInterface metaType =
{
/*.revision=*/ 0,
/*.alignment=*/ 0,
/*.size=*/ 0,
/*.flags=*/ 0,
/*.typeId=*/ BuiltinMetaType<void>::value,
- /*.metaObject=*/ nullptr,
+ /*.metaObjectFn=*/ nullptr,
/*.name=*/ "void",
/*.defaultCtr=*/ nullptr,
/*.copyCtr=*/ nullptr,
@@ -2230,48 +2545,37 @@ public:
/*.legacyRegisterOp=*/ nullptr
};
};
-#undef QT_METATYPE_CONSTEXPRLAMDA
-#ifndef QT_BOOTSTRAPPED
-#define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
+/*
+ MSVC instantiates extern templates
+(https://developercommunity.visualstudio.com/t/c11-extern-templates-doesnt-work-for-class-templat/157868)
+
+ The INTEGRITY compiler apparently does too.
+
+ On Windows (with other compilers or whenever MSVC is fixed), we can't declare
+ QMetaTypeInterfaceWrapper with __declspec(dllimport) because taking its
+ address is not a core constant expression.
+ */
+#if !defined(QT_BOOTSTRAPPED) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY)
+
+#ifdef QT_NO_DATA_RELOCATION
+# define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
extern template class Q_CORE_EXPORT QMetaTypeForType<Name>;
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4910) // '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_GCC("-Wattributes") // false positive because of QMetaTypeForType<void>
-QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
-QT_WARNING_POP
+#else
+# define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
+ extern template class Q_CORE_EXPORT QMetaTypeForType<Name>; \
+ extern template struct Q_CORE_EXPORT QMetaTypeInterfaceWrapper<Name>;
+#endif
+
+QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
-QT_WARNING_POP
#undef QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER
#endif
template<typename T>
-constexpr QMetaTypeInterface *qMetaTypeInterfaceForType()
-{
- using Ty = std::remove_cv_t<std::remove_reference_t<T>>;
- return &QMetaTypeForType<Ty>::metaType;
-}
-
-namespace detail {
-
-template <typename T, typename ODR_VIOLATION_PREVENTER>
-struct is_complete_helper {
- template <typename U>
- static auto check(U*) -> std::integral_constant<bool, sizeof(U) != 0>;
- static auto check(...) -> std::false_type;
- using type = decltype(check(static_cast<T*>(nullptr)));
-};
-
-}
-
-template <typename T, typename ODR_VIOLATION_PREVENTER>
-struct is_complete : detail::is_complete_helper<T, ODR_VIOLATION_PREVENTER>::type {};
-
-template<typename T>
struct qRemovePointerLike
{
using type = std::remove_pointer_t<T>;
@@ -2296,38 +2600,99 @@ struct TypeAndForceComplete
using ForceComplete = ForceComplete_;
};
+template<typename T>
+constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType()
+{
+ // don't check the type is suitable here
+ using Ty = typename MetatypeDecay<T>::type;
+ return &QMetaTypeInterfaceWrapper<Ty>::metaType;
+}
+
template<typename Unique, typename TypeCompletePair>
-constexpr QMetaTypeInterface *qTryMetaTypeInterfaceForType()
+constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType()
{
using T = typename TypeCompletePair::type;
using ForceComplete = typename TypeCompletePair::ForceComplete;
- using Ty = std::remove_cv_t<std::remove_reference_t<T>>;
+ using Ty = typename MetatypeDecay<T>::type;
using Tz = qRemovePointerLike_t<Ty>;
- if constexpr (!is_complete<Tz, Unique>::value && !ForceComplete::value) {
+
+ if constexpr (std::is_void_v<Tz>) {
+ // early out to avoid expanding the rest of the templates
+ return &QMetaTypeInterfaceWrapper<Ty>::metaType;
+ } else if constexpr (ForceComplete::value) {
+ checkTypeIsSuitableForMetaType<Ty>();
+ return &QMetaTypeInterfaceWrapper<Ty>::metaType;
+ } else if constexpr (std::is_reference_v<Tz>) {
+ return nullptr;
+ } else if constexpr (!is_complete<Tz, Unique>::value) {
return nullptr;
} else {
- return &QMetaTypeForType<Ty>::metaType;
+ // don't check the type is suitable here
+ return &QMetaTypeInterfaceWrapper<Ty>::metaType;
}
}
} // namespace QtPrivate
template<typename T>
-QMetaType QMetaType::fromType()
+constexpr QMetaType QMetaType::fromType()
{
+ QtPrivate::checkTypeIsSuitableForMetaType<T>();
return QMetaType(QtPrivate::qMetaTypeInterfaceForType<T>());
}
+constexpr qsizetype QMetaType::sizeOf() const
+{
+ return d_ptr ? d_ptr->size : 0;
+}
+
+constexpr qsizetype QMetaType::alignOf() const
+{
+ return d_ptr ? d_ptr->alignment : 0;
+}
+
+constexpr QMetaType::TypeFlags QMetaType::flags() const
+{
+ return d_ptr ? TypeFlags(d_ptr->flags) : TypeFlags{};
+}
+
+constexpr const QMetaObject *QMetaType::metaObject() const
+{
+ return d_ptr && d_ptr->metaObjectFn ? d_ptr->metaObjectFn(d_ptr) : nullptr;
+}
+
template<typename... T>
-QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = {
- QtPrivate::qMetaTypeInterfaceForType<T>()...
+constexpr const QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = {
+ /*
+ Unique in qTryMetaTypeInterfaceForType does not have to be unique here
+ as we require _all_ types here to be actually complete.
+ We just want to have the additional type processing that exist in
+ QtPrivate::qTryMetaTypeInterfaceForType as opposed to the normal
+ QtPrivate::qMetaTypeInterfaceForType used in QMetaType::fromType
+ */
+ QtPrivate::qTryMetaTypeInterfaceForType<void, QtPrivate::TypeAndForceComplete<T, std::true_type>>()...
};
+constexpr const char *QMetaType::name() const
+{
+ return d_ptr ? d_ptr->name : nullptr;
+}
+
template<typename Unique,typename... T>
-QtPrivate::QMetaTypeInterface *const qt_incomplete_metaTypeArray[] = {
+constexpr const QtPrivate::QMetaTypeInterface *const qt_incomplete_metaTypeArray[] = {
QtPrivate::qTryMetaTypeInterfaceForType<Unique, T>()...
};
+inline size_t qHash(QMetaType type, size_t seed = 0)
+{
+ // We cannot use d_ptr here since the same type in different DLLs
+ // might result in different pointers!
+ return qHash(type.id(), seed);
+}
+
QT_END_NAMESPACE
+QT_DECL_METATYPE_EXTERN_TAGGED(QtMetaTypePrivate::QPairVariantInterfaceImpl,
+ QPairVariantInterfaceImpl, Q_CORE_EXPORT)
+
#endif // QMETATYPE_H