Use the new QMetaType API in QVariant

Change-Id: I5495ee1159864ebd64083fadbfac7e07177ed406
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Olivier Goffart 2019-12-09 10:37:28 +01:00
parent 5e908ada67
commit a68e4f3b96
10 changed files with 296 additions and 441 deletions

View File

@ -660,12 +660,7 @@ void QMetaType::destruct(void *data) const
}
}
/*!
\fn QMetaType::~QMetaType()
Destructs this object.
*/
QMetaType::~QMetaType()
void QtMetaTypePrivate::derefAndDestroy(QtPrivate::QMetaTypeInterface *d_ptr)
{
if (d_ptr && !d_ptr->ref.deref()) {
if (auto reg = customTypeRegistery())
@ -675,6 +670,16 @@ QMetaType::~QMetaType()
}
}
/*!
\fn QMetaType::~QMetaType()
Destructs this object.
*/
QMetaType::~QMetaType()
{
QtMetaTypePrivate::derefAndDestroy(d_ptr);
}
QMetaType::QMetaType(QtPrivate::QMetaTypeInterface *d) : d_ptr(d)
{
if (d_ptr)

View File

@ -495,7 +495,8 @@ public:
TrackingPointerToQObject = 0x80,
WasDeclaredAsMetaType = 0x100,
IsGadget = 0x200,
PointerToGadget = 0x400
PointerToGadget = 0x400,
IsPointer = 0x800,
};
Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
@ -692,6 +693,7 @@ public:
static bool registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to);
static void unregisterConverterFunction(int from, int to);
private:
friend class QVariant;
QtPrivate::QMetaTypeInterface *d_ptr = nullptr;
};
@ -1708,6 +1710,7 @@ namespace QtPrivate {
| (std::is_enum<T>::value ? QMetaType::IsEnumeration : 0)
| (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0)
| (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0)
| (QTypeInfo<T>::isPointer ? QMetaType::IsPointer : 0)
};
};

View File

@ -217,6 +217,8 @@ static QtPrivate::QMetaTypeInterface *getInterfaceFromType()
QtMetaTypePrivate::QMetaTypeFunctionHelper<RealName, QtMetaTypePrivate::TypeDefinition<RealName>::IsAvailable>::Load(stream, data); \
return true;
void derefAndDestroy(QtPrivate::QMetaTypeInterface *d_ptr);
} //namespace QtMetaTypePrivate
QT_END_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -210,8 +210,8 @@ class Q_CORE_EXPORT QVariant
QVariant() noexcept : d() {}
~QVariant();
QVariant(Type type);
QVariant(int typeId, const void *copy);
QVariant(int typeId, const void *copy, uint flags);
QVariant(int typeId, const void *copy, uint flags = 0); // ### Qt6 TODO deprecate
explicit QVariant(QMetaType type, const void *copy);
QVariant(const QVariant &other);
#ifndef QT_NO_DATASTREAM
@ -285,6 +285,7 @@ class Q_CORE_EXPORT QVariant
Type type() const;
int userType() const;
const char *typeName() const;
QMetaType metaType() const;
bool canConvert(int targetTypeId) const;
bool convert(int targetTypeId);
@ -370,7 +371,9 @@ class Q_CORE_EXPORT QVariant
template<typename T>
static inline QVariant fromValue(const T &value)
{ return QVariant(qMetaTypeId<T>(), &value, QTypeInfo<T>::isPointer); }
{
return QVariant(QMetaType::fromType<T>(), &value);
}
#if (__has_include(<variant>) && __cplusplus >= 201703L) || defined(Q_CLANG_QDOC)
template<typename... Types>
@ -395,21 +398,32 @@ class Q_CORE_EXPORT QVariant
};
struct Private
{
inline Private() noexcept : type(Invalid), is_shared(false), is_null(true)
{}
Private() noexcept : packedType(0), is_shared(false), is_null(true) {}
explicit Private(const QMetaType &type) noexcept : is_shared(false), is_null(false)
{
if (type.d_ptr)
type.d_ptr->ref.ref();
quintptr mt = quintptr(type.d_ptr);
Q_ASSERT((mt & 0x3) == 0);
packedType = mt >> 2;
}
explicit Private(int type) noexcept : Private(QMetaType(type)) {}
Private(const Private &other) : Private(other.type())
{
data = other.data;
is_shared = other.is_shared;
is_null = other.is_null;
}
Private &operator=(const Private &other)
{
if (&other != this) {
this->~Private();
new (this) Private(other);
}
return *this;
}
Q_CORE_EXPORT ~Private();
// Internal constructor for initialized variants.
explicit inline Private(uint variantType) noexcept
: type(variantType), is_shared(false), is_null(false)
{}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Private(const Private &other) noexcept
: data(other.data), type(other.type),
is_shared(other.is_shared), is_null(other.is_null)
{}
Private &operator=(const Private &other) noexcept = default;
#endif
union Data
{
void *threeptr[3] = { nullptr, nullptr, nullptr };
@ -432,13 +446,15 @@ class Q_CORE_EXPORT QVariant
void *ptr;
PrivateShared *shared;
} data;
uint type : 30;
uint is_shared : 1;
uint is_null : 1;
quintptr packedType : sizeof(QMetaType) * 8 - 2;
quintptr is_shared : 1;
quintptr is_null : 1;
inline QMetaType type() const
{
return QMetaType(reinterpret_cast<QtPrivate::QMetaTypeInterface *>(packedType << 2));
}
};
public:
typedef void (*f_construct)(Private *, const void *);
typedef void (*f_clear)(Private *);
typedef bool (*f_null)(const Private *);
#ifndef QT_NO_DATASTREAM
typedef void (*f_load)(Private *, QDataStream &);
@ -449,8 +465,6 @@ class Q_CORE_EXPORT QVariant
typedef bool (*f_canConvert)(const QVariant::Private *d, int t);
typedef void (*f_debugStream)(QDebug, const QVariant &);
struct Handler {
f_construct construct;
f_clear clear;
f_null isNull;
#ifndef QT_NO_DATASTREAM
f_load load;
@ -546,22 +560,20 @@ inline QVariant QVariant::fromValue(const std::monostate &)
}
#endif
inline bool QVariant::isValid() const { return d.type != Invalid; }
inline bool QVariant::isValid() const
{
return d.type().isValid();
}
template<typename T>
inline void QVariant::setValue(const T &avalue)
{
QMetaType metaType = QMetaType::fromType<T>();
// If possible we reuse the current QVariant private.
const uint type = qMetaTypeId<T>();
if (isDetached() && (type == d.type || (type <= uint(QVariant::Char) && d.type <= uint(QVariant::Char)))) {
d.type = type;
d.is_null = false;
T *old = reinterpret_cast<T*>(d.is_shared ? d.data.shared->ptr : &d.data.ptr);
if (QTypeInfo<T>::isComplex)
old->~T();
new (old) T(avalue); // call the copy constructor
if (isDetached() && d.type() == metaType) {
*reinterpret_cast<T *>(data()) = avalue;
} else {
*this = QVariant(type, &avalue, QTypeInfo<T>::isPointer);
*this = QVariant::fromValue<T>(avalue);
}
}

View File

@ -234,7 +234,7 @@ public:
QVariantComparator(const QVariant::Private *a, const QVariant::Private *b)
: m_a(a), m_b(b)
{
Q_ASSERT(a->type == b->type);
Q_ASSERT(a->type() == b->type());
}
template<typename T>
@ -346,113 +346,6 @@ protected:
const QVariant::Private *m_d;
};
template<class Filter>
class QVariantConstructor
{
template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
struct FilteredConstructor {
FilteredConstructor(const QVariantConstructor &tc)
{
v_construct<T>(tc.m_x, tc.m_copy);
tc.m_x->is_null = !tc.m_copy;
}
};
template<typename T>
struct FilteredConstructor<T, /* IsAcceptedType = */ false> {
FilteredConstructor(const QVariantConstructor &tc)
{
// ignore types that lives outside of the current library
tc.m_x->type = QMetaType::UnknownType;
}
};
public:
QVariantConstructor(QVariant::Private *x, const void *copy)
: m_x(x)
, m_copy(copy)
{}
template<typename T>
void delegate(const T*)
{
FilteredConstructor<T>(*this);
}
void delegate(const QMetaTypeSwitcher::NotBuiltinType*)
{
// QVariantConstructor is used only for built-in types.
Q_ASSERT(false);
}
void delegate(const void*)
{
qWarning("Trying to create a QVariant instance of QMetaType::Void type, an invalid QVariant will be constructed instead");
m_x->type = QMetaType::UnknownType;
m_x->is_shared = false;
m_x->is_null = !m_copy;
}
void delegate(const QMetaTypeSwitcher::UnknownType*)
{
if (m_x->type != QMetaType::UnknownType) {
qWarning("Trying to construct an instance of an invalid type, type id: %i", m_x->type);
m_x->type = QMetaType::UnknownType;
}
m_x->is_shared = false;
m_x->is_null = !m_copy;
}
private:
QVariant::Private *m_x;
const void *m_copy;
};
template<class Filter>
class QVariantDestructor
{
template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
struct FilteredDestructor {
FilteredDestructor(QVariant::Private *d)
{
v_clear<T>(d);
}
};
template<typename T>
struct FilteredDestructor<T, /* IsAcceptedType = */ false> {
FilteredDestructor(QVariant::Private *)
{
// It is not possible to create not accepted type
Q_ASSERT(false);
}
};
public:
QVariantDestructor(QVariant::Private *d)
: m_d(d)
{}
~QVariantDestructor()
{
m_d->type = QMetaType::UnknownType;
m_d->is_null = true;
m_d->is_shared = false;
}
template<typename T>
void delegate(const T*)
{
FilteredDestructor<T> cleaner(m_d);
}
void delegate(const QMetaTypeSwitcher::NotBuiltinType*)
{
// QVariantDestructor class is used only for a built-in type
Q_ASSERT(false);
}
// Ignore nonconstructible type
void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const void*) { Q_ASSERT(false); }
private:
QVariant::Private *m_d;
};
namespace QVariantPrivate {
Q_CORE_EXPORT void registerHandler(const int /* Modules::Names */ name, const QVariant::Handler *handler);
}

View File

@ -101,19 +101,6 @@ struct GuiTypesFilter {
};
};
static void construct(QVariant::Private *x, const void *copy)
{
const int type = x->type;
QVariantConstructor<GuiTypesFilter> constructor(x, copy);
QMetaTypeSwitcher::switcher<void>(constructor, type, nullptr);
}
static void clear(QVariant::Private *d)
{
QVariantDestructor<GuiTypesFilter> destructor(d);
QMetaTypeSwitcher::switcher<void>(destructor, d->type, nullptr);
}
// This class is a hack that customizes access to QPolygon and QPolygonF
template<class Filter>
class QGuiVariantIsNull : public QVariantIsNull<Filter> {
@ -131,7 +118,7 @@ public:
static bool isNull(const QVariant::Private *d)
{
QGuiVariantIsNull<GuiTypesFilter> isNull(d);
return QMetaTypeSwitcher::switcher<bool>(isNull, d->type, nullptr);
return QMetaTypeSwitcher::switcher<bool>(isNull, d->type().id(), nullptr);
}
// This class is a hack that customizes access to QPixmap, QBitmap, QCursor and QIcon
@ -173,7 +160,7 @@ public:
static bool compare(const QVariant::Private *a, const QVariant::Private *b)
{
QGuiVariantComparator<GuiTypesFilter> comparator(a, b);
return QMetaTypeSwitcher::switcher<bool>(comparator, a->type, nullptr);
return QMetaTypeSwitcher::switcher<bool>(comparator, a->type().id(), nullptr);
}
static bool convert(const QVariant::Private *d, int t,
@ -181,7 +168,7 @@ static bool convert(const QVariant::Private *d, int t,
{
switch (t) {
case QMetaType::QByteArray:
if (d->type == QMetaType::QColor) {
if (d->type().id() == QMetaType::QColor) {
const QColor *c = v_cast<QColor>(d);
*static_cast<QByteArray *>(result) = c->name(c->alpha() != 255 ? QColor::HexArgb : QColor::HexRgb).toLatin1();
return true;
@ -189,7 +176,7 @@ static bool convert(const QVariant::Private *d, int t,
break;
case QMetaType::QString: {
QString *str = static_cast<QString *>(result);
switch (d->type) {
switch (d->type().id()) {
#if QT_CONFIG(shortcut)
case QMetaType::QKeySequence:
*str = (*v_cast<QKeySequence>(d)).toString(QKeySequence::NativeText);
@ -209,13 +196,13 @@ static bool convert(const QVariant::Private *d, int t,
break;
}
case QMetaType::QPixmap:
if (d->type == QMetaType::QImage) {
if (d->type().id() == QMetaType::QImage) {
*static_cast<QPixmap *>(result) = QPixmap::fromImage(*v_cast<QImage>(d));
return true;
} else if (d->type == QMetaType::QBitmap) {
} else if (d->type().id() == QMetaType::QBitmap) {
*static_cast<QPixmap *>(result) = *v_cast<QBitmap>(d);
return true;
} else if (d->type == QMetaType::QBrush) {
} else if (d->type().id() == QMetaType::QBrush) {
if (v_cast<QBrush>(d)->style() == Qt::TexturePattern) {
*static_cast<QPixmap *>(result) = v_cast<QBrush>(d)->texture();
return true;
@ -223,26 +210,26 @@ static bool convert(const QVariant::Private *d, int t,
}
break;
case QMetaType::QImage:
if (d->type == QMetaType::QPixmap) {
if (d->type().id() == QMetaType::QPixmap) {
*static_cast<QImage *>(result) = v_cast<QPixmap>(d)->toImage();
return true;
} else if (d->type == QMetaType::QBitmap) {
} else if (d->type().id() == QMetaType::QBitmap) {
*static_cast<QImage *>(result) = v_cast<QBitmap>(d)->toImage();
return true;
}
break;
case QMetaType::QBitmap:
if (d->type == QMetaType::QPixmap) {
if (d->type().id() == QMetaType::QPixmap) {
*static_cast<QBitmap *>(result) = *v_cast<QPixmap>(d);
return true;
} else if (d->type == QMetaType::QImage) {
} else if (d->type().id() == QMetaType::QImage) {
*static_cast<QBitmap *>(result) = QBitmap::fromImage(*v_cast<QImage>(d));
return true;
}
break;
#if QT_CONFIG(shortcut)
case QMetaType::Int:
if (d->type == QMetaType::QKeySequence) {
if (d->type().id() == QMetaType::QKeySequence) {
const QKeySequence &seq = *v_cast<QKeySequence>(d);
*static_cast<int *>(result) = seq.isEmpty() ? 0 : seq[0];
return true;
@ -250,20 +237,20 @@ static bool convert(const QVariant::Private *d, int t,
break;
#endif
case QMetaType::QFont:
if (d->type == QMetaType::QString) {
if (d->type().id() == QMetaType::QString) {
QFont *f = static_cast<QFont *>(result);
f->fromString(*v_cast<QString>(d));
return true;
}
break;
case QMetaType::QColor:
if (d->type == QMetaType::QString) {
if (d->type().id() == QMetaType::QString) {
static_cast<QColor *>(result)->setNamedColor(*v_cast<QString>(d));
return static_cast<QColor *>(result)->isValid();
} else if (d->type == QMetaType::QByteArray) {
} else if (d->type().id() == QMetaType::QByteArray) {
static_cast<QColor *>(result)->setNamedColor(QLatin1String(*v_cast<QByteArray>(d)));
return true;
} else if (d->type == QMetaType::QBrush) {
} else if (d->type().id() == QMetaType::QBrush) {
if (v_cast<QBrush>(d)->style() == Qt::SolidPattern) {
*static_cast<QColor *>(result) = v_cast<QBrush>(d)->color();
return true;
@ -271,10 +258,10 @@ static bool convert(const QVariant::Private *d, int t,
}
break;
case QMetaType::QBrush:
if (d->type == QMetaType::QColor) {
if (d->type().id() == QMetaType::QColor) {
*static_cast<QBrush *>(result) = QBrush(*v_cast<QColor>(d));
return true;
} else if (d->type == QMetaType::QPixmap) {
} else if (d->type().id() == QMetaType::QPixmap) {
*static_cast<QBrush *>(result) = QBrush(*v_cast<QPixmap>(d));
return true;
}
@ -282,7 +269,7 @@ static bool convert(const QVariant::Private *d, int t,
#if QT_CONFIG(shortcut)
case QMetaType::QKeySequence: {
QKeySequence *seq = static_cast<QKeySequence *>(result);
switch (d->type) {
switch (d->type().id()) {
case QMetaType::QString:
*seq = QKeySequence(*v_cast<QString>(d));
return true;
@ -313,13 +300,11 @@ static void streamDebug(QDebug dbg, const QVariant &v)
{
QVariant::Private *d = const_cast<QVariant::Private *>(&v.data_ptr());
QVariantDebugStream<GuiTypesFilter> stream(dbg, d);
QMetaTypeSwitcher::switcher<void>(stream, d->type, nullptr);
QMetaTypeSwitcher::switcher<void>(stream, d->type().id(), nullptr);
}
#endif
const QVariant::Handler qt_gui_variant_handler = {
construct,
clear,
isNull,
#ifndef QT_NO_DATASTREAM
nullptr,

View File

@ -48,36 +48,6 @@
QT_BEGIN_NAMESPACE
namespace {
static void construct(QVariant::Private *x, const void *copy)
{
switch (x->type) {
case QMetaType::QSizePolicy:
v_construct<QSizePolicy>(x, copy);
break;
default:
qWarning("Trying to construct an instance of an invalid type, type id: %i", x->type);
x->type = QMetaType::UnknownType;
return;
}
x->is_null = !copy;
}
static void clear(QVariant::Private *d)
{
switch (d->type) {
case QMetaType::QSizePolicy:
v_clear<QSizePolicy>(d);
break;
default:
Q_ASSERT(false);
return;
}
d->type = QMetaType::UnknownType;
d->is_null = true;
d->is_shared = false;
}
static bool isNull(const QVariant::Private *)
{
@ -86,8 +56,8 @@ static bool isNull(const QVariant::Private *)
static bool compare(const QVariant::Private *a, const QVariant::Private *b)
{
Q_ASSERT(a->type == b->type);
switch(a->type) {
Q_ASSERT(a->type() == b->type());
switch (a->type().id()) {
case QMetaType::QSizePolicy:
return *v_cast<QSizePolicy>(a) == *v_cast<QSizePolicy>(b);
default:
@ -110,19 +80,17 @@ static bool convert(const QVariant::Private *d, int type, void *result, bool *ok
static void streamDebug(QDebug dbg, const QVariant &v)
{
QVariant::Private *d = const_cast<QVariant::Private *>(&v.data_ptr());
switch (d->type) {
switch (d->type().id()) {
case QMetaType::QSizePolicy:
dbg.nospace() << *v_cast<QSizePolicy>(d);
break;
default:
dbg.nospace() << "QMetaType::Type(" << d->type << ')';
dbg.nospace() << "QMetaType::Type(" << d->type().id() << ')';
}
}
#endif
static const QVariant::Handler widgets_handler = {
construct,
clear,
isNull,
#ifndef QT_NO_DATASTREAM
nullptr,

View File

@ -349,13 +349,13 @@ void tst_QVariant::constructor_invalid()
QFETCH(uint, typeId);
{
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type, type id:"));
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type"));
QVariant variant(static_cast<QVariant::Type>(typeId));
QVERIFY(!variant.isValid());
QCOMPARE(variant.userType(), int(QMetaType::UnknownType));
}
{
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type, type id:"));
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type"));
QVariant variant(typeId, /* copy */ 0);
QVERIFY(!variant.isValid());
QCOMPARE(variant.userType(), int(QMetaType::UnknownType));
@ -1433,10 +1433,7 @@ void tst_QVariant::checkDataStream()
const int typeId = QMetaType::LastCoreType + 1;
QVERIFY(!QMetaType::isRegistered(typeId));
QByteArray errorMessage("Trying to construct an instance of an invalid type, type id: ");
errorMessage.append(QString::number(typeId, 10));
QTest::ignoreMessage(QtWarningMsg, errorMessage.constData());
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type"));
QByteArray settingsHex("000000");
settingsHex.append(QString::number(typeId, 16));
settingsHex.append("ffffffffff");
@ -2839,7 +2836,7 @@ void tst_QVariant::loadUnknownUserType()
void tst_QVariant::loadBrokenUserType()
{
QTest::ignoreMessage(QtWarningMsg, "Trying to construct an instance of an invalid type, type id: 127");
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type"));
char data[] = {0, 0, 0, 127, 0 };
QByteArray ba(data, sizeof(data));

View File

@ -272,6 +272,10 @@ void tst_QShaderNodesLoader::shouldLoadFromJsonStream_data()
QTest::newRow("NotOpen") << createBuffer(smallJson, QIODevice::NotOpen) << NodeHash() << QShaderNodesLoader::Error;
QTest::newRow("CorrectJSON") << createBuffer(smallJson) << smallProtos << QShaderNodesLoader::Ready;
// These types are normaly registered by QShaderGraphLoader
qRegisterMetaType<QShaderLanguage::StorageQualifier>();
qRegisterMetaType<QShaderLanguage::VariableType>();
}
void tst_QShaderNodesLoader::shouldLoadFromJsonStream()