Clean up QVariant::Private::Data

Remove all the internal members of the union. Instead replace
it with raw storage (uchar[]) aligned to max_align_t.

Place all accesses to the internal members with get<> methods
for consistency.

Change-Id: Icebf46b90c9375aa6ea0b5913b2132608e8c223d
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
This commit is contained in:
Lars Knoll 2020-07-12 22:27:41 +02:00
parent bfbac6be75
commit 524edc7363
3 changed files with 90 additions and 115 deletions

View File

@ -107,21 +107,21 @@ static qlonglong qMetaTypeNumber(const QVariant::Private *d)
{ {
switch (d->type().id()) { switch (d->type().id()) {
case QMetaType::Int: case QMetaType::Int:
return d->data.i; return d->get<int>();
case QMetaType::LongLong: case QMetaType::LongLong:
return d->data.ll; return d->get<qlonglong>();
case QMetaType::Char: case QMetaType::Char:
return qlonglong(d->data.c); return qlonglong(d->get<char>());
case QMetaType::SChar: case QMetaType::SChar:
return qlonglong(d->data.sc); return qlonglong(d->get<signed char>());
case QMetaType::Short: case QMetaType::Short:
return qlonglong(d->data.s); return qlonglong(d->get<short>());
case QMetaType::Long: case QMetaType::Long:
return qlonglong(d->data.l); return qlonglong(d->get<long>());
case QMetaType::Float: case QMetaType::Float:
return qRound64(d->data.f); return qRound64(d->get<float>());
case QMetaType::Double: case QMetaType::Double:
return qRound64(d->data.d); return qRound64(d->get<double>());
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
case QMetaType::QJsonValue: case QMetaType::QJsonValue:
return d->get<QJsonValue>().toDouble(); return d->get<QJsonValue>().toDouble();
@ -137,15 +137,15 @@ static qulonglong qMetaTypeUNumber(const QVariant::Private *d)
{ {
switch (d->type().id()) { switch (d->type().id()) {
case QMetaType::UInt: case QMetaType::UInt:
return d->data.u; return d->get<unsigned int>();
case QMetaType::ULongLong: case QMetaType::ULongLong:
return d->data.ull; return d->get<qulonglong>();
case QMetaType::UChar: case QMetaType::UChar:
return d->data.uc; return d->get<unsigned char>();
case QMetaType::UShort: case QMetaType::UShort:
return d->data.us; return d->get<unsigned short>();
case QMetaType::ULong: case QMetaType::ULong:
return d->data.ul; return d->get<unsigned long>();
} }
Q_ASSERT(false); Q_ASSERT(false);
return 0; return 0;
@ -178,7 +178,7 @@ static qlonglong qConvertToNumber(const QVariant::Private *d, bool *ok, bool all
case QMetaType::QByteArray: case QMetaType::QByteArray:
return d->get<QByteArray>().toLongLong(ok); return d->get<QByteArray>().toLongLong(ok);
case QMetaType::Bool: case QMetaType::Bool:
return qlonglong(d->data.b); return qlonglong(d->get<bool>());
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
case QMetaType::QCborValue: case QMetaType::QCborValue:
if (!d->get<QCborValue>().isInteger() && !d->get<QCborValue>().isDouble()) if (!d->get<QCborValue>().isInteger() && !d->get<QCborValue>().isDouble())
@ -212,13 +212,13 @@ static qlonglong qConvertToNumber(const QVariant::Private *d, bool *ok, bool all
|| d->type().id() == QMetaType::QCborSimpleType) { || d->type().id() == QMetaType::QCborSimpleType) {
switch (typeInfo.sizeOf()) { switch (typeInfo.sizeOf()) {
case 1: case 1:
return d->is_shared ? *reinterpret_cast<signed char *>(d->data.shared->data()) : d->data.sc; return d->get<signed char>();
case 2: case 2:
return d->is_shared ? *reinterpret_cast<qint16 *>(d->data.shared->data()) : d->data.s; return d->get<short>();
case 4: case 4:
return d->is_shared ? *reinterpret_cast<qint32 *>(d->data.shared->data()) : d->data.i; return d->get<int>();
case 8: case 8:
return d->is_shared ? *reinterpret_cast<qint64 *>(d->data.shared->data()) : d->data.ll; return d->get<qlonglong>();
} }
} }
@ -233,9 +233,9 @@ static qreal qConvertToRealNumber(const QVariant::Private *d, bool *ok)
case QMetaType::QString: case QMetaType::QString:
return d->get<QString>().toDouble(ok); return d->get<QString>().toDouble(ok);
case QMetaType::Double: case QMetaType::Double:
return qreal(d->data.d); return qreal(d->get<double>());
case QMetaType::Float: case QMetaType::Float:
return qreal(d->data.f); return qreal(d->get<float>());
case QMetaType::ULongLong: case QMetaType::ULongLong:
case QMetaType::UInt: case QMetaType::UInt:
case QMetaType::UChar: case QMetaType::UChar:
@ -266,7 +266,7 @@ static qulonglong qConvertToUnsignedNumber(const QVariant::Private *d, bool *ok)
case QMetaType::QByteArray: case QMetaType::QByteArray:
return d->get<QByteArray>().toULongLong(ok); return d->get<QByteArray>().toULongLong(ok);
case QMetaType::Bool: case QMetaType::Bool:
return qulonglong(d->data.b); return qulonglong(d->get<bool>());
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
case QMetaType::QCborValue: case QMetaType::QCborValue:
if (d->get<QCborValue>().isDouble()) if (d->get<QCborValue>().isDouble())
@ -300,13 +300,13 @@ static qulonglong qConvertToUnsignedNumber(const QVariant::Private *d, bool *ok)
if (typeInfo.flags() & QMetaType::IsEnumeration) { if (typeInfo.flags() & QMetaType::IsEnumeration) {
switch (typeInfo.sizeOf()) { switch (typeInfo.sizeOf()) {
case 1: case 1:
return d->is_shared ? *reinterpret_cast<uchar *>(d->data.shared->data()) : d->data.uc; return d->get<unsigned char>();
case 2: case 2:
return d->is_shared ? *reinterpret_cast<quint16 *>(d->data.shared->data()) : d->data.us; return d->get<unsigned short>();
case 4: case 4:
return d->is_shared ? *reinterpret_cast<quint32 *>(d->data.shared->data()) : d->data.u; return d->get<unsigned int>();
case 8: case 8:
return d->is_shared ? *reinterpret_cast<qint64 *>(d->data.shared->data()) : d->data.ull; return d->get<qulonglong>();
} }
} }
@ -321,16 +321,6 @@ inline bool qt_convertToBool(const QVariant::Private *const d)
return !(str.isEmpty() || str == LiteralWrapper("0") || str == LiteralWrapper("false")); return !(str.isEmpty() || str == LiteralWrapper("0") || str == LiteralWrapper("false"));
} }
/*!
\internal
Returns the internal data pointer from \a d.
*/
static const void *constData(const QVariant::Private &d)
{
return d.is_shared ? d.data.shared->data() : reinterpret_cast<const void *>(&d.data.c);
}
#ifndef QT_NO_QOBJECT #ifndef QT_NO_QOBJECT
/*! /*!
\internal \internal
@ -361,7 +351,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
Q_ASSERT(result); Q_ASSERT(result);
if (d->type().id() >= QMetaType::LastCoreType || t >= QMetaType::LastCoreType) { if (d->type().id() >= QMetaType::LastCoreType || t >= QMetaType::LastCoreType) {
if (QMetaType::convert(constData(*d), d->type().id(), result, t)) if (QMetaType::convert(d->storage(), d->type().id(), result, t))
return true; return true;
} }
@ -414,7 +404,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
case QMetaType::Char: case QMetaType::Char:
case QMetaType::SChar: case QMetaType::SChar:
case QMetaType::UChar: case QMetaType::UChar:
*str = QChar::fromLatin1(d->data.c); *str = QChar::fromLatin1(d->get<char>());
break; break;
case QMetaType::Short: case QMetaType::Short:
case QMetaType::Long: case QMetaType::Long:
@ -429,10 +419,10 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*str = QString::number(qMetaTypeUNumber(d)); *str = QString::number(qMetaTypeUNumber(d));
break; break;
case QMetaType::Float: case QMetaType::Float:
*str = QString::number(d->data.f, 'g', QLocale::FloatingPointShortest); *str = QString::number(d->get<float>(), 'g', QLocale::FloatingPointShortest);
break; break;
case QMetaType::Double: case QMetaType::Double:
*str = QString::number(d->data.d, 'g', QLocale::FloatingPointShortest); *str = QString::number(d->get<double>(), 'g', QLocale::FloatingPointShortest);
break; break;
#if QT_CONFIG(datestring) #if QT_CONFIG(datestring)
case QMetaType::QDate: case QMetaType::QDate:
@ -446,7 +436,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
break; break;
#endif #endif
case QMetaType::Bool: case QMetaType::Bool:
*str = d->data.b ? QStringLiteral("true") : QStringLiteral("false"); *str = d->get<bool>() ? QStringLiteral("true") : QStringLiteral("false");
break; break;
case QMetaType::QByteArray: case QMetaType::QByteArray:
*str = QString::fromUtf8(d->get<QByteArray>().constData()); *str = QString::fromUtf8(d->get<QByteArray>().constData());
@ -639,15 +629,15 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*ba = d->get<QString>().toUtf8(); *ba = d->get<QString>().toUtf8();
break; break;
case QMetaType::Double: case QMetaType::Double:
*ba = QByteArray::number(d->data.d, 'g', QLocale::FloatingPointShortest); *ba = QByteArray::number(d->get<double>(), 'g', QLocale::FloatingPointShortest);
break; break;
case QMetaType::Float: case QMetaType::Float:
*ba = QByteArray::number(d->data.f, 'g', QLocale::FloatingPointShortest); *ba = QByteArray::number(d->get<float>(), 'g', QLocale::FloatingPointShortest);
break; break;
case QMetaType::Char: case QMetaType::Char:
case QMetaType::SChar: case QMetaType::SChar:
case QMetaType::UChar: case QMetaType::UChar:
*ba = QByteArray(1, d->data.c); *ba = QByteArray(1, d->get<char>());
break; break;
case QMetaType::Int: case QMetaType::Int:
case QMetaType::LongLong: case QMetaType::LongLong:
@ -662,7 +652,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*ba = QByteArray::number(qMetaTypeUNumber(d)); *ba = QByteArray::number(qMetaTypeUNumber(d));
break; break;
case QMetaType::Bool: case QMetaType::Bool:
*ba = QByteArray(d->data.b ? "true" : "false"); *ba = QByteArray(d->get<bool>() ? "true" : "false");
break; break;
case QMetaType::QUuid: case QMetaType::QUuid:
*ba = d->get<QUuid>().toByteArray(); *ba = d->get<QUuid>().toByteArray();
@ -783,10 +773,10 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*f = d->get<QByteArray>().toDouble(&ok); *f = d->get<QByteArray>().toDouble(&ok);
return ok; return ok;
case QMetaType::Bool: case QMetaType::Bool:
*f = double(d->data.b); *f = double(d->get<bool>());
break; break;
case QMetaType::Float: case QMetaType::Float:
*f = double(d->data.f); *f = double(d->get<float>());
break; break;
case QMetaType::LongLong: case QMetaType::LongLong:
case QMetaType::Int: case QMetaType::Int:
@ -831,10 +821,10 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*f = d->get<QByteArray>().toFloat(&ok); *f = d->get<QByteArray>().toFloat(&ok);
return ok; return ok;
case QMetaType::Bool: case QMetaType::Bool:
*f = float(d->data.b); *f = float(d->get<bool>());
break; break;
case QMetaType::Double: case QMetaType::Double:
*f = float(d->data.d); *f = float(d->get<double>());
break; break;
case QMetaType::LongLong: case QMetaType::LongLong:
case QMetaType::Int: case QMetaType::Int:
@ -1023,7 +1013,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*static_cast<QJsonValue *>(result) = QJsonValue(QJsonValue::Null); *static_cast<QJsonValue *>(result) = QJsonValue(QJsonValue::Null);
break; break;
case QMetaType::Bool: case QMetaType::Bool:
*static_cast<QJsonValue *>(result) = QJsonValue(d->data.b); *static_cast<QJsonValue *>(result) = QJsonValue(d->get<bool>());
break; break;
case QMetaType::Int: case QMetaType::Int:
case QMetaType::UInt: case QMetaType::UInt:
@ -1153,7 +1143,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*static_cast<QCborValue *>(result) = QCborValue(QCborValue::Null); *static_cast<QCborValue *>(result) = QCborValue(QCborValue::Null);
break; break;
case QMetaType::Bool: case QMetaType::Bool:
*static_cast<QCborValue *>(result) = QCborValue(d->data.b); *static_cast<QCborValue *>(result) = QCborValue(d->get<bool>());
break; break;
case QMetaType::Int: case QMetaType::Int:
case QMetaType::UInt: case QMetaType::UInt:
@ -1366,8 +1356,7 @@ static void customConstruct(QVariant::Private *d, const void *copy)
return; return;
} }
// this logic should match with QVariantIntegrator::CanUseInternalSpace if (QVariant::Private::canUseInternalSpace(size)) {
if (size <= sizeof(QVariant::Private::Data)) {
type.construct(&d->data, copy); type.construct(&d->data, copy);
d->is_shared = false; d->is_shared = false;
} else { } else {
@ -1929,25 +1918,25 @@ QVariant::QVariant(QMetaType type, const void *copy) : d(type)
QVariant::QVariant(int val) QVariant::QVariant(int val)
: d(Int) : d(Int)
{ d.data.i = val; } { d.set(val); }
QVariant::QVariant(uint val) QVariant::QVariant(uint val)
: d(UInt) : d(UInt)
{ d.data.u = val; } { d.set(val); }
QVariant::QVariant(qlonglong val) QVariant::QVariant(qlonglong val)
: d(LongLong) : d(LongLong)
{ d.data.ll = val; } { d.set(val); }
QVariant::QVariant(qulonglong val) QVariant::QVariant(qulonglong val)
: d(ULongLong) : d(ULongLong)
{ d.data.ull = val; } { d.set(val); }
QVariant::QVariant(bool val) QVariant::QVariant(bool val)
: d(Bool) : d(Bool)
{ d.data.b = val; } { d.set(val); }
QVariant::QVariant(double val) QVariant::QVariant(double val)
: d(Double) : d(Double)
{ d.data.d = val; } { d.set(val); }
QVariant::QVariant(float val) QVariant::QVariant(float val)
: d(QMetaType::Float) : d(QMetaType::Float)
{ d.data.f = val; } { d.set(val); }
QVariant::QVariant(const QByteArray &val) QVariant::QVariant(const QByteArray &val)
: d(ByteArray) : d(ByteArray)
@ -2474,7 +2463,7 @@ inline T qVariantToHelper(const QVariant::Private &d)
T ret; T ret;
if (d.type().id() >= QMetaType::LastCoreType || targetType.id() >= QMetaType::LastCoreType) { if (d.type().id() >= QMetaType::LastCoreType || targetType.id() >= QMetaType::LastCoreType) {
const void * const from = constData(d); const void * const from = d.storage();
if (QMetaType::convert(from, d.type().id(), &ret, targetType.id())) if (QMetaType::convert(from, d.type().id(), &ret, targetType.id()))
return ret; return ret;
} }
@ -2908,7 +2897,7 @@ inline T qNumVariantToHelper(const QVariant::Private &d, bool *ok, const T& val)
T ret = 0; T ret = 0;
if ((d.type().id() >= QMetaType::LastCoreType || t >= QMetaType::LastCoreType) if ((d.type().id() >= QMetaType::LastCoreType || t >= QMetaType::LastCoreType)
&& QMetaType::convert(constData(d), d.type().id(), &ret, t)) && QMetaType::convert(d.storage(), d.type().id(), &ret, t))
return ret; return ret;
bool success = convert(&d, t, &ret); bool success = convert(&d, t, &ret);
@ -2936,7 +2925,7 @@ inline T qNumVariantToHelper(const QVariant::Private &d, bool *ok, const T& val)
*/ */
int QVariant::toInt(bool *ok) const int QVariant::toInt(bool *ok) const
{ {
return qNumVariantToHelper<int>(d, ok, d.data.i); return qNumVariantToHelper<int>(d, ok, d.get<int>());
} }
/*! /*!
@ -2958,7 +2947,7 @@ int QVariant::toInt(bool *ok) const
*/ */
uint QVariant::toUInt(bool *ok) const uint QVariant::toUInt(bool *ok) const
{ {
return qNumVariantToHelper<uint>(d, ok, d.data.u); return qNumVariantToHelper<uint>(d, ok, d.get<unsigned int>());
} }
/*! /*!
@ -2975,7 +2964,7 @@ uint QVariant::toUInt(bool *ok) const
*/ */
qlonglong QVariant::toLongLong(bool *ok) const qlonglong QVariant::toLongLong(bool *ok) const
{ {
return qNumVariantToHelper<qlonglong>(d, ok, d.data.ll); return qNumVariantToHelper<qlonglong>(d, ok, d.get<qlonglong>());
} }
/*! /*!
@ -2992,7 +2981,7 @@ qlonglong QVariant::toLongLong(bool *ok) const
*/ */
qulonglong QVariant::toULongLong(bool *ok) const qulonglong QVariant::toULongLong(bool *ok) const
{ {
return qNumVariantToHelper<qulonglong>(d, ok, d.data.ull); return qNumVariantToHelper<qulonglong>(d, ok, d.get<qulonglong>());
} }
/*! /*!
@ -3010,7 +2999,7 @@ qulonglong QVariant::toULongLong(bool *ok) const
bool QVariant::toBool() const bool QVariant::toBool() const
{ {
if (d.type() == QMetaType::fromType<bool>()) if (d.type() == QMetaType::fromType<bool>())
return d.data.b; return d.get<bool>();
bool res = false; bool res = false;
@ -3039,7 +3028,7 @@ bool QVariant::toBool() const
*/ */
double QVariant::toDouble(bool *ok) const double QVariant::toDouble(bool *ok) const
{ {
return qNumVariantToHelper<double>(d, ok, d.data.d); return qNumVariantToHelper<double>(d, ok, d.get<double>());
} }
/*! /*!
@ -3058,7 +3047,7 @@ double QVariant::toDouble(bool *ok) const
*/ */
float QVariant::toFloat(bool *ok) const float QVariant::toFloat(bool *ok) const
{ {
return qNumVariantToHelper<float>(d, ok, d.data.f); return qNumVariantToHelper<float>(d, ok, d.get<float>());
} }
/*! /*!
@ -3077,7 +3066,7 @@ float QVariant::toFloat(bool *ok) const
*/ */
qreal QVariant::toReal(bool *ok) const qreal QVariant::toReal(bool *ok) const
{ {
return qNumVariantToHelper<qreal>(d, ok, d.data.real); return qNumVariantToHelper<qreal>(d, ok, d.get<qreal>());
} }
/*! /*!
@ -3356,7 +3345,7 @@ bool QVariant::canConvert(int targetTypeId) const
if (QMetaType::typeFlags(targetTypeId) & QMetaType::IsEnumeration) { if (QMetaType::typeFlags(targetTypeId) & QMetaType::IsEnumeration) {
targetTypeId = QMetaType::Int; targetTypeId = QMetaType::Int;
} else { } else {
return canConvertMetaObject(currentType, targetTypeId, d.data.o); return canConvertMetaObject(currentType, targetTypeId, d.get<QObject *>());
} }
} }
@ -3504,7 +3493,7 @@ bool QVariant::canConvert(int targetTypeId) const
&& qCanConvertMatrix[QVariant::Int] & (1U << currentType)) && qCanConvertMatrix[QVariant::Int] & (1U << currentType))
|| QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration; || QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration;
case QMetaType::QObjectStar: case QMetaType::QObjectStar:
return canConvertMetaObject(currentType, targetTypeId, d.data.o); return canConvertMetaObject(currentType, targetTypeId, d.get<QObject *>());
default: default:
return false; return false;
} }
@ -3553,7 +3542,7 @@ bool QVariant::convert(int targetTypeId)
return false; return false;
if ((QMetaType::typeFlags(oldValue.userType()) & QMetaType::PointerToQObject) && (QMetaType::typeFlags(targetTypeId) & QMetaType::PointerToQObject)) { if ((QMetaType::typeFlags(oldValue.userType()) & QMetaType::PointerToQObject) && (QMetaType::typeFlags(targetTypeId) & QMetaType::PointerToQObject)) {
create(targetTypeId, &oldValue.d.data.o); create(targetTypeId, &oldValue.d.get<QObject *>());
return true; return true;
} }
@ -3821,7 +3810,7 @@ bool QVariant::equals(const QVariant &v) const
if (!metatype.isValid()) if (!metatype.isValid())
return true; return true;
return metatype.equals(QT_PREPEND_NAMESPACE(constData(d)), QT_PREPEND_NAMESPACE(constData(v.d))); return metatype.equals(d.storage(), v.d.storage());
} }
/*! /*!
@ -3859,10 +3848,8 @@ bool QVariant::isNull() const
{ {
if (d.is_null || !metaType().isValid()) if (d.is_null || !metaType().isValid())
return true; return true;
if (metaType().flags() & QMetaType::IsPointer) { if (metaType().flags() & QMetaType::IsPointer)
const void *d_ptr = d.is_shared ? d.data.shared->data() : &(d.data); return d.get<void *>() == nullptr;
return *static_cast<void *const *>(d_ptr) == nullptr;
}
return false; return false;
} }
@ -3874,7 +3861,7 @@ QDebug operator<<(QDebug dbg, const QVariant &v)
dbg.nospace() << "QVariant("; dbg.nospace() << "QVariant(";
if (typeId != QMetaType::UnknownType) { if (typeId != QMetaType::UnknownType) {
dbg << QMetaType::typeName(typeId) << ", "; dbg << QMetaType::typeName(typeId) << ", ";
bool streamed = v.d.type().debugStream(dbg, constData(v.d)); bool streamed = v.d.type().debugStream(dbg, v.d.storage());
if (!streamed && v.canConvert<QString>()) if (!streamed && v.canConvert<QString>())
dbg << v.toString(); dbg << v.toString();
} else { } else {

View File

@ -352,7 +352,7 @@ class Q_CORE_EXPORT QVariant
void *data(); void *data();
const void *constData() const const void *constData() const
{ return d.is_shared ? d.data.shared->data() : &d.data.ptr; } { return d.storage(); }
inline const void *data() const { return constData(); } inline const void *data() const { return constData(); }
template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>> template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>>
@ -442,7 +442,21 @@ class Q_CORE_EXPORT QVariant
}; };
struct Private struct Private
{ {
Private() noexcept : packedType(0), is_shared(false), is_null(true) {} static constexpr size_t MaxInternalSize = 3*sizeof(void *);
template<typename T>
static constexpr bool CanUseInternalSpace = (sizeof(T) <= MaxInternalSize);
static constexpr bool canUseInternalSpace(size_t s) { return s <= MaxInternalSize; }
alignas(std::max_align_t) union
{
uchar data[MaxInternalSize] = {};
PrivateShared *shared;
} data;
quintptr is_shared : 1;
quintptr is_null : 1;
quintptr packedType : sizeof(QMetaType) * 8 - 2;
Private() noexcept : is_shared(false), is_null(true), packedType(0) {}
explicit Private(const QMetaType &type) noexcept : is_shared(false), is_null(false) explicit Private(const QMetaType &type) noexcept : is_shared(false), is_null(false)
{ {
if (type.d_ptr) if (type.d_ptr)
@ -468,45 +482,19 @@ class Q_CORE_EXPORT QVariant
} }
Q_CORE_EXPORT ~Private(); Q_CORE_EXPORT ~Private();
union Data
{
void *threeptr[3] = { nullptr, nullptr, nullptr };
char c;
uchar uc;
short s;
signed char sc;
ushort us;
int i;
uint u;
long l;
ulong ul;
bool b;
double d;
float f;
qreal real;
qlonglong ll;
qulonglong ull;
QObject *o;
void *ptr;
PrivateShared *shared;
} data;
quintptr packedType : sizeof(QMetaType) * 8 - 2;
quintptr is_shared : 1;
quintptr is_null : 1;
template<typename T>
static constexpr bool CanUseInternalSpace = sizeof(T) <= sizeof(QVariant::Private::Data);
const void *storage() const const void *storage() const
{ return is_shared ? data.shared->data() : &data; } { return is_shared ? data.shared->data() : &data.data; }
const void *internalStorage() const const void *internalStorage() const
{ Q_ASSERT(is_shared); return &data; } { Q_ASSERT(is_shared); return &data.data; }
// determine internal storage at compile time // determine internal storage at compile time
template<typename T> template<typename T>
const T &get() const const T &get() const
{ return *static_cast<const T *>(CanUseInternalSpace<T> ? &data : data.shared->data()); } { return *static_cast<const T *>(storage()); }
template<typename T>
void set(const T &t)
{ *static_cast<T *>(CanUseInternalSpace<T> ? &data.data : data.shared->data()) = t; }
inline QMetaType type() const inline QMetaType type() const
{ {
@ -750,7 +738,7 @@ namespace QtPrivate {
static T object(const QVariant &v) static T object(const QVariant &v)
{ {
return qobject_cast<T>(QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject return qobject_cast<T>(QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject
? v.d.data.o ? v.d.get<QObject *>()
: QVariantValueHelper::metaType(v)); : QVariantValueHelper::metaType(v));
} }
#endif #endif

View File

@ -91,7 +91,7 @@ struct BigClass
{ {
double n,i,e,r,o,b; double n,i,e,r,o,b;
}; };
static_assert(sizeof(BigClass) > sizeof(QVariant::Private::Data)); static_assert(sizeof(BigClass) > sizeof(QVariant::Private::MaxInternalSize));
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(BigClass, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(BigClass, Q_MOVABLE_TYPE);
QT_END_NAMESPACE QT_END_NAMESPACE
@ -101,7 +101,7 @@ struct SmallClass
{ {
char s; char s;
}; };
static_assert(sizeof(SmallClass) <= sizeof(QVariant::Private::Data)); static_assert(sizeof(SmallClass) <= sizeof(QVariant::Private::MaxInternalSize));
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(SmallClass, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(SmallClass, Q_MOVABLE_TYPE);
QT_END_NAMESPACE QT_END_NAMESPACE