From fefb1c136220750ff4bbe2638108c4f7273bab19 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 13 Jul 2020 16:13:29 +0200 Subject: Move enum conversions over into QMetaType Take the opportunity to properly handle the underlying type (size and signed vs unsigned). Change-Id: I0cb8cf40acac6de03c24ed3fe570db68268952c8 Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetatype.cpp | 145 ++++++++++++++++++++++++++++++++++++++- src/corelib/kernel/qmetatype.h | 7 ++ src/corelib/kernel/qvariant.cpp | 89 ------------------------ 3 files changed, 151 insertions(+), 90 deletions(-) (limited to 'src/corelib/kernel') diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 776b593d23..4bbc228a9e 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -71,6 +71,7 @@ # include "qcborarray.h" # include "qcbormap.h" # include "qbytearraylist.h" +# include "qmetaobject.h" #endif #if QT_CONFIG(itemmodel) @@ -86,6 +87,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -1541,6 +1543,138 @@ bool QMetaType::hasRegisteredDebugStreamOperator() const } #endif +#ifndef QT_NO_QOBJECT +/*! + \internal + returns a QMetaEnum for a given meta tape type id if possible +*/ +static QMetaEnum metaEnumFromType(QMetaType t) +{ + if (t.flags() & QMetaType::IsEnumeration) { + if (const QMetaObject *metaObject = t.metaObject()) { + const QByteArray enumName = t.name(); + const char *lastColon = std::strrchr(enumName, ':'); + return metaObject->enumerator(metaObject->indexOfEnumerator( + lastColon ? lastColon + 1 : enumName.constData())); + } + } + return QMetaEnum(); +} +#endif + +static bool convertFromEnum(const void *from, const QMetaType &fromType, void *to, int toTypeId) +{ + qlonglong ll; + if (fromType.flags() & QMetaType::IsUnsignedEnumeration) { + qulonglong ull; + switch (fromType.sizeOf()) { + case 1: + ull = *static_cast(from); + break; + case 2: + ull = *static_cast(from); + break; + case 4: + ull = *static_cast(from); + break; + case 8: + ull = *static_cast(from); + break; + default: + Q_UNREACHABLE(); + } + if (toTypeId == QMetaType::ULongLong) { + *static_cast(to) = ull; + return true; + } + if (toTypeId != QMetaType::QString && toTypeId != QMetaType::QByteArray) + return QMetaType::convert(&ull, QMetaType::ULongLong, to, toTypeId); + ll = qlonglong(ull); + } else { + switch (fromType.sizeOf()) { + case 1: + ll = *static_cast(from); + break; + case 2: + ll = *static_cast(from); + break; + case 4: + ll = *static_cast(from); + break; + case 8: + ll = *static_cast(from); + break; + default: + Q_UNREACHABLE(); + } + if (toTypeId == QMetaType::LongLong) { + *static_cast(to) = ll; + return true; + } + if (toTypeId != QMetaType::QString && toTypeId != QMetaType::QByteArray) + return QMetaType::convert(&ll, QMetaType::LongLong, to, toTypeId); + } + Q_ASSERT(toTypeId == QMetaType::QString || toTypeId == QMetaType::QByteArray); +#ifndef QT_NO_QOBJECT + QMetaEnum en = metaEnumFromType(fromType); + if (en.isValid()) { + const char *key = en.valueToKey(ll); + if (toTypeId == QMetaType::QString) + *static_cast(to) = QString::fromUtf8(key); + else + *static_cast(to) = key; + return true; + } +#endif + return false; +} + +static bool convertToEnum(const void *from, int fromTypeId, void *to, const QMetaType &toType) +{ + qlonglong value; + bool ok = false; +#ifndef QT_NO_QOBJECT + if (fromTypeId == QMetaType::QString || fromTypeId == QMetaType::QByteArray) { + QMetaEnum en = metaEnumFromType(toType); + if (!en.isValid()) + return false; + QByteArray keys = (fromTypeId == QMetaType::QString) + ? static_cast(from)->toUtf8() + : *static_cast(from); + value = en.keysToValue(keys.constData(), &ok); + } +#endif + if (!ok) { + if (fromTypeId == QMetaType::LongLong) { + value = *static_cast(from); + ok = true; + } else { + ok = QMetaType::convert(from, fromTypeId, &value, QMetaType::LongLong); + } + } + + if (!ok) + return false; + + switch (toType.sizeOf()) { + case 1: + *static_cast(to) = value; + return true; + case 2: + *static_cast(to) = value; + return true; + case 4: + *static_cast(to) = value; + return true; + case 8: + *static_cast(to) = value; + return true; + default: + Q_UNREACHABLE(); + return false; + } +} + /*! Converts the object at \a from from \a fromTypeId to the preallocated space at \a to typed \a toTypeId. Returns \c true, if the conversion succeeded, otherwise false. @@ -1554,7 +1688,16 @@ bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId } const QMetaType::ConverterFunction * const f = customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId)); - return f && (*f)(from, to); + if (f) + return (*f)(from, to); + + QMetaType fromType(fromTypeId); + if (fromType.flags() & QMetaType::IsEnumeration) + return convertFromEnum(from, fromType, to, toTypeId); + QMetaType toType(toTypeId); + if (toType.flags() & QMetaType::IsEnumeration) + return convertToEnum(from, fromTypeId, to, toType); + return false; } /*! diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index a6c415b268..b4217bc3a1 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -356,6 +356,7 @@ public: IsGadget = 0x200, PointerToGadget = 0x400, IsPointer = 0x800, + IsUnsignedEnumeration = 0x1000 }; Q_DECLARE_FLAGS(TypeFlags, TypeFlag) @@ -1428,6 +1429,11 @@ namespace QtPrivate { template struct IsPointerToTypeDerivedFromQObject { enum { Value = false }; }; + template::value> + constexpr bool IsUnsignedEnum = false; + template + constexpr bool IsUnsignedEnum = !std::is_signed_v>; + template struct QMetaTypeTypeFlags { @@ -1442,6 +1448,7 @@ namespace QtPrivate { | (IsGadgetHelper::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0) | (IsPointerToGadgetHelper::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0) | (QTypeInfo::isPointer ? QMetaType::IsPointer : 0) + | (IsUnsignedEnum ? QMetaType::IsUnsignedEnumeration : 0) }; }; diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index f904879190..1877832db3 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -312,25 +312,6 @@ inline bool qt_convertToBool(const QVariant::Private *const d) return !(str.isEmpty() || str == LiteralWrapper("0") || str == LiteralWrapper("false")); } -#ifndef QT_NO_QOBJECT -/*! - \internal - returns a QMetaEnum for a given meta tape type id if possible -*/ -static QMetaEnum metaEnumFromType(QMetaType t) -{ - if (t.flags() & QMetaType::IsEnumeration) { - if (const QMetaObject *metaObject = t.metaObject()) { - const QByteArray enumName = t.name(); - const char *lastColon = std::strrchr(enumName, ':'); - return metaObject->enumerator(metaObject->indexOfEnumerator( - lastColon ? lastColon + 1 : enumName.constData())); - } - } - return QMetaEnum(); -} -#endif - /*! \internal @@ -349,28 +330,6 @@ static bool convert(const QVariant::Private *d, int t, void *result) bool ok = true; switch (uint(t)) { - case QMetaType::QString: { - QString *str = static_cast(result); -#ifndef QT_NO_QOBJECT - QMetaEnum en = metaEnumFromType(d->type()); - if (en.isValid()) { - *str = QString::fromUtf8(en.valueToKey(qConvertToNumber(d, &ok))); - return ok; - } -#endif - return false; - } - case QMetaType::QByteArray: { -#ifndef QT_NO_QOBJECT - QMetaEnum en = metaEnumFromType(d->type()); - if (en.isValid()) { - QByteArray *ba = static_cast(result); - *ba = en.valueToKey(qConvertToNumber(d, &ok)); - return ok; - } -#endif - return false; - } case QMetaType::Short: *static_cast(result) = short(qConvertToNumber(d, &ok)); return ok; @@ -716,54 +675,6 @@ static bool convert(const QVariant::Private *d, int t, void *result) #endif default: -#ifndef QT_NO_QOBJECT - if (d->typeId() == QMetaType::QString || d->typeId() == QMetaType::QByteArray) { - QMetaEnum en = metaEnumFromType(QMetaType(t)); - if (en.isValid()) { - QByteArray keys = (d->typeId() == QMetaType::QString) - ? d->get().toUtf8() - : d->get(); - int value = en.keysToValue(keys.constData(), &ok); - if (ok) { - switch (QMetaType::sizeOf(t)) { - case 1: - *static_cast(result) = value; - return true; - case 2: - *static_cast(result) = value; - return true; - case 4: - *static_cast(result) = value; - return true; - case 8: - *static_cast(result) = value; - return true; - } - } - } - } -#endif - if (QMetaType::typeFlags(t) & QMetaType::IsEnumeration - || d->typeId() == QMetaType::QCborSimpleType) { - qlonglong value = qConvertToNumber(d, &ok); - if (ok) { - switch (QMetaType::sizeOf(t)) { - case 1: - *static_cast(result) = value; - return true; - case 2: - *static_cast(result) = value; - return true; - case 4: - *static_cast(result) = value; - return true; - case 8: - *static_cast(result) = value; - return true; - } - } - return ok; - } return false; } return true; -- cgit v1.2.3