diff options
author | Jędrzej Nowacki <jedrzej.nowacki@nokia.com> | 2011-11-29 15:42:33 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-01-04 14:25:25 +0100 |
commit | 08863b6fdaa8383e2274826db3ec42c4d4f11576 (patch) | |
tree | a3cc772ada845bffa60f5b186defeb469bf1f5af /src/corelib/kernel/qvariant.cpp | |
parent | 52fc6694b87e93fe0828424bb26d9279785de3e7 (diff) |
Refactor QVariant handlers.
QVariant implementation is based on delegation to a handler. The handler
has rather simple construction, it is a set of function that implements
a switch statement over known types and redirects calls to a right
method of an encapsulated types instance. Unfortunately after qt
modularization project, it is not easy to use types directly from
different modules, as they can be undefined or completely unaccessible.
Which means that each module has to implement own handler to cooperate
correctly with QVariant. We can suspect that list of modules known to
QVariant will grow and it is not limited to GUI, Widgets and Core,
therefore it would be nice to have an unified, from performance and
source code point of view, way of working with handlers.
This patch is an attempt to cleanup handlers. Keynotes:
- Each handler is working only on types defined in the same module
- Core handler implements handling of primitive types too
- Custom types have an own handler
- Each handler is independent which means that dispatch between handlers
is done on QVariant level
- Handlers might be registered / unregistered using same interface
Change-Id: Ib096df65e2c4ce464bc7a684aade5af7d1264c24
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Diffstat (limited to 'src/corelib/kernel/qvariant.cpp')
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 261 |
1 files changed, 211 insertions, 50 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 29717398a8..f898cc4823 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -74,6 +74,25 @@ QT_BEGIN_NAMESPACE #endif namespace { +class HandlersManager +{ + static const QVariant::Handler *Handlers[QModulesPrivate::ModulesCount]; +public: + const QVariant::Handler *operator[] (const int typeId) const + { + return Handlers[QModulesPrivate::moduleForType(typeId)]; + } + + void registerHandler(const QModulesPrivate::Names name, const QVariant::Handler *handler) + { + Handlers[name] = handler; + } + + inline void unregisterHandler(const QModulesPrivate::Names name); +}; +} // namespace + +namespace { template<typename T> struct TypeDefiniton { static const bool IsAvailable = true; @@ -100,7 +119,9 @@ struct CoreTypesFilter { static const bool IsAccepted = QTypeModuleInfo<T>::IsCore && TypeDefiniton<T>::IsAvailable; }; }; -} // namspace +} // annonymous used to hide TypeDefiniton + +namespace { // annonymous used to hide QVariant handlers static void construct(QVariant::Private *x, const void *copy) { @@ -813,13 +834,142 @@ const QVariant::Handler qt_kernel_variant_handler = { #endif }; +static void dummyConstruct(QVariant::Private *, const void *) { Q_ASSERT_X(false, "QVariant", "Trying to construct an unknown type"); } +static void dummyClear(QVariant::Private *) { Q_ASSERT_X(false, "QVariant", "Trying to clear an unknown type"); } +static bool dummyIsNull(const QVariant::Private *d) { Q_ASSERT_X(false, "QVariant::isNull", "Trying to call isNull on an unknown type"); return d->is_null; } +static bool dummyCompare(const QVariant::Private *, const QVariant::Private *) { Q_ASSERT_X(false, "QVariant", "Trying to compare an unknown types"); return false; } +static bool dummyConvert(const QVariant::Private *, QVariant::Type , void *, bool *) { Q_ASSERT_X(false, "QVariant", "Trying to convert an unknown type"); return false; } +#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) +static void dummyStreamDebug(QDebug, const QVariant &) { Q_ASSERT_X(false, "QVariant", "Trying to convert an unknown type"); } +#endif +const QVariant::Handler qt_dummy_variant_handler = { + dummyConstruct, + dummyClear, + dummyIsNull, +#ifndef QT_NO_DATASTREAM + 0, + 0, +#endif + dummyCompare, + dummyConvert, + 0, +#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) + dummyStreamDebug +#else + 0 +#endif +}; + +static void customConstruct(QVariant::Private *d, const void *copy) +{ + const uint size = QMetaType::sizeOf(d->type); + if (!size) { + d->type = QVariant::Invalid; + return; + } + + // this logic should match with QVariantIntegrator::CanUseInternalSpace + if (size <= sizeof(QVariant::Private::Data) + && (QMetaType::typeFlags(d->type) & QMetaType::MovableType)) { + QMetaType::construct(d->type, &d->data.ptr, copy); + d->is_shared = false; + } else { + void *ptr = QMetaType::create(d->type, copy); + d->is_shared = true; + d->data.shared = new QVariant::PrivateShared(ptr); + } +} + +static void customClear(QVariant::Private *d) +{ + if (!d->is_shared) { + QMetaType::destruct(d->type, &d->data.ptr); + } else { + QMetaType::destroy(d->type, d->data.shared->ptr); + delete d->data.shared; + } +} + +static bool customIsNull(const QVariant::Private *d) +{ + return d->is_null; +} + +static bool customCompare(const QVariant::Private *a, const QVariant::Private *b) +{ + const char *const typeName = QMetaType::typeName(a->type); + if (Q_UNLIKELY(!typeName) && Q_LIKELY(!QMetaType::isRegistered(a->type))) + qFatal("QVariant::compare: type %d unknown to QVariant.", a->type); + + const void *a_ptr = a->is_shared ? a->data.shared->ptr : &(a->data.ptr); + const void *b_ptr = b->is_shared ? b->data.shared->ptr : &(b->data.ptr); + + uint typeNameLen = qstrlen(typeName); + if (typeNameLen > 0 && typeName[typeNameLen - 1] == '*') + return *static_cast<void *const *>(a_ptr) == *static_cast<void *const *>(b_ptr); + + if (a->is_null && b->is_null) + return true; + + return !memcmp(a_ptr, b_ptr, QMetaType::sizeOf(a->type)); +} + +static bool customConvert(const QVariant::Private *, QVariant::Type, void *, bool *ok) +{ + if (ok) + *ok = false; + return false; +} + +#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) +static void customStreamDebug(QDebug, const QVariant &) {} +#endif + +const QVariant::Handler qt_custom_variant_handler = { + customConstruct, + customClear, + customIsNull, +#ifndef QT_NO_DATASTREAM + 0, + 0, +#endif + customCompare, + customConvert, + 0, +#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) + customStreamDebug +#else + 0 +#endif +}; + +} // annonymous used to hide QVariant handlers + +static HandlersManager handlerManager; +Q_STATIC_ASSERT_X(!QModulesPrivate::Core, "Initialization assumes that ModulesNames::Core is 0"); +const QVariant::Handler *HandlersManager::Handlers[QModulesPrivate::ModulesCount] + = { &qt_kernel_variant_handler, &qt_dummy_variant_handler, + &qt_dummy_variant_handler, &qt_custom_variant_handler }; + Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler() { return &qt_kernel_variant_handler; } +inline void HandlersManager::unregisterHandler(const QModulesPrivate::Names name) +{ + Handlers[name] = &qt_dummy_variant_handler; +} -const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; +Q_CORE_EXPORT void QVariantPrivate::registerHandler(const int /* Modules::Names */name, const QVariant::Handler *handler) +{ + handlerManager.registerHandler(static_cast<QModulesPrivate::Names>(name), handler); +} + +Q_CORE_EXPORT void QVariantPrivate::unregisterHandler(const int /* Modules::Names */ name) +{ + handlerManager.unregisterHandler(static_cast<QModulesPrivate::Names>(name)); +} /*! \class QVariant @@ -1018,7 +1168,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; void QVariant::create(int type, const void *copy) { d.type = type; - handler->construct(&d, copy); + handlerManager[type]->construct(&d, copy); } /*! @@ -1035,7 +1185,7 @@ void QVariant::create(int type, const void *copy) QVariant::~QVariant() { if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type > Char)) - handler->clear(&d); + handlerManager[d.type]->clear(&d); } /*! @@ -1051,7 +1201,7 @@ QVariant::QVariant(const QVariant &p) if (d.is_shared) { d.data.shared->ref.ref(); } else if (p.d.type > Char) { - handler->construct(&d, p.constData()); + handlerManager[d.type]->construct(&d, p.constData()); d.is_null = p.d.is_null; } } @@ -1435,7 +1585,7 @@ QVariant& QVariant::operator=(const QVariant &variant) d = variant.d; } else if (variant.d.type > Char) { d.type = variant.d.type; - handler->construct(&d, variant.constData()); + handlerManager[d.type]->construct(&d, variant.constData()); d.is_null = variant.d.is_null; } else { d = variant.d; @@ -1465,9 +1615,9 @@ void QVariant::detach() Private dd; dd.type = d.type; - handler->construct(&dd, constData()); + handlerManager[d.type]->construct(&dd, constData()); if (!d.data.shared->ref.deref()) - handler->clear(&d); + handlerManager[d.type]->clear(&d); d.data.shared = dd.data.shared; } @@ -1496,7 +1646,7 @@ const char *QVariant::typeName() const void QVariant::clear() { if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type > Char)) - handler->clear(&d); + handlerManager[d.type]->clear(&d); d.type = Invalid; d.is_null = true; d.is_shared = false; @@ -1732,14 +1882,13 @@ QDataStream& operator<<(QDataStream &s, const QVariant::Type p) */ template <typename T> -inline T qVariantToHelper(const QVariant::Private &d, QVariant::Type t, - const QVariant::Handler *handler, T * = 0) +inline T qVariantToHelper(const QVariant::Private &d, QVariant::Type t, const HandlersManager &handler) { if (d.type == t) return *v_cast<T>(&d); T ret; - handler->convert(&d, t, &ret, 0); + handler[d.type]->convert(&d, t, &ret, 0); return ret; } @@ -1754,7 +1903,7 @@ inline T qVariantToHelper(const QVariant::Private &d, QVariant::Type t, */ QStringList QVariant::toStringList() const { - return qVariantToHelper<QStringList>(d, StringList, handler); + return qVariantToHelper<QStringList>(d, StringList, handlerManager); } /*! @@ -1767,7 +1916,7 @@ QStringList QVariant::toStringList() const */ QString QVariant::toString() const { - return qVariantToHelper<QString>(d, String, handler); + return qVariantToHelper<QString>(d, String, handlerManager); } /*! @@ -1778,7 +1927,7 @@ QString QVariant::toString() const */ QVariantMap QVariant::toMap() const { - return qVariantToHelper<QVariantMap>(d, Map, handler); + return qVariantToHelper<QVariantMap>(d, Map, handlerManager); } /*! @@ -1789,7 +1938,7 @@ QVariantMap QVariant::toMap() const */ QVariantHash QVariant::toHash() const { - return qVariantToHelper<QVariantHash>(d, Hash, handler); + return qVariantToHelper<QVariantHash>(d, Hash, handlerManager); } /*! @@ -1805,7 +1954,7 @@ QVariantHash QVariant::toHash() const */ QDate QVariant::toDate() const { - return qVariantToHelper<QDate>(d, Date, handler); + return qVariantToHelper<QDate>(d, Date, handlerManager); } /*! @@ -1821,7 +1970,7 @@ QDate QVariant::toDate() const */ QTime QVariant::toTime() const { - return qVariantToHelper<QTime>(d, Time, handler); + return qVariantToHelper<QTime>(d, Time, handlerManager); } /*! @@ -1838,7 +1987,7 @@ QTime QVariant::toTime() const */ QDateTime QVariant::toDateTime() const { - return qVariantToHelper<QDateTime>(d, DateTime, handler); + return qVariantToHelper<QDateTime>(d, DateTime, handlerManager); } /*! @@ -1853,7 +2002,7 @@ QDateTime QVariant::toDateTime() const #ifndef QT_BOOTSTRAPPED QEasingCurve QVariant::toEasingCurve() const { - return qVariantToHelper<QEasingCurve>(d, EasingCurve, handler); + return qVariantToHelper<QEasingCurve>(d, EasingCurve, handlerManager); } #endif @@ -1868,7 +2017,7 @@ QEasingCurve QVariant::toEasingCurve() const */ QByteArray QVariant::toByteArray() const { - return qVariantToHelper<QByteArray>(d, ByteArray, handler); + return qVariantToHelper<QByteArray>(d, ByteArray, handlerManager); } #ifndef QT_NO_GEOM_VARIANT @@ -1882,7 +2031,7 @@ QByteArray QVariant::toByteArray() const */ QPoint QVariant::toPoint() const { - return qVariantToHelper<QPoint>(d, Point, handler); + return qVariantToHelper<QPoint>(d, Point, handlerManager); } /*! @@ -1895,7 +2044,7 @@ QPoint QVariant::toPoint() const */ QRect QVariant::toRect() const { - return qVariantToHelper<QRect>(d, Rect, handler); + return qVariantToHelper<QRect>(d, Rect, handlerManager); } /*! @@ -1908,7 +2057,7 @@ QRect QVariant::toRect() const */ QSize QVariant::toSize() const { - return qVariantToHelper<QSize>(d, Size, handler); + return qVariantToHelper<QSize>(d, Size, handlerManager); } /*! @@ -1921,7 +2070,7 @@ QSize QVariant::toSize() const */ QSizeF QVariant::toSizeF() const { - return qVariantToHelper<QSizeF>(d, SizeF, handler); + return qVariantToHelper<QSizeF>(d, SizeF, handlerManager); } /*! @@ -1934,7 +2083,7 @@ QSizeF QVariant::toSizeF() const */ QRectF QVariant::toRectF() const { - return qVariantToHelper<QRectF>(d, RectF, handler); + return qVariantToHelper<QRectF>(d, RectF, handlerManager); } /*! @@ -1947,7 +2096,7 @@ QRectF QVariant::toRectF() const */ QLineF QVariant::toLineF() const { - return qVariantToHelper<QLineF>(d, LineF, handler); + return qVariantToHelper<QLineF>(d, LineF, handlerManager); } /*! @@ -1960,7 +2109,7 @@ QLineF QVariant::toLineF() const */ QLine QVariant::toLine() const { - return qVariantToHelper<QLine>(d, Line, handler); + return qVariantToHelper<QLine>(d, Line, handlerManager); } /*! @@ -1973,7 +2122,7 @@ QLine QVariant::toLine() const */ QPointF QVariant::toPointF() const { - return qVariantToHelper<QPointF>(d, PointF, handler); + return qVariantToHelper<QPointF>(d, PointF, handlerManager); } #endif // QT_NO_GEOM_VARIANT @@ -1988,7 +2137,7 @@ QPointF QVariant::toPointF() const */ QUrl QVariant::toUrl() const { - return qVariantToHelper<QUrl>(d, Url, handler); + return qVariantToHelper<QUrl>(d, Url, handlerManager); } /*! @@ -2001,7 +2150,7 @@ QUrl QVariant::toUrl() const */ QLocale QVariant::toLocale() const { - return qVariantToHelper<QLocale>(d, Locale, handler); + return qVariantToHelper<QLocale>(d, Locale, handlerManager); } /*! @@ -2016,7 +2165,7 @@ QLocale QVariant::toLocale() const #ifndef QT_NO_REGEXP QRegExp QVariant::toRegExp() const { - return qVariantToHelper<QRegExp>(d, RegExp, handler); + return qVariantToHelper<QRegExp>(d, RegExp, handlerManager); } #endif @@ -2030,7 +2179,7 @@ QRegExp QVariant::toRegExp() const */ QChar QVariant::toChar() const { - return qVariantToHelper<QChar>(d, Char, handler); + return qVariantToHelper<QChar>(d, Char, handlerManager); } /*! @@ -2041,12 +2190,12 @@ QChar QVariant::toChar() const */ QBitArray QVariant::toBitArray() const { - return qVariantToHelper<QBitArray>(d, BitArray, handler); + return qVariantToHelper<QBitArray>(d, BitArray, handlerManager); } template <typename T> inline T qNumVariantToHelper(const QVariant::Private &d, - const QVariant::Handler *handler, bool *ok, const T& val) + const HandlersManager &handler, bool *ok, const T& val) { uint t = qMetaTypeId<T>(); if (ok) @@ -2054,8 +2203,8 @@ inline T qNumVariantToHelper(const QVariant::Private &d, if (d.type == t) return val; - T ret; - if (!handler->convert(&d, QVariant::Type(t), &ret, ok) && ok) + T ret = 0; + if (!handler[d.type]->convert(&d, QVariant::Type(t), &ret, ok) && ok) *ok = false; return ret; } @@ -2077,7 +2226,7 @@ inline T qNumVariantToHelper(const QVariant::Private &d, */ int QVariant::toInt(bool *ok) const { - return qNumVariantToHelper<int>(d, handler, ok, d.data.i); + return qNumVariantToHelper<int>(d, handlerManager, ok, d.data.i); } /*! @@ -2097,7 +2246,7 @@ int QVariant::toInt(bool *ok) const */ uint QVariant::toUInt(bool *ok) const { - return qNumVariantToHelper<uint>(d, handler, ok, d.data.u); + return qNumVariantToHelper<uint>(d, handlerManager, ok, d.data.u); } /*! @@ -2112,7 +2261,7 @@ uint QVariant::toUInt(bool *ok) const */ qlonglong QVariant::toLongLong(bool *ok) const { - return qNumVariantToHelper<qlonglong>(d, handler, ok, d.data.ll); + return qNumVariantToHelper<qlonglong>(d, handlerManager, ok, d.data.ll); } /*! @@ -2128,7 +2277,7 @@ qlonglong QVariant::toLongLong(bool *ok) const */ qulonglong QVariant::toULongLong(bool *ok) const { - return qNumVariantToHelper<qulonglong>(d, handler, ok, d.data.ull); + return qNumVariantToHelper<qulonglong>(d, handlerManager, ok, d.data.ull); } /*! @@ -2148,7 +2297,7 @@ bool QVariant::toBool() const return d.data.b; bool res = false; - handler->convert(&d, Bool, &res, 0); + handlerManager[d.type]->convert(&d, Bool, &res, 0); return res; } @@ -2165,7 +2314,7 @@ bool QVariant::toBool() const */ double QVariant::toDouble(bool *ok) const { - return qNumVariantToHelper<double>(d, handler, ok, d.data.d); + return qNumVariantToHelper<double>(d, handlerManager, ok, d.data.d); } /*! @@ -2182,7 +2331,7 @@ double QVariant::toDouble(bool *ok) const */ float QVariant::toFloat(bool *ok) const { - return qNumVariantToHelper<float>(d, handler, ok, d.data.f); + return qNumVariantToHelper<float>(d, handlerManager, ok, d.data.f); } /*! @@ -2199,7 +2348,7 @@ float QVariant::toFloat(bool *ok) const */ qreal QVariant::toReal(bool *ok) const { - return qNumVariantToHelper<qreal>(d, handler, ok, d.data.real); + return qNumVariantToHelper<qreal>(d, handlerManager, ok, d.data.real); } /*! @@ -2210,7 +2359,7 @@ qreal QVariant::toReal(bool *ok) const */ QVariantList QVariant::toList() const { - return qVariantToHelper<QVariantList>(d, List, handler); + return qVariantToHelper<QVariantList>(d, List, handlerManager); } @@ -2418,13 +2567,25 @@ bool QVariant::convert(Type t) return false; bool isOk = true; - if (!handler->convert(&oldValue.d, t, data(), &isOk)) + if (!handlerManager[d.type]->convert(&oldValue.d, t, data(), &isOk)) isOk = false; d.is_null = !isOk; return isOk; } /*! + \fn convert(const int type, void *ptr) const + \internal + Created for qvariant_cast() usage +*/ +bool QVariant::convert(const int type, void *ptr) const +{ + Q_ASSERT(type < int(QMetaType::User)); + return handlerManager[type]->convert(&d, QVariant::Type(type), ptr, 0); +} + + +/*! \fn bool operator==(const QVariant &v1, const QVariant &v2) \relates QVariant @@ -2490,7 +2651,7 @@ bool QVariant::cmp(const QVariant &v) const if (!v2.canConvert(Type(d.type)) || !v2.convert(Type(d.type))) return false; } - return handler->compare(&d, &v2.d); + return handlerManager[d.type]->compare(&d, &v2.d); } /*! \internal @@ -2520,7 +2681,7 @@ void* QVariant::data() */ bool QVariant::isNull() const { - return handler->isNull(&d); + return handlerManager[d.type]->isNull(&d); } #ifndef QT_NO_DEBUG_STREAM @@ -2528,7 +2689,7 @@ QDebug operator<<(QDebug dbg, const QVariant &v) { #ifndef Q_BROKEN_DEBUG_STREAM dbg.nospace() << "QVariant(" << v.typeName() << ", "; - QVariant::handler->debugStream(dbg, v); + handlerManager[v.d.type]->debugStream(dbg, v); dbg.nospace() << ')'; return dbg.space(); #else |