summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qvariant.cpp143
-rw-r--r--src/corelib/kernel/qvariant.h58
-rw-r--r--tests/benchmarks/corelib/kernel/qvariant/tst_qvariant.cpp4
3 files changed, 90 insertions, 115 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 2a0066c9e2..fa021dc1d1 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -107,21 +107,21 @@ static qlonglong qMetaTypeNumber(const QVariant::Private *d)
{
switch (d->type().id()) {
case QMetaType::Int:
- return d->data.i;
+ return d->get<int>();
case QMetaType::LongLong:
- return d->data.ll;
+ return d->get<qlonglong>();
case QMetaType::Char:
- return qlonglong(d->data.c);
+ return qlonglong(d->get<char>());
case QMetaType::SChar:
- return qlonglong(d->data.sc);
+ return qlonglong(d->get<signed char>());
case QMetaType::Short:
- return qlonglong(d->data.s);
+ return qlonglong(d->get<short>());
case QMetaType::Long:
- return qlonglong(d->data.l);
+ return qlonglong(d->get<long>());
case QMetaType::Float:
- return qRound64(d->data.f);
+ return qRound64(d->get<float>());
case QMetaType::Double:
- return qRound64(d->data.d);
+ return qRound64(d->get<double>());
#ifndef QT_BOOTSTRAPPED
case QMetaType::QJsonValue:
return d->get<QJsonValue>().toDouble();
@@ -137,15 +137,15 @@ static qulonglong qMetaTypeUNumber(const QVariant::Private *d)
{
switch (d->type().id()) {
case QMetaType::UInt:
- return d->data.u;
+ return d->get<unsigned int>();
case QMetaType::ULongLong:
- return d->data.ull;
+ return d->get<qulonglong>();
case QMetaType::UChar:
- return d->data.uc;
+ return d->get<unsigned char>();
case QMetaType::UShort:
- return d->data.us;
+ return d->get<unsigned short>();
case QMetaType::ULong:
- return d->data.ul;
+ return d->get<unsigned long>();
}
Q_ASSERT(false);
return 0;
@@ -178,7 +178,7 @@ static qlonglong qConvertToNumber(const QVariant::Private *d, bool *ok, bool all
case QMetaType::QByteArray:
return d->get<QByteArray>().toLongLong(ok);
case QMetaType::Bool:
- return qlonglong(d->data.b);
+ return qlonglong(d->get<bool>());
#ifndef QT_BOOTSTRAPPED
case QMetaType::QCborValue:
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) {
switch (typeInfo.sizeOf()) {
case 1:
- return d->is_shared ? *reinterpret_cast<signed char *>(d->data.shared->data()) : d->data.sc;
+ return d->get<signed char>();
case 2:
- return d->is_shared ? *reinterpret_cast<qint16 *>(d->data.shared->data()) : d->data.s;
+ return d->get<short>();
case 4:
- return d->is_shared ? *reinterpret_cast<qint32 *>(d->data.shared->data()) : d->data.i;
+ return d->get<int>();
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:
return d->get<QString>().toDouble(ok);
case QMetaType::Double:
- return qreal(d->data.d);
+ return qreal(d->get<double>());
case QMetaType::Float:
- return qreal(d->data.f);
+ return qreal(d->get<float>());
case QMetaType::ULongLong:
case QMetaType::UInt:
case QMetaType::UChar:
@@ -266,7 +266,7 @@ static qulonglong qConvertToUnsignedNumber(const QVariant::Private *d, bool *ok)
case QMetaType::QByteArray:
return d->get<QByteArray>().toULongLong(ok);
case QMetaType::Bool:
- return qulonglong(d->data.b);
+ return qulonglong(d->get<bool>());
#ifndef QT_BOOTSTRAPPED
case QMetaType::QCborValue:
if (d->get<QCborValue>().isDouble())
@@ -300,13 +300,13 @@ static qulonglong qConvertToUnsignedNumber(const QVariant::Private *d, bool *ok)
if (typeInfo.flags() & QMetaType::IsEnumeration) {
switch (typeInfo.sizeOf()) {
case 1:
- return d->is_shared ? *reinterpret_cast<uchar *>(d->data.shared->data()) : d->data.uc;
+ return d->get<unsigned char>();
case 2:
- return d->is_shared ? *reinterpret_cast<quint16 *>(d->data.shared->data()) : d->data.us;
+ return d->get<unsigned short>();
case 4:
- return d->is_shared ? *reinterpret_cast<quint32 *>(d->data.shared->data()) : d->data.u;
+ return d->get<unsigned int>();
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"));
}
-/*!
- \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
/*!
\internal
@@ -361,7 +351,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
Q_ASSERT(result);
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;
}
@@ -414,7 +404,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
case QMetaType::Char:
case QMetaType::SChar:
case QMetaType::UChar:
- *str = QChar::fromLatin1(d->data.c);
+ *str = QChar::fromLatin1(d->get<char>());
break;
case QMetaType::Short:
case QMetaType::Long:
@@ -429,10 +419,10 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*str = QString::number(qMetaTypeUNumber(d));
break;
case QMetaType::Float:
- *str = QString::number(d->data.f, 'g', QLocale::FloatingPointShortest);
+ *str = QString::number(d->get<float>(), 'g', QLocale::FloatingPointShortest);
break;
case QMetaType::Double:
- *str = QString::number(d->data.d, 'g', QLocale::FloatingPointShortest);
+ *str = QString::number(d->get<double>(), 'g', QLocale::FloatingPointShortest);
break;
#if QT_CONFIG(datestring)
case QMetaType::QDate:
@@ -446,7 +436,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
break;
#endif
case QMetaType::Bool:
- *str = d->data.b ? QStringLiteral("true") : QStringLiteral("false");
+ *str = d->get<bool>() ? QStringLiteral("true") : QStringLiteral("false");
break;
case QMetaType::QByteArray:
*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();
break;
case QMetaType::Double:
- *ba = QByteArray::number(d->data.d, 'g', QLocale::FloatingPointShortest);
+ *ba = QByteArray::number(d->get<double>(), 'g', QLocale::FloatingPointShortest);
break;
case QMetaType::Float:
- *ba = QByteArray::number(d->data.f, 'g', QLocale::FloatingPointShortest);
+ *ba = QByteArray::number(d->get<float>(), 'g', QLocale::FloatingPointShortest);
break;
case QMetaType::Char:
case QMetaType::SChar:
case QMetaType::UChar:
- *ba = QByteArray(1, d->data.c);
+ *ba = QByteArray(1, d->get<char>());
break;
case QMetaType::Int:
case QMetaType::LongLong:
@@ -662,7 +652,7 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*ba = QByteArray::number(qMetaTypeUNumber(d));
break;
case QMetaType::Bool:
- *ba = QByteArray(d->data.b ? "true" : "false");
+ *ba = QByteArray(d->get<bool>() ? "true" : "false");
break;
case QMetaType::QUuid:
*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);
return ok;
case QMetaType::Bool:
- *f = double(d->data.b);
+ *f = double(d->get<bool>());
break;
case QMetaType::Float:
- *f = double(d->data.f);
+ *f = double(d->get<float>());
break;
case QMetaType::LongLong:
case QMetaType::Int:
@@ -831,10 +821,10 @@ static bool convert(const QVariant::Private *d, int t, void *result)
*f = d->get<QByteArray>().toFloat(&ok);
return ok;
case QMetaType::Bool:
- *f = float(d->data.b);
+ *f = float(d->get<bool>());
break;
case QMetaType::Double:
- *f = float(d->data.d);
+ *f = float(d->get<double>());
break;
case QMetaType::LongLong:
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);
break;
case QMetaType::Bool:
- *static_cast<QJsonValue *>(result) = QJsonValue(d->data.b);
+ *static_cast<QJsonValue *>(result) = QJsonValue(d->get<bool>());
break;
case QMetaType::Int:
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);
break;
case QMetaType::Bool:
- *static_cast<QCborValue *>(result) = QCborValue(d->data.b);
+ *static_cast<QCborValue *>(result) = QCborValue(d->get<bool>());
break;
case QMetaType::Int:
case QMetaType::UInt:
@@ -1366,8 +1356,7 @@ static void customConstruct(QVariant::Private *d, const void *copy)
return;
}
- // this logic should match with QVariantIntegrator::CanUseInternalSpace
- if (size <= sizeof(QVariant::Private::Data)) {
+ if (QVariant::Private::canUseInternalSpace(size)) {
type.construct(&d->data, copy);
d->is_shared = false;
} else {
@@ -1929,25 +1918,25 @@ QVariant::QVariant(QMetaType type, const void *copy) : d(type)
QVariant::QVariant(int val)
: d(Int)
-{ d.data.i = val; }
+{ d.set(val); }
QVariant::QVariant(uint val)
: d(UInt)
-{ d.data.u = val; }
+{ d.set(val); }
QVariant::QVariant(qlonglong val)
: d(LongLong)
-{ d.data.ll = val; }
+{ d.set(val); }
QVariant::QVariant(qulonglong val)
: d(ULongLong)
-{ d.data.ull = val; }
+{ d.set(val); }
QVariant::QVariant(bool val)
: d(Bool)
-{ d.data.b = val; }
+{ d.set(val); }
QVariant::QVariant(double val)
: d(Double)
-{ d.data.d = val; }
+{ d.set(val); }
QVariant::QVariant(float val)
: d(QMetaType::Float)
-{ d.data.f = val; }
+{ d.set(val); }
QVariant::QVariant(const QByteArray &val)
: d(ByteArray)
@@ -2474,7 +2463,7 @@ inline T qVariantToHelper(const QVariant::Private &d)
T ret;
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()))
return ret;
}
@@ -2908,7 +2897,7 @@ inline T qNumVariantToHelper(const QVariant::Private &d, bool *ok, const T& val)
T ret = 0;
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;
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
{
- 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
{
- 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
{
- 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
{
- 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
{
if (d.type() == QMetaType::fromType<bool>())
- return d.data.b;
+ return d.get<bool>();
bool res = false;
@@ -3039,7 +3028,7 @@ bool QVariant::toBool() 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
{
- 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
{
- 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) {
targetTypeId = QMetaType::Int;
} 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))
|| QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration;
case QMetaType::QObjectStar:
- return canConvertMetaObject(currentType, targetTypeId, d.data.o);
+ return canConvertMetaObject(currentType, targetTypeId, d.get<QObject *>());
default:
return false;
}
@@ -3553,7 +3542,7 @@ bool QVariant::convert(int targetTypeId)
return false;
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;
}
@@ -3821,7 +3810,7 @@ bool QVariant::equals(const QVariant &v) const
if (!metatype.isValid())
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())
return true;
- if (metaType().flags() & QMetaType::IsPointer) {
- const void *d_ptr = d.is_shared ? d.data.shared->data() : &(d.data);
- return *static_cast<void *const *>(d_ptr) == nullptr;
- }
+ if (metaType().flags() & QMetaType::IsPointer)
+ return d.get<void *>() == nullptr;
return false;
}
@@ -3874,7 +3861,7 @@ QDebug operator<<(QDebug dbg, const QVariant &v)
dbg.nospace() << "QVariant(";
if (typeId != QMetaType::UnknownType) {
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>())
dbg << v.toString();
} else {
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 419aefd081..258dac3bbc 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -352,7 +352,7 @@ class Q_CORE_EXPORT QVariant
void *data();
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(); }
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
{
- 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)
{
if (type.d_ptr)
@@ -468,45 +482,19 @@ class Q_CORE_EXPORT QVariant
}
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
- { return is_shared ? data.shared->data() : &data; }
+ { return is_shared ? data.shared->data() : &data.data; }
const void *internalStorage() const
- { Q_ASSERT(is_shared); return &data; }
+ { Q_ASSERT(is_shared); return &data.data; }
// determine internal storage at compile time
template<typename T>
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
{
@@ -750,7 +738,7 @@ namespace QtPrivate {
static T object(const QVariant &v)
{
return qobject_cast<T>(QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject
- ? v.d.data.o
+ ? v.d.get<QObject *>()
: QVariantValueHelper::metaType(v));
}
#endif
diff --git a/tests/benchmarks/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/benchmarks/corelib/kernel/qvariant/tst_qvariant.cpp
index d3c779b3aa..be77cf5d6c 100644
--- a/tests/benchmarks/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/benchmarks/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -91,7 +91,7 @@ struct BigClass
{
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
Q_DECLARE_TYPEINFO(BigClass, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
@@ -101,7 +101,7 @@ struct SmallClass
{
char s;
};
-static_assert(sizeof(SmallClass) <= sizeof(QVariant::Private::Data));
+static_assert(sizeof(SmallClass) <= sizeof(QVariant::Private::MaxInternalSize));
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(SmallClass, Q_MOVABLE_TYPE);
QT_END_NAMESPACE