diff options
author | Lars Knoll <lars.knoll@qt.io> | 2020-07-13 16:13:29 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2020-08-24 00:17:50 +0200 |
commit | fefb1c136220750ff4bbe2638108c4f7273bab19 (patch) | |
tree | 912e7f452c470798d62e2120b78aecaacfa55409 /src/corelib/kernel | |
parent | f21a7116e950286b7f13cdff23aab653fefc2ddb (diff) |
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 <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 145 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 7 | ||||
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 89 |
3 files changed, 151 insertions, 90 deletions
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 <bitset> #include <new> +#include <cstring> 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<const unsigned char *>(from); + break; + case 2: + ull = *static_cast<const unsigned short *>(from); + break; + case 4: + ull = *static_cast<const unsigned int *>(from); + break; + case 8: + ull = *static_cast<const quint64 *>(from); + break; + default: + Q_UNREACHABLE(); + } + if (toTypeId == QMetaType::ULongLong) { + *static_cast<qulonglong *>(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<const signed char *>(from); + break; + case 2: + ll = *static_cast<const short *>(from); + break; + case 4: + ll = *static_cast<const int *>(from); + break; + case 8: + ll = *static_cast<const qint64 *>(from); + break; + default: + Q_UNREACHABLE(); + } + if (toTypeId == QMetaType::LongLong) { + *static_cast<qlonglong *>(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<QString *>(to) = QString::fromUtf8(key); + else + *static_cast<QByteArray *>(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<const QString *>(from)->toUtf8() + : *static_cast<const QByteArray *>(from); + value = en.keysToValue(keys.constData(), &ok); + } +#endif + if (!ok) { + if (fromTypeId == QMetaType::LongLong) { + value = *static_cast<const qlonglong *>(from); + ok = true; + } else { + ok = QMetaType::convert(from, fromTypeId, &value, QMetaType::LongLong); + } + } + + if (!ok) + return false; + + switch (toType.sizeOf()) { + case 1: + *static_cast<signed char *>(to) = value; + return true; + case 2: + *static_cast<qint16 *>(to) = value; + return true; + case 4: + *static_cast<qint32 *>(to) = value; + return true; + case 8: + *static_cast<qint64 *>(to) = value; + return true; + default: + Q_UNREACHABLE(); + return false; + } +} + /*! 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 <typename Result, typename... Args> struct IsPointerToTypeDerivedFromQObject<Result(*)(Args...)> { enum { Value = false }; }; + template<typename T, bool = std::is_enum<T>::value> + constexpr bool IsUnsignedEnum = false; + template<typename T> + constexpr bool IsUnsignedEnum<T, true> = !std::is_signed_v<std::underlying_type_t<T>>; + template<typename T> struct QMetaTypeTypeFlags { @@ -1442,6 +1448,7 @@ namespace QtPrivate { | (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0) | (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0) | (QTypeInfo<T>::isPointer ? QMetaType::IsPointer : 0) + | (IsUnsignedEnum<T> ? 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<QString *>(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<QByteArray *>(result); - *ba = en.valueToKey(qConvertToNumber(d, &ok)); - return ok; - } -#endif - return false; - } case QMetaType::Short: *static_cast<short *>(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<QString>().toUtf8() - : d->get<QByteArray>(); - int value = en.keysToValue(keys.constData(), &ok); - if (ok) { - switch (QMetaType::sizeOf(t)) { - case 1: - *static_cast<signed char *>(result) = value; - return true; - case 2: - *static_cast<qint16 *>(result) = value; - return true; - case 4: - *static_cast<qint32 *>(result) = value; - return true; - case 8: - *static_cast<qint64 *>(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<signed char *>(result) = value; - return true; - case 2: - *static_cast<qint16 *>(result) = value; - return true; - case 4: - *static_cast<qint32 *>(result) = value; - return true; - case 8: - *static_cast<qint64 *>(result) = value; - return true; - } - } - return ok; - } return false; } return true; |