summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qiterable.h4
-rw-r--r--src/corelib/kernel/qmetatype.cpp342
-rw-r--r--src/corelib/kernel/qmetatype.h230
-rw-r--r--src/corelib/kernel/qvariant.cpp27
-rw-r--r--src/corelib/kernel/qvariant.h18
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp45
6 files changed, 559 insertions, 107 deletions
diff --git a/src/corelib/kernel/qiterable.h b/src/corelib/kernel/qiterable.h
index 8a230d5f0e..20d937591a 100644
--- a/src/corelib/kernel/qiterable.h
+++ b/src/corelib/kernel/qiterable.h
@@ -501,9 +501,7 @@ public:
}
const void *constIterable() const { return m_iterable.constPointer(); }
-
- // TODO: fix this when introducing mutable iterables
- void *mutableIterable() { return const_cast<void *>(m_iterable.constPointer()); }
+ void *mutableIterable() { return m_iterable.mutablePointer(); }
QConstIterator<Container> constBegin() const
{
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 7977335c98..87835be25c 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -1580,6 +1580,10 @@ QMetaTypeConverterRegistry;
Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry)
+using QMetaTypeMutableViewRegistry
+ = QMetaTypeFunctionRegistry<QMetaType::MutableViewFunction, QPair<int,int>>;
+Q_GLOBAL_STATIC(QMetaTypeMutableViewRegistry, customTypesMutableViewRegistry)
+
/*!
\fn bool QMetaType::registerConverter()
\since 5.2
@@ -1618,26 +1622,78 @@ Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry)
\since 5.2
\internal
*/
-bool QMetaType::registerConverterFunction(const ConverterFunction &f, int from, int to)
+bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType from, QMetaType to)
{
- if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from, to), f)) {
+ if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from.id(), to.id()), f)) {
qWarning("Type conversion already registered from type %s to type %s",
- QMetaType(from).name(), QMetaType(to).name());
+ from.name(), to.name());
return false;
}
return true;
}
/*!
+ \fn template<typename MemberFunction, int> bool QMetaType::registerMutableView(MemberFunction function)
+ \since 6.0
+ \overload
+ Registers a method \a function like \c {To From::function()} as mutable view of type \c {To} on
+ type \c {From} in the meta type system. Returns \c true if the registration succeeded, otherwise
+ \c false.
+*/
+
+/*!
+ \fn template<typename MemberFunctionOk, char> bool QMetaType::registerMutableView(MemberFunctionOk function)
+ \since 6.0
+ \overload
+ Registers a method \a function like To From::function(bool *ok) as mutable view of type To on
+ type From in the meta type system. Returns \c true if the registration succeeded, otherwise
+ \c false.
+*/
+
+/*!
+ \fn template<typename UnaryFunction> bool QMetaType::registerMutableView(UnaryFunction function)
+ \since 6.0
+ \overload
+ Registers a unary function object \a function as mutable view of type To on type From
+ in the meta type system. Returns \c true if the registration succeeded, otherwise \c false.
+*/
+
+/*!
+ Registers function \a f as mutable view of type id \a to on type id \a from.
+ Returns \c true if the registration succeeded, otherwise \c false.
+ \since 6.0
+ \internal
+*/
+bool QMetaType::registerMutableViewFunction(const MutableViewFunction &f, QMetaType from, QMetaType to)
+{
+ if (!customTypesMutableViewRegistry()->insertIfNotContains(qMakePair(from.id(), to.id()), f)) {
+ qWarning("Mutable view on type already registered from type %s to type %s",
+ from.name(), to.name());
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \internal
+ */
+void QMetaType::unregisterMutableViewFunction(QMetaType from, QMetaType to)
+{
+ if (customTypesMutableViewRegistry.isDestroyed())
+ return;
+ customTypesMutableViewRegistry()->remove(from.id(), to.id());
+}
+
+/*!
\internal
Invoked automatically when a converter function object is destroyed.
*/
-void QMetaType::unregisterConverterFunction(int from, int to)
+void QMetaType::unregisterConverterFunction(QMetaType from, QMetaType to)
{
if (customTypesConversionRegistry.isDestroyed())
return;
- customTypesConversionRegistry()->remove(from, to);
+ customTypesConversionRegistry()->remove(from.id(), to.id());
}
#ifndef QT_NO_DEBUG_STREAM
@@ -1833,14 +1889,10 @@ static bool convertToEnum(QMetaType fromType, const void *from, QMetaType toType
#ifndef QT_BOOTSTRAPPED
static bool convertIterableToVariantList(QMetaType fromType, const void *from, void *to)
{
- const QMetaType::ConverterFunction * const f =
- customTypesConversionRegistry()->function(
- qMakePair(fromType.id(), qMetaTypeId<QIterable<QMetaSequence>>()));
- if (!f)
+ QSequentialIterable list;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<QSequentialIterable>(), &list))
return false;
- QSequentialIterable list;
- (*f)(from, &list);
QVariantList &l = *static_cast<QVariantList *>(to);
l.clear();
l.reserve(list.size());
@@ -1852,14 +1904,10 @@ static bool convertIterableToVariantList(QMetaType fromType, const void *from, v
static bool convertIterableToVariantMap(QMetaType fromType, const void *from, void *to)
{
- const QMetaType::ConverterFunction * const f =
- customTypesConversionRegistry()->function(
- qMakePair(fromType.id(), qMetaTypeId<QIterable<QMetaAssociation>>()));
- if (!f)
+ QAssociativeIterable map;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<QAssociativeIterable>(), &map))
return false;
- QAssociativeIterable map;
- (*f)(from, &map);
QVariantMap &h = *static_cast<QVariantMap *>(to);
h.clear();
auto end = map.end();
@@ -1870,14 +1918,10 @@ static bool convertIterableToVariantMap(QMetaType fromType, const void *from, vo
static bool convertIterableToVariantHash(QMetaType fromType, const void *from, void *to)
{
- const QMetaType::ConverterFunction * const f =
- customTypesConversionRegistry()->function(
- qMakePair(fromType.id(), qMetaTypeId<QIterable<QMetaAssociation>>()));
- if (!f)
+ QAssociativeIterable map;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<QAssociativeIterable>(), &map))
return false;
- QAssociativeIterable map;
- (*f)(from, &map);
QVariantHash &h = *static_cast<QVariantHash *>(to);
h.clear();
h.reserve(map.size());
@@ -1948,6 +1992,60 @@ static bool convertToSequentialIterable(QMetaType fromType, const void *from, vo
return false;
}
+static bool canConvertToSequentialIterable(QMetaType fromType)
+{
+ switch (fromType.id()) {
+ case QMetaType::QVariantList:
+ case QMetaType::QStringList:
+ case QMetaType::QByteArrayList:
+ return true;
+ default:
+ return QMetaType::canConvert(fromType, QMetaType::fromType<QIterable<QMetaSequence>>());
+ }
+}
+
+static bool canImplicitlyViewAsSequentialIterable(QMetaType fromType)
+{
+ switch (fromType.id()) {
+ case QMetaType::QVariantList:
+ case QMetaType::QStringList:
+ case QMetaType::QByteArrayList:
+ return true;
+ default:
+ return QMetaType::canView(
+ fromType, QMetaType::fromType<QIterable<QMetaSequence>>());
+ }
+}
+
+static bool viewAsSequentialIterable(QMetaType fromType, void *from, void *to)
+{
+ using namespace QtMetaTypePrivate;
+ int fromTypeId = fromType.id();
+
+ QSequentialIterable &i = *static_cast<QSequentialIterable *>(to);
+ if (fromTypeId == QMetaType::QVariantList) {
+ i = QSequentialIterable(reinterpret_cast<QVariantList *>(from));
+ return true;
+ }
+ if (fromTypeId == QMetaType::QStringList) {
+ i = QSequentialIterable(reinterpret_cast<QStringList *>(from));
+ return true;
+ }
+ else if (fromTypeId == QMetaType::QByteArrayList) {
+ i = QSequentialIterable(reinterpret_cast<QByteArrayList *>(from));
+ return true;
+ }
+
+ QIterable<QMetaSequence> j;
+ if (QMetaType::view(
+ fromType, from, QMetaType::fromType<QIterable<QMetaSequence>>(), &j)) {
+ i = std::move(j);
+ return true;
+ }
+
+ return false;
+}
+
static bool convertToAssociativeIterable(QMetaType fromType, const void *from, void *to)
{
using namespace QtMetaTypePrivate;
@@ -1981,6 +2079,74 @@ static bool canConvertMetaObject(QMetaType fromType, QMetaType toType)
}
return false;
}
+
+static bool canConvertToAssociativeIterable(QMetaType fromType)
+{
+ switch (fromType.id()) {
+ case QMetaType::QVariantMap:
+ case QMetaType::QVariantHash:
+ return true;
+ default:
+ return QMetaType::canConvert(fromType, QMetaType::fromType<QIterable<QMetaAssociation>>());
+ }
+}
+
+static bool canImplicitlyViewAsAssociativeIterable(QMetaType fromType)
+{
+ switch (fromType.id()) {
+ case QMetaType::QVariantMap:
+ case QMetaType::QVariantHash:
+ return true;
+ default:
+ return QMetaType::canView(
+ fromType, QMetaType::fromType<QIterable<QMetaAssociation>>());
+ }
+}
+
+static bool viewAsAssociativeIterable(QMetaType fromType, void *from, void *to)
+{
+ using namespace QtMetaTypePrivate;
+ int fromTypeId = fromType.id();
+
+ QAssociativeIterable &i = *static_cast<QAssociativeIterable *>(to);
+ if (fromTypeId == QMetaType::QVariantMap) {
+ i = QAssociativeIterable(reinterpret_cast<QVariantMap *>(from));
+ return true;
+ }
+ if (fromTypeId == QMetaType::QVariantHash) {
+ i = QAssociativeIterable(reinterpret_cast<QVariantHash *>(from));
+ return true;
+ }
+
+ QIterable<QMetaAssociation> j;
+ if (QMetaType::view(
+ fromType, from, QMetaType::fromType<QIterable<QMetaAssociation>>(), &j)) {
+ i = std::move(j);
+ return true;
+ }
+
+ return false;
+}
+
+static bool convertQObject(QMetaType fromType, const void *from, QMetaType toType, void *to)
+{
+ // handle QObject conversion
+ if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) {
+ QObject *fromObject = *static_cast<QObject * const *>(from);
+ // use dynamic metatype of from if possible
+ if (fromObject && fromObject->metaObject()->inherits(toType.metaObject())) {
+ *static_cast<QObject **>(to) = toType.metaObject()->cast(fromObject);
+ return true;
+ } else if (!fromObject && fromType.metaObject()) {
+ // if fromObject is null, use static fromType to check if conversion works
+ *static_cast<void **>(to) = nullptr;
+ return fromType.metaObject()->inherits(toType.metaObject());
+ } else {
+ return false;
+ }
+ }
+ return false;
+}
#endif
/*!
@@ -2053,21 +2219,82 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
if (toTypeId == qMetaTypeId<QAssociativeIterable>())
return convertToAssociativeIterable(fromType, from, to);
- // handle QObject conversion
- if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) {
- QObject *fromObject = *static_cast<QObject * const *>(from);
- // use dynamic metatype of from if possible
- if (fromObject && fromObject->metaObject()->inherits(toType.metaObject())) {
- *static_cast<QObject **>(to) = toType.metaObject()->cast(fromObject);
- return true;
- } else if (!fromObject && fromType.metaObject()) {
- // if fromObject is null, use static fromType to check if conversion works
- *static_cast<void **>(to) = nullptr;
- return fromType.metaObject()->inherits(toType.metaObject());
- } else {
- return false;
- }
- }
+ return convertQObject(fromType, from, toType, to);
+#else
+ return false;
+#endif
+}
+
+/*!
+ Creates a mutable view on the object at \a from of \a fromType in the preallocated space at
+ \a to typed \a toType. Returns \c true if the conversion succeeded, otherwise false.
+ \since 6.0
+*/
+bool QMetaType::view(QMetaType fromType, void *from, QMetaType toType, void *to)
+{
+ if (!fromType.isValid() || !toType.isValid())
+ return false;
+
+ int fromTypeId = fromType.id();
+ int toTypeId = toType.id();
+
+ const QMetaType::MutableViewFunction * const f =
+ customTypesMutableViewRegistry()->function(qMakePair(fromTypeId, toTypeId));
+ if (f)
+ return (*f)(from, to);
+
+#ifndef QT_BOOTSTRAPPED
+ if (toTypeId == qMetaTypeId<QSequentialIterable>())
+ return viewAsSequentialIterable(fromType, from, to);
+
+ if (toTypeId == qMetaTypeId<QAssociativeIterable>())
+ return viewAsAssociativeIterable(fromType, from, to);
+
+ return convertQObject(fromType, from, toType, to);
+#else
+ return false;
+#endif
+}
+
+/*!
+ Returns \c true if QMetaType::view can create a mutable view of type \a toType
+ on type \a fromType.
+
+ Converting between pointers of types derived from QObject will return true for this
+ function if a qobject_cast from the type described by \a fromType to the type described
+ by \a toType would succeed.
+
+ You can create a mutable view of type QSequentialIterable on any container registered with
+ Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE().
+
+ Similarly you can create a mutable view of type QAssociativeIterable on any container
+ registered with Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE().
+
+ \sa convert(), QSequentialIterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(),
+ QAssociativeIterable, Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE()
+*/
+bool QMetaType::canView(QMetaType fromType, QMetaType toType)
+{
+ int fromTypeId = fromType.id();
+ int toTypeId = toType.id();
+
+ if (fromTypeId == UnknownType || toTypeId == UnknownType)
+ return false;
+
+ const MutableViewFunction * const f =
+ customTypesMutableViewRegistry()->function(qMakePair(fromTypeId, toTypeId));
+ if (f)
+ return true;
+
+#ifndef QT_BOOTSTRAPPED
+ if (toTypeId == qMetaTypeId<QSequentialIterable>())
+ return canImplicitlyViewAsSequentialIterable(fromType);
+
+ if (toTypeId == qMetaTypeId<QAssociativeIterable>())
+ return canImplicitlyViewAsAssociativeIterable(fromType);
+
+ if (canConvertMetaObject(fromType, toType))
+ return true;
#endif
return false;
@@ -2165,17 +2392,25 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
return true;
#ifndef QT_BOOTSTRAPPED
- if (toTypeId == QVariantList && hasRegisteredConverterFunction(
- fromTypeId, qMetaTypeId<QIterable<QMetaSequence>>()))
+ if (toTypeId == qMetaTypeId<QSequentialIterable>())
+ return canConvertToSequentialIterable(fromType);
+
+ if (toTypeId == qMetaTypeId<QAssociativeIterable>())
+ return canConvertToAssociativeIterable(fromType);
+
+ if (toTypeId == QVariantList
+ && canConvert(fromType, QMetaType::fromType<QSequentialIterable>())) {
return true;
+ }
- if ((toTypeId == QVariantHash || toTypeId == QVariantMap) && hasRegisteredConverterFunction(
- fromTypeId, qMetaTypeId<QIterable<QMetaAssociation>>()))
+ if ((toTypeId == QVariantHash || toTypeId == QVariantMap)
+ && canConvert(fromType, QMetaType::fromType<QAssociativeIterable>())) {
return true;
+ }
#endif
if (toTypeId == QVariantPair && hasRegisteredConverterFunction(
- fromTypeId, qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>()))
+ fromType, QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>()))
return true;
if (fromType.flags() & IsEnumeration) {
@@ -2219,9 +2454,26 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
to \a toTypeId
\since 5.2
*/
-bool QMetaType::hasRegisteredConverterFunction(int fromTypeId, int toTypeId)
+bool QMetaType::hasRegisteredConverterFunction(QMetaType fromType, QMetaType toType)
+{
+ return customTypesConversionRegistry()->contains(qMakePair(fromType.id(), toType.id()));
+}
+
+/*!
+ \fn bool QMetaType::hasRegisteredMutableViewFunction()
+ Returns \c true, if the meta type system has a registered mutable view on type From of type To.
+ \since 6.0
+ \overload
+*/
+
+/*!
+ Returns \c true, if the meta type system has a registered mutable view on meta type id
+ \a fromTypeId of meta type id \a toTypeId.
+ \since 5.2
+*/
+bool QMetaType::hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType)
{
- return customTypesConversionRegistry()->contains(qMakePair(fromTypeId, toTypeId));
+ return customTypesMutableViewRegistry()->contains(qMakePair(fromType.id(), toType.id()));
}
/*!
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index f28bfead5c..971388fabd 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -465,6 +465,9 @@ public:
// type erased converter function
using ConverterFunction = std::function<bool(const void *src, void *target)>;
+ // type erased mutable view, primarily for containers
+ using MutableViewFunction = std::function<bool(void *src, void *target)>;
+
// implicit conversion supported like double -> float
template<typename From, typename To>
static bool registerConverter()
@@ -479,6 +482,13 @@ public:
static bool registerConverter(MemberFunctionOk function);
template<typename UnaryFunction>
static bool registerConverter(UnaryFunction function);
+
+ template<typename MemberFunction, int>
+ static bool registerMutableView(MemberFunction function);
+ template<typename MemberFunctionOk, char>
+ static bool registerMutableView(MemberFunctionOk function);
+ template<typename UnaryFunction>
+ static bool registerMutableView(UnaryFunction function);
#else
// member function as in "QString QFont::toString() const"
template<typename From, typename To>
@@ -487,15 +497,33 @@ public:
static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
"QMetaType::registerConverter: At least one of the types must be a custom type.");
- const int fromTypeId = qMetaTypeId<From>();
- const int toTypeId = qMetaTypeId<To>();
+ const QMetaType fromType = QMetaType::fromType<From>();
+ const QMetaType toType = QMetaType::fromType<To>();
auto converter = [function](const void *from, void *to) -> bool {
const From *f = static_cast<const From *>(from);
To *t = static_cast<To *>(to);
*t = (f->*function)();
return true;
};
- return registerConverterFunction(converter, fromTypeId, toTypeId);
+ return registerConverterFunction(converter, fromType, toType);
+ }
+
+ // member function
+ template<typename From, typename To>
+ static bool registerMutableView(To(From::*function)())
+ {
+ static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
+ "QMetaType::registerMutableView: At least one of the types must be a custom type.");
+
+ const QMetaType fromType = QMetaType::fromType<From>();
+ const QMetaType toType = QMetaType::fromType<To>();
+ auto view = [function](void *from, void *to) -> bool {
+ From *f = static_cast<From *>(from);
+ To *t = static_cast<To *>(to);
+ *t = (f->*function)();
+ return true;
+ };
+ return registerMutableViewFunction(view, fromType, toType);
}
// member function as in "double QString::toDouble(bool *ok = nullptr) const"
@@ -505,8 +533,8 @@ public:
static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
"QMetaType::registerConverter: At least one of the types must be a custom type.");
- const int fromTypeId = qMetaTypeId<From>();
- const int toTypeId = qMetaTypeId<To>();
+ const QMetaType fromType = QMetaType::fromType<From>();
+ const QMetaType toType = QMetaType::fromType<To>();
auto converter = [function](const void *from, void *to) -> bool {
const From *f = static_cast<const From *>(from);
To *t = static_cast<To *>(to);
@@ -516,7 +544,7 @@ public:
*t = To();
return result;
};
- return registerConverterFunction(converter, fromTypeId, toTypeId);
+ return registerConverterFunction(converter, fromType, toType);
}
// functor or function pointer
@@ -526,20 +554,41 @@ public:
static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
"QMetaType::registerConverter: At least one of the types must be a custom type.");
- const int fromTypeId = qMetaTypeId<From>();
- const int toTypeId = qMetaTypeId<To>();
+ const QMetaType fromType = QMetaType::fromType<From>();
+ const QMetaType toType = QMetaType::fromType<To>();
auto converter = [function](const void *from, void *to) -> bool {
const From *f = static_cast<const From *>(from);
To *t = static_cast<To *>(to);
*t = function(*f);
return true;
};
- return registerConverterFunction(converter, fromTypeId, toTypeId);
+ return registerConverterFunction(converter, fromType, toType);
+ }
+
+ // functor or function pointer
+ template<typename From, typename To, typename UnaryFunction>
+ static bool registerMutableView(UnaryFunction function)
+ {
+ static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
+ "QMetaType::registerMutableView: At least one of the types must be a custom type.");
+
+ const QMetaType fromType = QMetaType::fromType<From>();
+ const QMetaType toType = QMetaType::fromType<To>();
+ auto view = [function](void *from, void *to) -> bool {
+ From *f = static_cast<From *>(from);
+ To *t = static_cast<To *>(to);
+ *t = function(*f);
+ return true;
+ };
+ return registerMutableViewFunction(view, fromType, toType);
}
#endif
static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to);
static bool canConvert(QMetaType fromType, QMetaType toType);
+
+ static bool view(QMetaType fromType, void *from, QMetaType toType, void *to);
+ static bool canView(QMetaType fromType, QMetaType toType);
#if QT_DEPRECATED_SINCE(6, 0)
QT_DEPRECATED_VERSION_6_0
static bool convert(const void *from, int fromTypeId, void *to, int toTypeId)
@@ -570,10 +619,20 @@ public:
template<typename From, typename To>
static bool hasRegisteredConverterFunction()
{
- return hasRegisteredConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>());
+ return hasRegisteredConverterFunction(
+ QMetaType::fromType<From>(), QMetaType::fromType<To>());
}
- static bool hasRegisteredConverterFunction(int fromTypeId, int toTypeId);
+ static bool hasRegisteredConverterFunction(QMetaType fromType, QMetaType toType);
+
+ template<typename From, typename To>
+ static bool hasRegisteredMutableViewFunction()
+ {
+ return hasRegisteredMutableViewFunction(
+ QMetaType::fromType<From>(), QMetaType::fromType<To>());
+ }
+
+ static bool hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType);
#ifndef Q_CLANG_QDOC
template<typename, bool> friend struct QtPrivate::SequentialValueTypeIsMetaType;
@@ -581,8 +640,11 @@ public:
template<typename, bool> friend struct QtPrivate::IsMetaTypePair;
template<typename, typename> friend struct QtPrivate::MetaTypeSmartPointerHelper;
#endif
- static bool registerConverterFunction(const ConverterFunction &f, int from, int to);
- static void unregisterConverterFunction(int from, int to);
+ static bool registerConverterFunction(const ConverterFunction &f, QMetaType from, QMetaType to);
+ static void unregisterConverterFunction(QMetaType from, QMetaType to);
+
+ static bool registerMutableViewFunction(const MutableViewFunction &f, QMetaType from, QMetaType to);
+ static void unregisterMutableViewFunction(QMetaType from, QMetaType to);
static void unregisterMetaType(QMetaType type);
QtPrivate::QMetaTypeInterface *iface() { return d_ptr; }
@@ -833,9 +895,14 @@ namespace QtPrivate
};
template<typename T, bool = QtPrivate::IsSequentialContainer<T>::Value>
- struct SequentialContainerConverterHelper
+ struct SequentialContainerTransformationHelper
{
- static bool registerConverter(int)
+ static bool registerConverter()
+ {
+ return false;
+ }
+
+ static bool registerMutableView()
{
return false;
}
@@ -844,51 +911,66 @@ namespace QtPrivate
template<typename T, bool = QMetaTypeId2<typename T::value_type>::Defined>
struct SequentialValueTypeIsMetaType
{
- static bool registerConverter(int)
+ static bool registerConverter()
+ {
+ return false;
+ }
+
+ static bool registerMutableView()
{
return false;
}
};
template<typename T>
- struct SequentialContainerConverterHelper<T, true> : SequentialValueTypeIsMetaType<T>
+ struct SequentialContainerTransformationHelper<T, true> : SequentialValueTypeIsMetaType<T>
{
};
template<typename T, bool = QtPrivate::IsAssociativeContainer<T>::Value>
- struct AssociativeContainerConverterHelper
+ struct AssociativeContainerTransformationHelper
{
- static bool registerConverter(int)
+ static bool registerConverter()
{
return false;
}
- };
- template<typename T, bool = QMetaTypeId2<typename T::mapped_type>::Defined>
- struct AssociativeValueTypeIsMetaType
- {
- static bool registerConverter(int)
+ static bool registerMutableView()
{
return false;
}
};
template<typename T, bool = QMetaTypeId2<typename T::key_type>::Defined>
- struct KeyAndValueTypeIsMetaType
+ struct AssociativeKeyTypeIsMetaType
{
- static bool registerConverter(int)
+ static bool registerConverter()
+ {
+ return false;
+ }
+
+ static bool registerMutableView()
{
return false;
}
};
- template<typename T>
- struct KeyAndValueTypeIsMetaType<T, true> : AssociativeValueTypeIsMetaType<T>
+ template<typename T, bool = QMetaTypeId2<typename T::mapped_type>::Defined>
+ struct AssociativeMappedTypeIsMetaType
{
+ static bool registerConverter()
+ {
+ return false;
+ }
+
+ static bool registerMutableView()
+ {
+ return false;
+ }
};
template<typename T>
- struct AssociativeContainerConverterHelper<T, true> : KeyAndValueTypeIsMetaType<T>
+ struct AssociativeContainerTransformationHelper<T, true> : AssociativeKeyTypeIsMetaType<T>
{
};
@@ -896,7 +978,7 @@ namespace QtPrivate
&& QMetaTypeId2<typename T::second_type>::Defined>
struct IsMetaTypePair
{
- static bool registerConverter(int)
+ static bool registerConverter()
{
return false;
}
@@ -905,13 +987,13 @@ namespace QtPrivate
template<typename T>
struct IsMetaTypePair<T, true>
{
- inline static bool registerConverter(int id);
+ inline static bool registerConverter();
};
template<typename T>
struct IsPair
{
- static bool registerConverter(int)
+ static bool registerConverter()
{
return false;
}
@@ -925,7 +1007,7 @@ namespace QtPrivate
template<typename T, typename = void>
struct MetaTypeSmartPointerHelper
{
- static bool registerConverter(int) { return false; }
+ static bool registerConverter() { return false; }
};
Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type);
@@ -1042,10 +1124,12 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz
if (id > 0) {
QMetaType::registerNormalizedTypedef(normalizedTypeName, metaType);
- QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id);
- QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id);
- QtPrivate::MetaTypePairHelper<T>::registerConverter(id);
- QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter(id);
+ QtPrivate::SequentialContainerTransformationHelper<T>::registerConverter();
+ QtPrivate::SequentialContainerTransformationHelper<T>::registerMutableView();
+ QtPrivate::AssociativeContainerTransformationHelper<T>::registerConverter();
+ QtPrivate::AssociativeContainerTransformationHelper<T>::registerMutableView();
+ QtPrivate::MetaTypePairHelper<T>::registerConverter();
+ QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter();
}
return id;
@@ -1338,10 +1422,10 @@ template<typename T> \
struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \
typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> \
{ \
- static bool registerConverter(int id) \
+ static bool registerConverter() \
{ \
- const int toId = QMetaType::QObjectStar; \
- if (!QMetaType::hasRegisteredConverterFunction(id, toId)) { \
+ const QMetaType to = QMetaType(QMetaType::QObjectStar); \
+ if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<SMART_POINTER<T>>(), to)) { \
QtPrivate::QSmartPointerConvertFunctor<SMART_POINTER<T> > o; \
return QMetaType::registerConverter<SMART_POINTER<T>, QObject*>(o); \
} \
@@ -1421,10 +1505,10 @@ Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl)
QT_BEGIN_NAMESPACE
template <typename T>
-inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter(int id)
+inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter()
{
- const int toId = qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
- if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
+ const QMetaType to = QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
+ if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o;
return QMetaType::registerConverter<T, QtMetaTypePrivate::QPairVariantInterfaceImpl>(o);
}
@@ -1442,18 +1526,37 @@ struct QSequentialIterableConvertFunctor
}
};
+template<typename From>
+struct QSequentialIterableMutableViewFunctor
+{
+ QIterable<QMetaSequence> operator()(From &f) const
+ {
+ return QIterable<QMetaSequence>(QMetaSequence::fromContainer<From>(), &f);
+ }
+};
+
template<typename T>
struct SequentialValueTypeIsMetaType<T, true>
{
- static bool registerConverter(int id)
+ static bool registerConverter()
{
- const int toId = qMetaTypeId<QIterable<QMetaSequence>>();
- if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
+ const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
+ if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
QSequentialIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QIterable<QMetaSequence>>(o);
}
return true;
- }
+ }
+
+ static bool registerMutableView()
+ {
+ const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
+ if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) {
+ QSequentialIterableMutableViewFunctor<T> o;
+ return QMetaType::registerMutableView<T, QIterable<QMetaSequence>>(o);
+ }
+ return true;
+ }
};
template<typename From>
@@ -1465,23 +1568,40 @@ struct QAssociativeIterableConvertFunctor
}
};
+template<typename From>
+struct QAssociativeIterableMutableViewFunctor
+{
+ QIterable<QMetaAssociation> operator()(From &f) const
+ {
+ return QIterable<QMetaAssociation>(QMetaAssociation::fromContainer<From>(), &f);
+ }
+};
+
+// Mapped type can be omitted, for example in case of a set.
+// However, if it is available, we want to instantiate the metatype here.
template<typename T>
-struct AssociativeValueTypeIsMetaType<T, true>
+struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T>
{
- static bool registerConverter(int id)
+ static bool registerConverter()
{
- const int toId = qMetaTypeId<QIterable<QMetaAssociation>>();
- if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
+ const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
+ if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
QAssociativeIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QIterable<QMetaAssociation>>(o);
}
return true;
}
-};
-}
-
-namespace QtPrivate {
+ static bool registerMutableView()
+ {
+ const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
+ if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) {
+ QAssociativeIterableMutableViewFunctor<T> o;
+ return QMetaType::registerMutableView<T, QIterable<QMetaAssociation>>(o);
+ }
+ return true;
+ }
+};
class QMetaTypeInterface
{
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 603c49ebfe..65cdfc8580 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -2068,6 +2068,13 @@ bool QVariant::convert(int type, void *ptr) const
return QMetaType::convert(d.type(), constData(), QMetaType(type), ptr);
}
+/*!
+ \internal
+*/
+bool QVariant::view(int type, void *ptr)
+{
+ return QMetaType::view(d.type(), data(), QMetaType(type), ptr);
+}
/*!
\fn bool operator==(const QVariant &v1, const QVariant &v2)
@@ -2457,6 +2464,18 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
\sa setValue(), fromValue(), canConvert(), Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE()
*/
+/*! \fn template<typename T> T QVariant::view()
+
+ Returns a mutable view of template type \c{T} on the stored value.
+ Call canView() to find out whether such a view is supported.
+ If no such view can be created, returns the stored value converted to the
+ template type \c{T}. Call canConvert() to find out whether a type can be
+ converted. If the value can neither be viewed nor converted, a
+ \l{default-constructed value} will be returned.
+
+ \sa canView(), Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE()
+*/
+
/*! \fn bool QVariant::canConvert() const
Returns \c true if the variant can be converted to the template type \c{T},
@@ -2473,6 +2492,14 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
\sa convert()
*/
+/*! \fn bool QVariant::canView() const
+
+ Returns \c true if a mutable view of the template type \c{T} can be created on this variant,
+ otherwise \c false.
+
+ \sa value()
+*/
+
/*! \fn template<typename T> static QVariant QVariant::fromValue(const T &value)
Returns a QVariant containing a copy of \a value. Behaves
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 1825d4be88..83cb40a7c7 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -248,6 +248,9 @@ class Q_CORE_EXPORT QVariant
{ return QMetaType::canConvert(d.type(), targetType); }
bool convert(QMetaType type);
+ bool canView(QMetaType targetType) const
+ { return QMetaType::canView(d.type(), targetType); }
+
#if QT_DEPRECATED_SINCE(6, 0)
QT_DEPRECATED_VERSION_6_0
bool canConvert(int targetTypeId) const
@@ -364,6 +367,14 @@ class Q_CORE_EXPORT QVariant
{ return qvariant_cast<T>(*this); }
template<typename T>
+ inline T view()
+ {
+ T t{};
+ QMetaType::view(metaType(), data(), QMetaType::fromType<T>(), &t);
+ return t;
+ }
+
+ template<typename T>
static inline QVariant fromValue(const T &value)
{
return QVariant(QMetaType::fromType<T>(), std::addressof(value));
@@ -383,6 +394,10 @@ class Q_CORE_EXPORT QVariant
bool canConvert() const
{ return canConvert(QMetaType::fromType<T>()); }
+ template<typename T>
+ bool canView() const
+ { return canView(QMetaType::fromType<T>()); }
+
public:
struct PrivateShared
{
@@ -488,7 +503,8 @@ protected:
Private d;
void create(int type, const void *copy);
bool equals(const QVariant &other) const;
- bool convert(int t, void *ptr) const;
+ bool convert(int type, void *ptr) const;
+ bool view(int type, void *ptr);
private:
// force compile error, prevent QVariant(bool) to be called
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index 4190a0cb9f..8122220b88 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -278,6 +278,7 @@ private slots:
void sequentialIterableAppend();
void preferDirectConversionOverInterfaces();
+ void mutableView();
private:
void dataStream_data(QDataStream::Version version);
@@ -4173,7 +4174,7 @@ void testSequentialIteration()
QVERIFY(listVariant.canConvert<QVariantList>());
QVariantList varList = listVariant.value<QVariantList>();
QCOMPARE(varList.size(), (int)std::distance(sequence.begin(), sequence.end()));
- QSequentialIterable listIter = listVariant.value<QSequentialIterable>();
+ QSequentialIterable listIter = listVariant.view<QSequentialIterable>();
QCOMPARE(varList.size(), listIter.size());
typename Container::iterator containerIter = sequence.begin();
@@ -4758,7 +4759,7 @@ void tst_QVariant::sequentialIterableAppend()
QList<int> container { 1, 2 };
auto variant = QVariant::fromValue(container);
QVERIFY(variant.canConvert<QIterable<QMetaSequence>>());
- QSequentialIterable asIterable = variant.value<QIterable<QMetaSequence>>();
+ QSequentialIterable asIterable = variant.view<QIterable<QMetaSequence>>();
const int i = 3, j = 4;
void *mutableIterable = asIterable.mutableIterable();
asIterable.metaContainer().addValueAtEnd(mutableIterable, &i);
@@ -4778,7 +4779,7 @@ void tst_QVariant::sequentialIterableAppend()
QSet<QByteArray> container { QByteArray{"hello"}, QByteArray{"world"} };
auto variant = QVariant::fromValue(std::move(container));
QVERIFY(variant.canConvert<QIterable<QMetaSequence>>());
- QSequentialIterable asIterable = variant.value<QIterable<QMetaSequence>>();
+ QSequentialIterable asIterable = variant.view<QIterable<QMetaSequence>>();
QByteArray qba1 {"goodbye"};
QByteArray qba2 { "moon" };
void *mutableIterable = asIterable.mutableIterable();
@@ -4834,5 +4835,43 @@ void tst_QVariant::preferDirectConversionOverInterfaces()
QVERIFY(calledCorrectConverter);
}
+struct MyTypeView
+{
+ MyType *data;
+};
+
+void tst_QVariant::mutableView()
+{
+ bool calledView = false;
+ const bool success = QMetaType::registerMutableView<MyType, MyTypeView>([&](MyType &data) {
+ calledView = true;
+ return MyTypeView { &data };
+ });
+ QVERIFY(success);
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ "Mutable view on type already registered from type MyType to type MyTypeView");
+ const bool shouldFail = QMetaType::registerMutableView<MyType, MyTypeView>([&](MyType &) {
+ return MyTypeView { nullptr };
+ });
+ QVERIFY(!shouldFail);
+
+ auto original = QVariant::fromValue(MyType {});
+
+ QVERIFY(original.canView<MyTypeView>());
+ QVERIFY(!original.canConvert<MyTypeView>());
+
+ MyTypeView view = original.view<MyTypeView>();
+ QVERIFY(calledView);
+ const char *txt = "lll";
+ view.data->number = 113;
+ view.data->text = txt;
+
+ MyType extracted = original.view<MyType>();
+ QCOMPARE(extracted.number, 0);
+ QCOMPARE(extracted.text, nullptr);
+}
+
QTEST_MAIN(tst_QVariant)
#include "tst_qvariant.moc"