summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qmetatype.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2020-07-30 22:42:31 +0200
committerLars Knoll <lars.knoll@qt.io>2020-08-24 00:17:03 +0200
commited8acbeb7c6fd137486b5c8a6eec58a3b9db862c (patch)
treed92c3f06a07082e2cc40be366faac8bc58b82def /src/corelib/kernel/qmetatype.cpp
parent5282545589244c1a3e01442e3586d5666213f76d (diff)
Automatically register data/debug stream operations in QMetaType
And remove the old manual registration code for those operators. Add some special handling for long/ulong, as these types could be streamed as a QVariant so far, but are not directly streamable through QDataStream. [ChangeLog][QtCore][QMetaType] The QMetaType::registerStreamOperators() and QMetaType::registerDebugStreamOperator() methods have been removed. The streaming operators for a type are now automatically registered together with the type registration. This implies that the operators should be visible wherever the type is visible and being used. [ChangeLog][Behavior Incompatible Changes] Because the QDataStream and QDebug serialization operators are automatically registered with QMetaType, the declarations of those functions must be present at any point where the type is used with QMetaType and QVariant. Change-Id: I4a0732651b20319af4a8397ff90b848ca4580d99 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib/kernel/qmetatype.cpp')
-rw-r--r--src/corelib/kernel/qmetatype.cpp371
1 files changed, 97 insertions, 274 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 1422e60a1c..7440f58a1c 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -105,14 +105,6 @@ struct QMetaTypeCustomRegistry
QReadWriteLock lock;
QList<QtPrivate::QMetaTypeInterface *> registry;
QHash<QByteArray, QtPrivate::QMetaTypeInterface *> aliases;
-#ifndef QT_NO_DATASTREAM
- struct DataStreamOps
- {
- QMetaType::SaveOperator saveOp;
- QMetaType::LoadOperator loadOp;
- };
- QHash<int, DataStreamOps> dataStreamOp;
-#endif
// index of first empty (unregistered) type in registry, if any.
int firstEmpty = 0;
@@ -246,6 +238,15 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry)
\li Classes that have a Q_GADGET macro
\endlist
+ \note This method also registers the stream and debug operators for the type if they
+ are visible at registration time. As this is done automatically in some places,
+ it is strongly recommended to declare the stream operators for a type directly
+ after the type itself.
+
+ The stream operators should have the following signatures:
+
+ \snippet code/src_corelib_kernel_qmetatype.cpp 6
+
\sa qRegisterMetaType()
*/
@@ -902,11 +903,8 @@ private:
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractConverterFunction,QPair<int,int> >
QMetaTypeConverterRegistry;
-typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int>
-QMetaTypeDebugStreamRegistry;
Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry)
-Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
/*!
\fn bool QMetaType::registerConverter()
@@ -939,15 +937,6 @@ Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false.
*/
-#ifndef QT_NO_DEBUG_STREAM
-/*!
- \fn bool QMetaType::registerDebugStreamOperator()
- Registers the debug stream operator for the user-registered type T. This requires T to have
- an operator<<(QDebug dbg, T).
- Returns \c true if the registration succeeded, otherwise false.
-*/
-#endif
-
/*!
Registers function \a f as converter function from type id \a from to \a to.
If there's already a conversion registered, this does nothing but deleting \a f.
@@ -978,30 +967,54 @@ void QMetaType::unregisterConverterFunction(int from, int to)
}
#ifndef QT_NO_DEBUG_STREAM
-bool QMetaType::registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f,
- int type)
+
+/*!
+ Streams the object at \a rhs of type \a typeId to the debug stream \a dbg. Returns \c true
+ on success, otherwise false.
+ \since 5.2
+*/
+bool QMetaType::debugStream(QDebug& dbg, const void *rhs)
{
- if (!customTypesDebugStreamRegistry()->insertIfNotContains(type, f)) {
- qWarning("Debug stream operator already registered for type %s", QMetaType::typeName(type));
+ if (!isValid() || !d_ptr->debugStream)
return false;
- }
+ d_ptr->debugStream(d_ptr, dbg, rhs);
return true;
}
/*!
+ \fn bool QMetaType::debugStream(QDebug& dbg, const void *rhs, int typeId)
+ \overload
+ \obsolete
+*/
+
+/*!
\fn bool QMetaType::hasRegisteredDebugStreamOperator()
- Returns \c true, if the meta type system has a registered debug stream operator for type T.
+ \obsolete
\since 5.2
+
+ Returns \c true, if the meta type system has a registered debug stream operator for type T.
*/
/*!
+ \fn bool QMetaType::hasRegisteredDebugStreamOperator(int typeId)
+ \obsolete
+
Returns \c true, if the meta type system has a registered debug stream operator for type
id \a typeId.
\since 5.2
*/
-bool QMetaType::hasRegisteredDebugStreamOperator(int typeId)
+
+/*!
+ \fn bool QMetaType::hasRegisteredDebugStreamOperator(int typeId)
+ \since 6.0
+
+ Returns \c true, if the meta type system has a registered debug stream operator for this
+ meta type.
+*/
+bool QMetaType::hasRegisteredDebugStreamOperator() const
+
{
- return customTypesDebugStreamRegistry()->contains(typeId);
+ return d_ptr && d_ptr->debugStream != nullptr;
}
#endif
@@ -1018,20 +1031,6 @@ bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId
}
/*!
- Streams the object at \a rhs of type \a typeId to the debug stream \a dbg. Returns \c true
- on success, otherwise false.
- \since 5.2
-*/
-bool QMetaType::debugStream(QDebug& dbg, const void *rhs, int typeId)
-{
- const QtPrivate::AbstractDebugStreamFunction * const f = customTypesDebugStreamRegistry()->function(typeId);
- if (!f)
- return false;
- f->stream(f, dbg, rhs);
- return true;
-}
-
-/*!
\fn bool QMetaType::hasRegisteredConverterFunction()
Returns \c true, if the meta type system has a registered conversion from type From to type To.
\since 5.2
@@ -1048,32 +1047,6 @@ bool QMetaType::hasRegisteredConverterFunction(int fromTypeId, int toTypeId)
return customTypesConversionRegistry()->contains(qMakePair(fromTypeId, toTypeId));
}
-#ifndef QT_NO_DATASTREAM
-/*!
- \internal
-*/
-void QMetaType::registerStreamOperators(const char *typeName, SaveOperator saveOp,
- LoadOperator loadOp)
-{
- registerStreamOperators(type(typeName), saveOp, loadOp);
-}
-
-/*!
- \internal
-*/
-void QMetaType::registerStreamOperators(int idx, SaveOperator saveOp,
- LoadOperator loadOp)
-{
- if (idx < User)
- return; //builtin types should not be registered;
-
- if (auto reg = customTypeRegistry()) {
- QWriteLocker locker(&reg->lock);
- reg->dataStreamOp[idx] = { saveOp, loadOp };
- }
-}
-#endif // QT_NO_DATASTREAM
-
// We don't officially support constexpr in MSVC 2015, but the limited support it
// has is enough for the code below.
@@ -1315,218 +1288,90 @@ int QMetaType::type(const QT_PREPEND_NAMESPACE(QByteArray) &typeName)
}
#ifndef QT_NO_DATASTREAM
-namespace
-{
-
-template<typename T>
-class HasStreamOperator
-{
- struct Yes { char unused[1]; };
- struct No { char unused[2]; };
- static_assert(sizeof(Yes) != sizeof(No));
-
- template<class C> static decltype(std::declval<QDataStream&>().operator>>(std::declval<C&>()), Yes()) load(int);
- template<class C> static decltype(operator>>(std::declval<QDataStream&>(), std::declval<C&>()), Yes()) load(int);
- template<class C> static No load(...);
- template<class C> static decltype(operator<<(std::declval<QDataStream&>(), std::declval<const C&>()), Yes()) saveFunction(int);
- template<class C> static decltype(std::declval<QDataStream&>().operator<<(std::declval<const C&>()), Yes()) saveMethod(int);
- template<class C> static No saveMethod(...);
- template<class C> static No saveFunction(...);
- static constexpr bool LoadValue = QtMetaTypePrivate::TypeDefinition<T>::IsAvailable && (sizeof(load<T>(0)) == sizeof(Yes));
- static constexpr bool SaveValue = QtMetaTypePrivate::TypeDefinition<T>::IsAvailable &&
- ((sizeof(saveMethod<T>(0)) == sizeof(Yes)) || (sizeof(saveFunction<T>(0)) == sizeof(Yes)));
-public:
- static constexpr bool Value = LoadValue && SaveValue;
-};
-
-// Quick sanity checks
-static_assert(HasStreamOperator<NS(QJsonDocument)>::Value);
-static_assert(!HasStreamOperator<void*>::Value);
-static_assert(HasStreamOperator<qint8>::Value);
-
-template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted && HasStreamOperator<T>::Value>
-struct FilteredOperatorSwitch
-{
- static bool load(QDataStream &stream, T *data, int)
- {
- stream >> *data;
- return true;
- }
- static bool save(QDataStream &stream, const T *data, int)
- {
- stream << *data;
- return true;
- }
-};
-
-template<typename T>
-struct FilteredOperatorSwitch<T, /* IsAcceptedType = */ false>
-{
- static const QMetaTypeModuleHelper *getMetaTypeInterface()
- {
- if (QModulesPrivate::QTypeModuleInfo<T>::IsGui)
- return qMetaTypeGuiHelper;
- else if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget)
- return qMetaTypeWidgetsHelper;
- return nullptr;
- }
- static bool save(QDataStream &stream, const T *data, int type)
- {
- if (auto interface = getMetaTypeInterface()) {
- return interface->save(stream, type, data);
- }
- return false;
- }
- static bool load(QDataStream &stream, T *data, int type)
- {
- if (auto interface = getMetaTypeInterface()) {
- return interface->load(stream, type, data);
- }
- return false;
- }
-};
-
-class SaveOperatorSwitch
-{
-public:
- QDataStream &stream;
- int m_type;
-
- template<typename T>
- bool delegate(const T *data)
- {
- return FilteredOperatorSwitch<T>::save(stream, data, m_type);
- }
- bool delegate(const char *data)
- {
- // force a char to be signed
- stream << qint8(*data);
- return true;
- }
- bool delegate(const long *data)
- {
- stream << qlonglong(*data);
- return true;
- }
- bool delegate(const unsigned long *data)
- {
- stream << qulonglong(*data);
- return true;
- }
- bool delegate(const QMetaTypeSwitcher::NotBuiltinType *data)
- {
- auto ct = customTypeRegistry();
- if (!ct)
- return false;
- QMetaType::SaveOperator op = nullptr;
- {
- QReadLocker lock(&ct->lock);
- op = ct->dataStreamOp.value(m_type).saveOp;
- }
- if (!op)
- return false;
- op(stream, data);
- return true;
- }
- bool delegate(const void*) { return false; }
- bool delegate(const QMetaTypeSwitcher::UnknownType*) { return false; }
-};
-class LoadOperatorSwitch
-{
-public:
- QDataStream &stream;
- int m_type;
-
- template<typename T>
- bool delegate(const T *data)
- {
- return FilteredOperatorSwitch<T>::load(stream, const_cast<T*>(data), m_type);
- }
- bool delegate(const char *data)
- {
- // force a char to be signed
- qint8 c;
- stream >> c;
- *const_cast<char*>(data) = c;
- return true;
- }
- bool delegate(const long *data)
- {
- qlonglong l;
- stream >> l;
- *const_cast<long*>(data) = l;
- return true;
- }
- bool delegate(const unsigned long *data)
- {
- qlonglong l;
- stream >> l;
- *const_cast<unsigned long*>(data) = l;
- return true;
- }
- bool delegate(const QMetaTypeSwitcher::NotBuiltinType *data)
- {
- auto ct = customTypeRegistry();
- if (!ct)
- return false;
- QMetaType::LoadOperator op = nullptr;
- {
- QReadLocker lock(&ct->lock);
- op = ct->dataStreamOp.value(m_type).loadOp;
- }
- if (!op)
- return false;
- op(stream, const_cast<QMetaTypeSwitcher::NotBuiltinType *>(data));
- return true;
- }
- bool delegate(const void*) { return false; }
- bool delegate(const QMetaTypeSwitcher::UnknownType*) { return false; }
-};
-} // namespace
-
/*!
Writes the object pointed to by \a data with the ID \a type to
the given \a stream. Returns \c true if the object is saved
successfully; otherwise returns \c false.
- The type must have been registered with qRegisterMetaType() and
- qRegisterMetaTypeStreamOperators() beforehand.
+ The type must have been registered with Q_DECLARE_METATYPE()
+ beforehand.
Normally, you should not need to call this function directly.
Instead, use QVariant's \c operator<<(), which relies on save()
to stream custom types.
- \sa load(), qRegisterMetaTypeStreamOperators()
+ \sa load()
*/
-bool QMetaType::save(QDataStream &stream, int type, const void *data)
+bool QMetaType::save(QDataStream &stream, const void *data) const
{
- if (!data)
+ if (!data || !isValid())
+ return false;
+
+ // keep compatibility for long/ulong
+ if (id() == QMetaType::Long) {
+ stream << qlonglong(*(long *)data);
+ return true;
+ } else if (id() == QMetaType::ULong) {
+ stream << qlonglong(*(unsigned long *)data);
+ return true;
+ }
+
+ if (!d_ptr->dataStreamOut)
return false;
- SaveOperatorSwitch saveOp{stream, type};
- return QMetaTypeSwitcher::switcher<bool>(saveOp, type, data);
+
+ d_ptr->dataStreamOut(d_ptr, stream, data);
+ return true;
}
/*!
+ \fn bool QMetaType::save(QDataStream &stream, int type, const void *data)
+ \overload
+ \obsolete
+*/
+
+/*!
Reads the object of the specified \a type from the given \a
stream into \a data. Returns \c true if the object is loaded
successfully; otherwise returns \c false.
- The type must have been registered with qRegisterMetaType() and
- qRegisterMetaTypeStreamOperators() beforehand.
+ The type must have been registered with Q_DECLARE_METATYPE()
+ beforehand.
Normally, you should not need to call this function directly.
Instead, use QVariant's \c operator>>(), which relies on load()
to stream custom types.
- \sa save(), qRegisterMetaTypeStreamOperators()
+ \sa save()
*/
-bool QMetaType::load(QDataStream &stream, int type, void *data)
+bool QMetaType::load(QDataStream &stream, void *data) const
{
- if (!data)
+ if (!data || !isValid())
return false;
- LoadOperatorSwitch loadOp{stream, type};
- return QMetaTypeSwitcher::switcher<bool>(loadOp, type, data);
+
+ // keep compatibility for long/ulong
+ if (id() == QMetaType::Long) {
+ qlonglong ll;
+ stream >> ll;
+ *(long *)data = long(ll);
+ return true;
+ } else if (id() == QMetaType::ULong) {
+ qulonglong ull;
+ stream >> ull;
+ *(unsigned long *)data = (unsigned long)(ull);
+ return true;
+ }
+ if (!d_ptr->dataStreamIn)
+ return false;
+
+ d_ptr->dataStreamIn(d_ptr, stream, data);
+ return true;
}
+
+/*!
+ \fn bool QMetaType::load(QDataStream &stream, int type, void *data)
+ \overload
+ \obsolete
+*/
#endif // QT_NO_DATASTREAM
/*!
@@ -1668,29 +1513,7 @@ const QMetaObject *QMetaType::metaObjectForType(int type)
\warning This function is useful only for registering an alias (typedef)
for every other use case Q_DECLARE_METATYPE and qMetaTypeId() should be used instead.
- \sa {QMetaType::}{qRegisterMetaTypeStreamOperators()}, {QMetaType::}{isRegistered()},
- Q_DECLARE_METATYPE()
-*/
-
-/*!
- \fn void qRegisterMetaTypeStreamOperators(const char *typeName)
- \relates QMetaType
- \threadsafe
-
- Registers the stream operators for the type \c{T} called \a
- typeName.
-
- Afterward, the type can be streamed using QMetaType::load() and
- QMetaType::save(). These functions are used when streaming a
- QVariant.
-
- \snippet code/src_corelib_kernel_qmetatype.cpp 5
-
- The stream operators should have the following signatures:
-
- \snippet code/src_corelib_kernel_qmetatype.cpp 6
-
- \sa qRegisterMetaType(), QMetaType::isRegistered(), Q_DECLARE_METATYPE()
+ \sa {QMetaType::}{isRegistered()}, Q_DECLARE_METATYPE()
*/
/*!