+template<class Filter>
+class QVariantIsNull
+{
+ /// \internal
+ /// This class checks if a type T has method called isNull. Result is kept in the Value property
+ /// TODO Can we somehow generalize it? A macro version?
+ template<typename T, bool IsClass = QTypeInfo<T>::isComplex>
+ class HasIsNullMethod
+ {
+ struct Yes { char unused[1]; };
+ struct No { char unused[2]; };
+ Q_STATIC_ASSERT(sizeof(Yes) != sizeof(No));
+
+ struct FallbackMixin { bool isNull() const; };
+ struct Derived : public T, public FallbackMixin {};
+ template<class C, C> struct TypeCheck {};
+
+ template<class C> static Yes test(...);
+ template<class C> static No test(TypeCheck<bool (FallbackMixin::*)() const, &C::isNull> *);
+ public:
+ static const bool Value = (sizeof(test<Derived>(0)) == sizeof(Yes));
+ };
+
+ // We need to exclude primitive types as they won't compile with HasIsNullMethod::Check classes
+ // anyway it is not a problem as the types do not have isNull method.
+ template<typename T>
+ class HasIsNullMethod<T, /* IsClass = */ false> {
+ public:
+ static const bool Value = false;
+ };
+
+ // TODO This part should go to autotests during HasIsNullMethod generalization.
+ Q_STATIC_ASSERT(!HasIsNullMethod<bool>::Value);
+ struct SelfTest1 { bool isNull() const; };
+ Q_STATIC_ASSERT(HasIsNullMethod<SelfTest1>::Value);
+ struct SelfTest2 {};
+ Q_STATIC_ASSERT(!HasIsNullMethod<SelfTest2>::Value);
+ struct SelfTest3 : public SelfTest1 {};
+ Q_STATIC_ASSERT(HasIsNullMethod<SelfTest3>::Value);
+
+ template<typename T, bool HasIsNull = HasIsNullMethod<T>::Value>
+ struct CallFilteredIsNull
+ {
+ static bool isNull(const QVariant::Private *d)
+ {
+ return v_cast<T>(d)->isNull();
+ }
+ };
+ template<typename T>
+ struct CallFilteredIsNull<T, /* HasIsNull = */ false>
+ {
+ static bool isNull(const QVariant::Private *d)
+ {
+ return d->is_null;
+ }
+ };
+
+ template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
+ struct CallIsNull
+ {
+ static bool isNull(const QVariant::Private *d)
+ {
+ return CallFilteredIsNull<T>::isNull(d);
+ }
+ };
+ template<typename T>
+ struct CallIsNull<T, /* IsAcceptedType = */ false>
+ {
+ static bool isNull(const QVariant::Private *d)
+ {
+ return CallFilteredIsNull<T, false>::isNull(d);
+ }
+ };
+
+public:
+ QVariantIsNull(const QVariant::Private *d)
+ : m_d(d)
+ {}
+ template<typename T>
+ bool delegate(const T*)
+ {
+ CallIsNull<T> null;
+ return null.isNull(m_d);
+ }
+ // we need that as sizof(void) is undefined and it is needed in HasIsNullMethod
+ bool delegate(const void *) { return m_d->is_null; }
+protected:
+ const QVariant::Private *m_d;
+};
+
+template<class Filter>
+class QVariantConstructor
+{
+ template<typename T, bool IsSmall = (sizeof(T) <= sizeof(QVariant::Private::Data))>
+ struct CallConstructor {};
+
+ template<typename T>
+ struct CallConstructor<T, /* IsSmall = */ true>
+ {
+ CallConstructor(const QVariantConstructor &tc)
+ {
+ if (tc.m_copy)
+ new (&tc.m_x->data.ptr) T(*static_cast<const T*>(tc.m_copy));
+ else
+ new (&tc.m_x->data.ptr) T();
+ tc.m_x->is_shared = false;
+ }
+ };
+
+ template<typename T>
+ struct CallConstructor<T, /* IsSmall = */ false>
+ {
+ CallConstructor(const QVariantConstructor &tc)
+ {
+ Q_STATIC_ASSERT(QTypeInfo<T>::isComplex);
+ tc.m_x->data.shared = tc.m_copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T*>(tc.m_copy))
+ : new QVariantPrivateSharedEx<T>;
+ tc.m_x->is_shared = true;
+ }
+ };
+
+ template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
+ struct FilteredConstructor {
+ FilteredConstructor(const QVariantConstructor &tc)
+ {
+ CallConstructor<T> tmp(tc);
+ 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 = QVariant::Invalid;
+ }
+ };
+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::UnknownType*)
+ {
+ if (m_x->type == QVariant::UserType) {
+ // TODO get rid of it
+ // And yes! we can support historical magic, unkonwn/unconstructed user type isn't that
+ // awesome? this QVariant::isValid will be true!
+ m_x->is_null = !m_copy;
+ 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 && 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;
+ }
+ 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);
+ }
+ }
+ }
+
+ void delegate(const void*)
+ {
+ // QMetaType::Void == QVariant::Invalid, creating an invalid value creates invalid QVariant
+ // TODO it might go away, check is needed
+ 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 *) {} // ignore non accessible types
+ };
+
+public:
+ QVariantDestructor(QVariant::Private *d)
+ : m_d(d)
+ {}
+ ~QVariantDestructor()
+ {
+ m_d->type = QVariant::Invalid;
+ 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::UnknownType*)
+ {
+ // This is not a static type, so lets delegate everyting to QMetaType
+ if (!m_d->is_shared) {
+ QMetaType::destruct(m_d->type, &m_d->data.ptr);
+ } else {
+ QMetaType::destroy(m_d->type, m_d->data.shared->ptr);
+ delete m_d->data.shared;
+ }
+ }
+ // Ignore nonconstructible type
+ void delegate(const void*) {}
+private:
+ QVariant::Private *m_d;
+};
+