From 73fd7f2efcdb31e33febe840357a9d7b05e89165 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sun, 12 Jul 2020 12:19:34 +0200 Subject: [PATCH] Use QMetaTypeModuleHelper as the interface to do type conversions Move the type conversions from QVariant::Helper to QMetaType. Only do this for Qt Gui in a first step. This makes it possible to completely remove the Handler struct in QVariant, and now allows QMetaType to also convert Gui types. Moving the conversion of Core types into QMetaType will require further work. Change-Id: I061f789deca1b595d92bb29227eb54b8e71a3ee3 Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetatype.cpp | 4 + src/corelib/kernel/qmetatype_p.h | 21 +++ src/corelib/kernel/qvariant.cpp | 112 +++++--------- src/corelib/kernel/qvariant.h | 5 - src/corelib/kernel/qvariant_p.h | 6 - src/gui/kernel/qguivariant.cpp | 206 ++++++++----------------- src/widgets/kernel/qwidgetsvariant.cpp | 15 -- 7 files changed, 127 insertions(+), 242 deletions(-) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index c410c510e6..8d15b4a2aa 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1036,6 +1036,10 @@ bool QMetaType::hasRegisteredDebugStreamOperator() const */ bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId) { + if (auto moduleHelper = qModuleHelperForType(qMax(fromTypeId, toTypeId))) { + if (moduleHelper->convert(from, fromTypeId, to, toTypeId)) + return true; + } const QMetaType::ConverterFunction * const f = customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId)); return f && (*f)(from, to); diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h index dedec4d469..9e391e6476 100644 --- a/src/corelib/kernel/qmetatype_p.h +++ b/src/corelib/kernel/qmetatype_p.h @@ -128,10 +128,31 @@ QT_WARNING_POP #undef QT_DECLARE_GUI_MODULE_TYPES_ITER #undef QT_DECLARE_WIDGETS_MODULE_TYPES_ITER +#define QMETATYPE_CONVERTER(To, From, assign_and_return) \ + case makePair(QMetaType::To, QMetaType::From): \ + if (onlyCheck) \ + return true; \ + { \ + const From &source = *static_cast(from); \ + To &result = *static_cast(to); \ + assign_and_return \ + } +#define QMETATYPE_CONVERTER_FUNCTION(To, assign_and_return) \ + { \ + To &result = *static_cast(r); \ + assign_and_return \ + } + class QMetaTypeModuleHelper { public: + static constexpr auto makePair(int from, int to) -> quint64 + { + return (quint64(from) << 32) + quint64(to); + }; + virtual QtPrivate::QMetaTypeInterface *interfaceForType(int) const = 0; + virtual bool convert(const void *, int, void *, int) const { return false; } }; namespace QtMetaTypePrivate { diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 760c4ea9b6..975a053ba0 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -89,23 +89,6 @@ QT_BEGIN_NAMESPACE -namespace { -class HandlersManager -{ - static const QVariant::Handler *Handlers[QModulesPrivate::ModulesCount]; -public: - const QVariant::Handler *operator[] (const uint typeId) const - { - return Handlers[QModulesPrivate::moduleForType(typeId)]; - } - - void registerHandler(const QModulesPrivate::Names name, const QVariant::Handler *handler) - { - Handlers[name] = handler; - } -}; -} // namespace - namespace { struct CoreTypesFilter { template @@ -377,7 +360,7 @@ static bool convert(const QVariant::Private *d, int t, void *result) Q_ASSERT(d->type().id() != t); Q_ASSERT(result); - if (d->type().id() >= QMetaType::User || t >= QMetaType::User) { + if (d->type().id() >= QMetaType::LastCoreType || t >= QMetaType::LastCoreType) { if (QMetaType::convert(constData(*d), d->type().id(), result, t)) return true; } @@ -1373,16 +1356,6 @@ static bool convert(const QVariant::Private *d, int t, void *result) return true; } -const QVariant::Handler qt_kernel_variant_handler = { - convert -}; - -static bool dummyConvert(const QVariant::Private *, int, void *) -{ Q_ASSERT_X(false, "QVariant", "Trying to convert an unknown type"); return false; } -const QVariant::Handler qt_dummy_variant_handler = { - dummyConvert, -}; - // the type of d has already been set, but other field are not set static void customConstruct(QVariant::Private *d, const void *copy) { @@ -1417,39 +1390,9 @@ static void customClear(QVariant::Private *d) } } -static bool customConvert(const QVariant::Private *d, int t, void *result) -{ - if (d->type().id() >= QMetaType::User || t >= QMetaType::User) { - if (QMetaType::convert(constData(*d), d->type().id(), result, t)) - return true; - } - - return convert(d, t, result); -} - -const QVariant::Handler qt_custom_variant_handler = { - customConvert -}; } // annonymous used to hide QVariant handlers -static HandlersManager handlerManager; - -static_assert(!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; -} - -Q_CORE_EXPORT void QVariantPrivate::registerHandler(const int /* Modules::Names */name, const QVariant::Handler *handler) -{ - handlerManager.registerHandler(static_cast(name), handler); -} - /*! \class QVariant \inmodule QtCore @@ -2530,13 +2473,13 @@ inline T qVariantToHelper(const QVariant::Private &d) return *v_cast(&d); T ret; - if (d.type().id() >= QMetaType::User || targetType.id() >= QMetaType::User) { + if (d.type().id() >= QMetaType::LastCoreType || targetType.id() >= QMetaType::LastCoreType) { const void * const from = constData(d); if (QMetaType::convert(from, d.type().id(), &ret, targetType.id())) return ret; } - handlerManager[d.type().id()]->convert(&d, targetType.id(), &ret); + convert(&d, targetType.id(), &ret); return ret; } @@ -2954,8 +2897,7 @@ QBitArray QVariant::toBitArray() const } template -inline T qNumVariantToHelper(const QVariant::Private &d, - const HandlersManager &handlerManager, bool *ok, const T& val) +inline T qNumVariantToHelper(const QVariant::Private &d, bool *ok, const T& val) { const uint t = qMetaTypeId(); if (ok) @@ -2965,11 +2907,11 @@ inline T qNumVariantToHelper(const QVariant::Private &d, return val; T ret = 0; - if ((d.type().id() >= QMetaType::User || t >= QMetaType::User) + if ((d.type().id() >= QMetaType::LastCoreType || t >= QMetaType::LastCoreType) && QMetaType::convert(constData(d), d.type().id(), &ret, t)) return ret; - bool success = handlerManager[d.type().id()]->convert(&d, t, &ret); + bool success = convert(&d, t, &ret); if (ok) *ok = success; return ret; @@ -2994,7 +2936,7 @@ inline T qNumVariantToHelper(const QVariant::Private &d, */ int QVariant::toInt(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.i); + return qNumVariantToHelper(d, ok, d.data.i); } /*! @@ -3016,7 +2958,7 @@ int QVariant::toInt(bool *ok) const */ uint QVariant::toUInt(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.u); + return qNumVariantToHelper(d, ok, d.data.u); } /*! @@ -3033,7 +2975,7 @@ uint QVariant::toUInt(bool *ok) const */ qlonglong QVariant::toLongLong(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.ll); + return qNumVariantToHelper(d, ok, d.data.ll); } /*! @@ -3050,7 +2992,7 @@ qlonglong QVariant::toLongLong(bool *ok) const */ qulonglong QVariant::toULongLong(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.ull); + return qNumVariantToHelper(d, ok, d.data.ull); } /*! @@ -3071,7 +3013,14 @@ bool QVariant::toBool() const return d.data.b; bool res = false; - handlerManager[d.type().id()]->convert(&d, Bool, &res); + + if (d.type().id() >= QMetaType::LastCoreType) { + const void * const from = constData(); + if (QMetaType::convert(from, d.type().id(), &res, QMetaType::Bool)) + return res; + } + + ::convert(&d, Bool, &res); return res; } @@ -3090,7 +3039,7 @@ bool QVariant::toBool() const */ double QVariant::toDouble(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.d); + return qNumVariantToHelper(d, ok, d.data.d); } /*! @@ -3109,7 +3058,7 @@ double QVariant::toDouble(bool *ok) const */ float QVariant::toFloat(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.f); + return qNumVariantToHelper(d, ok, d.data.f); } /*! @@ -3128,7 +3077,7 @@ float QVariant::toFloat(bool *ok) const */ qreal QVariant::toReal(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.real); + return qNumVariantToHelper(d, ok, d.data.real); } /*! @@ -3378,7 +3327,7 @@ bool QVariant::canConvert(int targetTypeId) const return true; } - if ((d.type().id() >= QMetaType::User || targetTypeId >= QMetaType::User) + if ((d.type().id() >= QMetaType::LastCoreType|| targetTypeId >= QMetaType::LastCoreType) && QMetaType::hasRegisteredConverterFunction(d.type().id(), targetTypeId)) { return true; } @@ -3608,8 +3557,14 @@ bool QVariant::convert(int targetTypeId) return true; } - int converterType = std::max(oldValue.userType(), targetTypeId); - bool isOk = handlerManager[converterType]->convert(&oldValue.d, targetTypeId, data()); + bool isOk = false; + if (oldValue.metaType().id() >= QMetaType::LastCoreType || targetTypeId >= QMetaType::LastCoreType) { + const void * const from = oldValue.constData(); + isOk = QMetaType::convert(from, oldValue.metaType().id(), data(), targetTypeId); + } + if (!isOk) + isOk = ::convert(&oldValue.d, targetTypeId, data()); + d.is_null = !isOk; return isOk; } @@ -3621,7 +3576,12 @@ bool QVariant::convert(int targetTypeId) */ bool QVariant::convert(const int type, void *ptr) const { - return handlerManager[type]->convert(&d, type, ptr); + if (d.type().id() >= QMetaType::LastCoreType || type >= QMetaType::LastCoreType) { + const void * const from = constData(); + if (QMetaType::convert(from, d.type().id(), ptr, type)) + return true; + } + return ::convert(&d, type, ptr); } diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index dbe99b023e..e4bfa7c896 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -499,11 +499,6 @@ class Q_CORE_EXPORT QVariant } }; public: - typedef bool (*f_convert)(const QVariant::Private *d, int t, void *); - struct Handler { - f_convert convert; - }; - inline bool operator==(const QVariant &v) const { return equals(v); } inline bool operator!=(const QVariant &v) const diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h index 18fc0fbf80..f517e3b695 100644 --- a/src/corelib/kernel/qvariant_p.h +++ b/src/corelib/kernel/qvariant_p.h @@ -97,12 +97,6 @@ inline void v_construct(QVariant::Private *x, const T &t) } } -Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler(); - -namespace QVariantPrivate { -Q_CORE_EXPORT void registerHandler(const int /* Modules::Names */ name, const QVariant::Handler *handler); -} - QT_END_NAMESPACE #endif // QVARIANT_P_H diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index af16c49b9c..ae6def7176 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -91,8 +91,6 @@ QT_BEGIN_NAMESPACE -Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler(); - namespace { struct GuiTypesFilter { template @@ -101,161 +99,89 @@ struct GuiTypesFilter { }; }; -static bool convert(const QVariant::Private *d, int t, void *result) -{ - switch (t) { - case QMetaType::QByteArray: - if (d->type().id() == QMetaType::QColor) { - const QColor *c = v_cast(d); - *static_cast(result) = c->name(c->alpha() != 255 ? QColor::HexArgb : QColor::HexRgb).toLatin1(); - return true; - } - break; - case QMetaType::QString: { - QString *str = static_cast(result); - switch (d->type().id()) { -#if QT_CONFIG(shortcut) - case QMetaType::QKeySequence: - *str = (*v_cast(d)).toString(QKeySequence::NativeText); - return true; -#endif - case QMetaType::QFont: - *str = v_cast(d)->toString(); - return true; - case QMetaType::QColor: { - const QColor *c = v_cast(d); - *str = c->name(c->alpha() != 255 ? QColor::HexArgb : QColor::HexRgb); - return true; - } - default: - break; - } - break; - } - case QMetaType::QPixmap: - if (d->type().id() == QMetaType::QImage) { - *static_cast(result) = QPixmap::fromImage(*v_cast(d)); - return true; - } else if (d->type().id() == QMetaType::QBitmap) { - *static_cast(result) = *v_cast(d); - return true; - } else if (d->type().id() == QMetaType::QBrush) { - if (v_cast(d)->style() == Qt::TexturePattern) { - *static_cast(result) = v_cast(d)->texture(); - return true; - } - } - break; - case QMetaType::QImage: - if (d->type().id() == QMetaType::QPixmap) { - *static_cast(result) = v_cast(d)->toImage(); - return true; - } else if (d->type().id() == QMetaType::QBitmap) { - *static_cast(result) = v_cast(d)->toImage(); - return true; - } - break; - case QMetaType::QBitmap: - if (d->type().id() == QMetaType::QPixmap) { - *static_cast(result) = *v_cast(d); - return true; - } else if (d->type().id() == QMetaType::QImage) { - *static_cast(result) = QBitmap::fromImage(*v_cast(d)); - return true; - } - break; -#if QT_CONFIG(shortcut) - case QMetaType::Int: - if (d->type().id() == QMetaType::QKeySequence) { - const QKeySequence &seq = *v_cast(d); - *static_cast(result) = seq.isEmpty() ? 0 : seq[0]; - return true; - } - break; -#endif - case QMetaType::QFont: - if (d->type().id() == QMetaType::QString) { - QFont *f = static_cast(result); - f->fromString(*v_cast(d)); - return true; - } - break; - case QMetaType::QColor: - if (d->type().id() == QMetaType::QString) { - static_cast(result)->setNamedColor(*v_cast(d)); - return static_cast(result)->isValid(); - } else if (d->type().id() == QMetaType::QByteArray) { - static_cast(result)->setNamedColor(QLatin1String(*v_cast(d))); - return true; - } else if (d->type().id() == QMetaType::QBrush) { - if (v_cast(d)->style() == Qt::SolidPattern) { - *static_cast(result) = v_cast(d)->color(); - return true; - } - } - break; - case QMetaType::QBrush: - if (d->type().id() == QMetaType::QColor) { - *static_cast(result) = QBrush(*v_cast(d)); - return true; - } else if (d->type().id() == QMetaType::QPixmap) { - *static_cast(result) = QBrush(*v_cast(d)); - return true; - } - break; -#if QT_CONFIG(shortcut) - case QMetaType::QKeySequence: { - QKeySequence *seq = static_cast(result); - switch (d->type().id()) { - case QMetaType::QString: - *seq = QKeySequence(*v_cast(d)); - return true; - case QMetaType::Int: - *seq = QKeySequence(d->data.i); - return true; - default: - break; - } - break; - } -#endif -#ifndef QT_NO_ICON - case QMetaType::QIcon: { - return false; - } -#endif - default: - break; - } - return qcoreVariantHandler()->convert(d, t, result); -} - -const QVariant::Handler qt_gui_variant_handler = { - convert -}; - -#define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \ - QT_METATYPE_INTERFACE_INIT(RealName), static const struct : QMetaTypeModuleHelper { +#define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \ + QT_METATYPE_INTERFACE_INIT(RealName), + QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override { switch (type) { QT_FOR_EACH_STATIC_GUI_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE) default: return nullptr; } } +#undef QT_IMPL_METATYPEINTERFACE_GUI_TYPES + + bool convert(const void *from, int fromTypeId, void *to, int toTypeId) const override + { + Q_ASSERT(fromTypeId != toTypeId); + + bool onlyCheck = (from == nullptr && to == nullptr); + + using Int = int; + switch (makePair(toTypeId, fromTypeId)) { + QMETATYPE_CONVERTER(QByteArray, QColor, + result = source.name(source.alpha() != 255 ? + QColor::HexArgb : QColor::HexRgb).toLatin1(); + return true; + ); + QMETATYPE_CONVERTER(QColor, QByteArray, + result.setNamedColor(QLatin1String(source)); + return result.isValid(); + ); + QMETATYPE_CONVERTER(QString, QColor, + result = source.name(source.alpha() != 255 ? + QColor::HexArgb : QColor::HexRgb); + return true; + ); + QMETATYPE_CONVERTER(QColor, QString, + result.setNamedColor(source); + return result.isValid(); + ); +#if QT_CONFIG(shortcut) + QMETATYPE_CONVERTER(QString, QKeySequence, + result = source.toString(QKeySequence::NativeText); + return true; + ); + QMETATYPE_CONVERTER(QKeySequence, QString, result = source; return true;); + QMETATYPE_CONVERTER(Int, QKeySequence, + result = source.isEmpty() ? 0 : source[0]; + return true; + ); + QMETATYPE_CONVERTER(QKeySequence, Int, result = source; return true;); +#endif + QMETATYPE_CONVERTER(QString, QFont, result = source.toString(); return true;); + QMETATYPE_CONVERTER(QFont, QString, return result.fromString(source);); + QMETATYPE_CONVERTER(QPixmap, QImage, result = QPixmap::fromImage(source); return true;); + QMETATYPE_CONVERTER(QImage, QPixmap, result = source.toImage(); return true;); + QMETATYPE_CONVERTER(QPixmap, QBitmap, result = source; return true;); + QMETATYPE_CONVERTER(QBitmap, QPixmap, result = source; return true;); + QMETATYPE_CONVERTER(QImage, QBitmap, result = source.toImage(); return true;); + QMETATYPE_CONVERTER(QBitmap, QImage, result = QBitmap::fromImage(source); return true;); + QMETATYPE_CONVERTER(QPixmap, QBrush, result = source.texture(); return true;); + QMETATYPE_CONVERTER(QBrush, QPixmap, result = source; return true;); + QMETATYPE_CONVERTER(QColor, QBrush, + if (source.style() == Qt::SolidPattern) { + result = source.color(); + return true; + } + return false; + ); + QMETATYPE_CONVERTER(QBrush, QColor, result = source; return true;); + default: + break; + } + return false; + } } qVariantGuiHelper; - -#undef QT_IMPL_METATYPEINTERFACE_GUI_TYPES } // namespace used to hide QVariant handler extern Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper; void qRegisterGuiVariant() { - QVariantPrivate::registerHandler(QModulesPrivate::Gui, &qt_gui_variant_handler); qMetaTypeGuiHelper = &qVariantGuiHelper; } Q_CONSTRUCTOR_FUNCTION(qRegisterGuiVariant) diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp index 27d4d9e2fe..935a53935f 100644 --- a/src/widgets/kernel/qwidgetsvariant.cpp +++ b/src/widgets/kernel/qwidgetsvariant.cpp @@ -49,20 +49,6 @@ QT_BEGIN_NAMESPACE namespace { -static bool convert(const QVariant::Private *d, int type, void *result, bool *ok) -{ - Q_UNUSED(d); - Q_UNUSED(type); - Q_UNUSED(result); - if (ok) - *ok = false; - return false; -} - -static const QVariant::Handler widgets_handler = { - convert -}; - static const struct : QMetaTypeModuleHelper { QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override { @@ -84,7 +70,6 @@ void qRegisterWidgetsVariant() { qRegisterMetaType(); qMetaTypeWidgetsHelper = &qVariantWidgetsHelper; - QVariantPrivate::registerHandler(QModulesPrivate::Widgets, &widgets_handler); } Q_CONSTRUCTOR_FUNCTION(qRegisterWidgetsVariant)