diff options
Diffstat (limited to 'src/corelib/kernel/qmetatype.h')
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 1215 |
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 |