#include <QtCore/qglobal.h>
#include <QtCore/qvariant.h>
+#include <QtCore/private/qmetatype_p.h>
#include "qmetatypeswitcher_p.h"
QT_BEGIN_NAMESPACE
+namespace {
+template<typename T>
+struct QVariantIntegrator
+{
+ static const bool CanUseInternalSpace = sizeof(T) <= sizeof(QVariant::Private::Data)
+ && (!QTypeInfo<T>::isStatic);
+};
+Q_STATIC_ASSERT(QVariantIntegrator<double>::CanUseInternalSpace);
+Q_STATIC_ASSERT(QVariantIntegrator<long int>::CanUseInternalSpace);
+Q_STATIC_ASSERT(QVariantIntegrator<qulonglong>::CanUseInternalSpace);
+} // namespace
+
#ifdef Q_CC_SUN // Sun CC picks the wrong overload, so introduce awful hack
template <typename T>
inline T *v_cast(const QVariant::Private *nd, T * = 0)
{
QVariant::Private *d = const_cast<QVariant::Private *>(nd);
- return ((sizeof(T) > sizeof(QVariant::Private::Data))
+ return !QVariantIntegrator<T>::CanUseInternalSpace
? static_cast<T *>(d->data.shared->ptr)
- : static_cast<T *>(static_cast<void *>(&d->data.c)));
+ : static_cast<T *>(static_cast<void *>(&d->data.c));
}
#else // every other compiler in this world
template <typename T>
inline const T *v_cast(const QVariant::Private *d, T * = 0)
{
- return ((sizeof(T) > sizeof(QVariant::Private::Data))
+ return !QVariantIntegrator<T>::CanUseInternalSpace
? static_cast<const T *>(d->data.shared->ptr)
- : static_cast<const T *>(static_cast<const void *>(&d->data.c)));
+ : static_cast<const T *>(static_cast<const void *>(&d->data.c));
}
template <typename T>
inline T *v_cast(QVariant::Private *d, T * = 0)
{
- return ((sizeof(T) > sizeof(QVariant::Private::Data))
+ return !QVariantIntegrator<T>::CanUseInternalSpace
? static_cast<T *>(d->data.shared->ptr)
- : static_cast<T *>(static_cast<void *>(&d->data.c)));
+ : static_cast<T *>(static_cast<void *>(&d->data.c));
}
#endif
template <class T>
inline void v_construct(QVariant::Private *x, const void *copy, T * = 0)
{
- if (sizeof(T) > sizeof(QVariant::Private::Data)) {
+ if (!QVariantIntegrator<T>::CanUseInternalSpace) {
x->data.shared = copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T *>(copy))
: new QVariantPrivateSharedEx<T>;
x->is_shared = true;
template <class T>
inline void v_construct(QVariant::Private *x, const T &t)
{
- if (sizeof(T) > sizeof(QVariant::Private::Data)) {
+ if (!QVariantIntegrator<T>::CanUseInternalSpace) {
x->data.shared = new QVariantPrivateSharedEx<T>(t);
x->is_shared = true;
} else {
inline void v_clear(QVariant::Private *d, T* = 0)
{
- if (sizeof(T) > sizeof(QVariant::Private::Data)) {
+ if (!QVariantIntegrator<T>::CanUseInternalSpace) {
//now we need to cast
//because QVariant::PrivateShared doesn't have a virtual destructor
delete static_cast<QVariantPrivateSharedEx<T>*>(d->data.shared);
template<class Filter>
class QVariantConstructor
{
- template<typename T, bool IsSmall = (sizeof(T) <= sizeof(QVariant::Private::Data))>
+ template<typename T, bool CanUseInternalSpace = QVariantIntegrator<T>::CanUseInternalSpace>
struct CallConstructor {};
template<typename T>
- struct CallConstructor<T, /* IsSmall = */ true>
+ struct CallConstructor<T, /* CanUseInternalSpace = */ true>
{
CallConstructor(const QVariantConstructor &tc)
{
};
template<typename T>
- struct CallConstructor<T, /* IsSmall = */ false>
+ struct CallConstructor<T, /* CanUseInternalSpace = */ false>
{
CallConstructor(const QVariantConstructor &tc)
{
m_x->is_shared = false;
return;
}
- // it is not a static known type, lets ask QMetaType if it can be constructed for us.
const uint size = QMetaType::sizeOf(m_x->type);
+ if (!size) {
+ m_x->type = QVariant::Invalid;
+ return;
+ }
- if (size && size <= sizeof(QVariant::Private::Data)) {
- void *ptr = QMetaType::construct(m_x->type, &m_x->data.ptr, m_copy);
- if (!ptr) {
- m_x->type = QVariant::Invalid;
- }
+ // this logic should match with QVariantIntegrator::CanUseInternalSpace
+ if (size <= sizeof(QVariant::Private::Data)
+ && (QMetaType::typeFlags(m_x->type) & QMetaType::MovableType)) {
+ QMetaType::construct(m_x->type, &m_x->data.ptr, m_copy);
m_x->is_shared = false;
} else {
void *ptr = QMetaType::create(m_x->type, m_copy);
- if (!ptr) {
- m_x->type = QVariant::Invalid;
- } else {
- m_x->is_shared = true;
- m_x->data.shared = new QVariant::PrivateShared(ptr);
- }
+ m_x->is_shared = true;
+ m_x->data.shared = new QVariant::PrivateShared(ptr);
}
}
void numericalConvert();
void moreCustomTypes();
+ void movabilityTest();
void variantInVariant();
void colorInteger();
QVariant userVar3;
qVariantSetValue(userVar3, data2);
- QVERIFY(userVar2 == userVar3);
+
userVar3 = userVar2;
QVERIFY(userVar2 == userVar3);
}
QCOMPARE(instanceCount, 3);
{
QVariant second = myCarrier;
- QCOMPARE(instanceCount, 4);
+ QCOMPARE(instanceCount, 3);
second.detach();
QCOMPARE(instanceCount, 4);
}
QCOMPARE(MyMovable::count, 0);
}
+void tst_QVariant::movabilityTest()
+{
+ // This test checks if QVariant is movable even if an internal data is not movable.
+ QVERIFY(!MyNotMovable::count);
+ {
+ QVariant variant = QVariant::fromValue(MyNotMovable());
+ QVERIFY(MyNotMovable::count);
+
+ // prepare destination memory space to which variant will be moved
+ QVariant buffer[1];
+ QCOMPARE(buffer[0].type(), QVariant::Invalid);
+ buffer[0].~QVariant();
+
+ memcpy(buffer, &variant, sizeof(QVariant));
+ QCOMPARE(buffer[0].type(), QVariant::UserType);
+ MyNotMovable tmp(buffer[0].value<MyNotMovable>());
+
+ new (&variant) QVariant();
+ }
+ QVERIFY(!MyNotMovable::count);
+}
void tst_QVariant::variantInVariant()
{