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 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) (limited to 'src/corelib/kernel/qmetatype.cpp') 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; } /*! -- cgit v1.2.3