diff options
18 files changed, 225 insertions, 470 deletions
diff --git a/examples/corelib/serialization/convert/cborconverter.cpp b/examples/corelib/serialization/convert/cborconverter.cpp index 77df367e50..4fc8408983 100644 --- a/examples/corelib/serialization/convert/cborconverter.cpp +++ b/examples/corelib/serialization/convert/cborconverter.cpp @@ -232,8 +232,6 @@ void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents, cons CborConverter::CborConverter() { qRegisterMetaType<QCborTag>(); - qRegisterMetaTypeStreamOperators<QCborTag>(); - QMetaType::registerDebugStreamOperator<QCborTag>(); } QString CborConverter::name() diff --git a/examples/corelib/serialization/convert/datastreamconverter.cpp b/examples/corelib/serialization/convert/datastreamconverter.cpp index 6f0ca41ff5..c459696b26 100644 --- a/examples/corelib/serialization/convert/datastreamconverter.cpp +++ b/examples/corelib/serialization/convert/datastreamconverter.cpp @@ -171,7 +171,6 @@ void DataStreamDumper::saveFile(QIODevice *f, const QVariant &contents, const QS DataStreamConverter::DataStreamConverter() { qRegisterMetaType<VariantOrderedMap>(); - qRegisterMetaTypeStreamOperators<VariantOrderedMap>(); } QString DataStreamConverter::name() diff --git a/qmake/CMakeLists.txt b/qmake/CMakeLists.txt index 2a7549f862..2201baa06f 100644 --- a/qmake/CMakeLists.txt +++ b/qmake/CMakeLists.txt @@ -71,6 +71,7 @@ qt_add_tool(${target_name} ../src/corelib/plugin/quuid.cpp ../src/corelib/plugin/quuid.h ../src/corelib/serialization/qcborstreamwriter.cpp ../src/corelib/serialization/qcborstreamwriter.h ../src/corelib/serialization/qcborvalue.cpp ../src/corelib/serialization/qcborvalue.h ../src/corelib/serialization/qcborvalue_p.h + ../src/corelib/serialization/qdatastream.cpp ../src/corelib/serialization/qdatastream.h ../src/corelib/serialization/qjson_p.h ../src/corelib/serialization/qjsonarray.cpp ../src/corelib/serialization/qjsonarray.h ../src/corelib/serialization/qjsoncbor.cpp diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp index d28a0ac956..a91458cc95 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp @@ -97,11 +97,6 @@ qRegisterMetaType<MyClass>("MyClass"); //! [4] -//! [5] -qRegisterMetaTypeStreamOperators<MyClass>("MyClass"); -//! [5] - - //! [6] QDataStream &operator<<(QDataStream &out, const MyClass &myObj); QDataStream &operator>>(QDataStream &in, MyClass &myObj); diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 6165cd2af2..0a62ffb2be 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -1979,8 +1979,9 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \snippet code/src_corelib_io_qsettings.cpp 1 - Custom types registered using qRegisterMetaType() and - qRegisterMetaTypeStreamOperators() can be stored using QSettings. + Custom types registered using qRegisterMetaType() that have + operators for streaming to and from a QDataStream can be stored + using QSettings. \section1 Section and Key Syntax 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(®->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() */ /*! diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index ced3444020..8e8ecac0a0 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -249,7 +249,6 @@ inline constexpr int qMetaTypeId(); F(QPointer) class QDataStream; -class QMetaTypeInterface; struct QMetaObject; namespace QtPrivate @@ -267,36 +266,6 @@ To convertImplicit(const From& from) return from; } -#ifndef QT_NO_DEBUG_STREAM -struct AbstractDebugStreamFunction -{ - typedef void (*Stream)(const AbstractDebugStreamFunction *, QDebug&, const void *); - typedef void (*Destroy)(AbstractDebugStreamFunction *); - explicit AbstractDebugStreamFunction(Stream s = nullptr, Destroy d = nullptr) - : stream(s), destroy(d) {} - Q_DISABLE_COPY(AbstractDebugStreamFunction) - Stream stream; - Destroy destroy; -}; - -template<typename T> -struct BuiltInDebugStreamFunction : public AbstractDebugStreamFunction -{ - BuiltInDebugStreamFunction() - : AbstractDebugStreamFunction(stream, destroy) {} - static void stream(const AbstractDebugStreamFunction *, QDebug& dbg, const void *r) - { - const T *rhs = static_cast<const T *>(r); - operator<<(dbg, *rhs); - } - - static void destroy(AbstractDebugStreamFunction *_this) - { - delete static_cast<BuiltInDebugStreamFunction *>(_this); - } -}; -#endif - struct AbstractConverterFunction { typedef bool (*Converter)(const AbstractConverterFunction *, const void *, void*); @@ -461,14 +430,6 @@ public: }; Q_DECLARE_FLAGS(TypeFlags, TypeFlag) - typedef void (*SaveOperator)(QDataStream &, const void *); - typedef void (*LoadOperator)(QDataStream &, void *); -#ifndef QT_NO_DATASTREAM - static void registerStreamOperators(const char *typeName, SaveOperator saveOp, - LoadOperator loadOp); - static void registerStreamOperators(int type, SaveOperator saveOp, - LoadOperator loadOp); -#endif static void registerNormalizedTypedef(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, QMetaType type); static int type(const char *typeName); @@ -484,11 +445,6 @@ public: static void *construct(int type, void *where, const void *copy); static void destruct(int type, void *where); -#ifndef QT_NO_DATASTREAM - static bool save(QDataStream &stream, int type, const void *data); - static bool load(QDataStream &stream, int type, void *data); -#endif - explicit QMetaType(int type); explicit QMetaType(QtPrivate::QMetaTypeInterface *d); constexpr QMetaType() : d_ptr(nullptr) {} @@ -521,6 +477,20 @@ public: bool isEqualityComparable() const; bool isOrdered() const; +#ifndef QT_NO_DATASTREAM + bool save(QDataStream &stream, const void *data) const; + bool load(QDataStream &stream, void *data) const; + +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_6_0 + static bool save(QDataStream &stream, int type, const void *data) + { return QMetaType(type).save(stream, data); } + QT_DEPRECATED_VERSION_6_0 + static bool load(QDataStream &stream, int type, void *data) + { return QMetaType(type).load(stream, data); } +#endif +#endif + template<typename T> static QMetaType fromType(); @@ -530,22 +500,21 @@ public: public: #ifndef QT_NO_DEBUG_STREAM - template<typename T> - static bool registerDebugStreamOperator() - { - static_assert((!QMetaTypeId2<T>::IsBuiltIn), - "QMetaType::registerDebugStreamOperator: The type must be a custom type."); + bool debugStream(QDebug& dbg, const void *rhs); + bool hasRegisteredDebugStreamOperator() const; - const int typeId = qMetaTypeId<T>(); - static const QtPrivate::BuiltInDebugStreamFunction<T> f; - return registerDebugStreamOperatorFunction(&f, typeId); - } +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_6_0 + static bool debugStream(QDebug& dbg, const void *rhs, int typeId) + { return QMetaType(typeId).debugStream(dbg, rhs); } template<typename T> + QT_DEPRECATED_VERSION_6_0 static bool hasRegisteredDebugStreamOperator() - { - return hasRegisteredDebugStreamOperator(qMetaTypeId<T>()); - } - static bool hasRegisteredDebugStreamOperator(int typeId); + { return QMetaType::fromType<T>().hasRegisteredDebugStreamOperator(); } + QT_DEPRECATED_VERSION_6_0 + static bool hasRegisteredDebugStreamOperator(int typeId) + { return QMetaType(typeId).hasRegisteredDebugStreamOperator(); } +#endif #endif // implicit conversion supported like double -> float @@ -628,8 +597,6 @@ public: } #endif - static bool debugStream(QDebug& dbg, const void *rhs, int typeId); - template<typename From, typename To> static bool hasRegisteredConverterFunction() { @@ -638,10 +605,6 @@ public: static bool hasRegisteredConverterFunction(int fromTypeId, int toTypeId); -#ifndef QT_NO_DEBUG_STREAM - static bool registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f, int type); -#endif - #ifndef Q_CLANG_QDOC template<typename, bool> friend struct QtPrivate::ValueTypeIsMetaType; template<typename, typename> friend struct QtPrivate::ConverterMemberFunction; @@ -1751,20 +1714,6 @@ int qRegisterMetaType(const char *typeName return qRegisterNormalizedMetaType<T>(normalizedTypeName, dummy, defined); } -#ifndef QT_NO_DATASTREAM -template <typename T> -void qRegisterMetaTypeStreamOperators(const char *typeName -#ifndef Q_CLANG_QDOC - , T * /* dummy */ = nullptr -#endif -) -{ - qRegisterMetaType<T>(typeName); - QMetaType::registerStreamOperators(typeName, QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Save, - QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Load); -} -#endif // QT_NO_DATASTREAM - template <typename T> inline constexpr int qMetaTypeId() { @@ -1889,17 +1838,6 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> }; #endif -#ifndef QT_NO_DATASTREAM -template <typename T> -inline int qRegisterMetaTypeStreamOperators() -{ - int id = qMetaTypeId<T>(); - QMetaType::registerStreamOperators(id, QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Save, - QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Load); - return id; -} -#endif - #define Q_DECLARE_OPAQUE_POINTER(POINTER) \ QT_BEGIN_NAMESPACE namespace QtPrivate { \ template <> \ @@ -2245,6 +2183,12 @@ public: EqualsFn equals; using LessThanFn = bool (*)(const QMetaTypeInterface *, const void *, const void *); LessThanFn lessThan; + using DebugStreamFn = void (*)(const QMetaTypeInterface *, QDebug &, const void *); + DebugStreamFn debugStream; + using DataStreamOutFn = void (*)(const QMetaTypeInterface *, QDataStream &, const void *); + DataStreamOutFn dataStreamOut; + using DataStreamInFn = void (*)(const QMetaTypeInterface *, QDataStream &, void *); + DataStreamInFn dataStreamIn; using LegacyRegisterOp = void (*)(); LegacyRegisterOp legacyRegisterOp; @@ -2692,6 +2636,35 @@ struct QLessThanOperatorForType <T, false> static constexpr QMetaTypeInterface::LessThanFn lessThan = nullptr; }; +template<typename T, bool = QTypeTraits::has_ostream_operator_v<QDebug, T>> +struct QDebugStreamOperatorForType +{ + static void debugStream(const QMetaTypeInterface *, QDebug &dbg, const void *a) + { dbg << *reinterpret_cast<const T *>(a); } +}; + +template<typename T> +struct QDebugStreamOperatorForType <T, false> +{ + static constexpr QMetaTypeInterface::DebugStreamFn debugStream = nullptr; +}; + +template<typename T, bool = QTypeTraits::has_stream_operator_v<QDataStream, T>> +struct QDataStreamOperatorForType +{ + static void dataStreamOut(const QMetaTypeInterface *, QDataStream &ds, const void *a) + { ds << *reinterpret_cast<const T *>(a); } + static void dataStreamIn(const QMetaTypeInterface *, QDataStream &ds, void *a) + { ds >> *reinterpret_cast<T *>(a); } +}; + +template<typename T> +struct QDataStreamOperatorForType <T, false> +{ + static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr; + static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr; +}; + template<typename S> class QMetaTypeForType { @@ -2780,6 +2753,9 @@ QMetaTypeInterface QMetaTypeForType<T>::metaType = { /*.dtor=*/ getDtor<T>(), /*.equals=*/ QEqualityOperatorForType<T>::equals, /*.lessThan=*/ QLessThanOperatorForType<T>::lessThan, + /*.debugStream=*/ QDebugStreamOperatorForType<T>::debugStream, + /*.dataStreamOut=*/ QDataStreamOperatorForType<T>::dataStreamOut, + /*.dataStreamIn=*/ QDataStreamOperatorForType<T>::dataStreamIn, /*.legacyRegisterOp=*/ getLegacyRegister<T>() }; @@ -2809,6 +2785,9 @@ public: /*.dtor=*/ nullptr, /*.equals=*/ nullptr, /*.lessThan=*/ nullptr, + /*.debugStream=*/ nullptr, + /*.dataStreamOut=*/ nullptr, + /*.dataStreamIn=*/ nullptr, /*.legacyRegisterOp=*/ nullptr }; }; diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp index 21a1350fc5..f2641adcd8 100644 --- a/src/corelib/kernel/qmimedata.cpp +++ b/src/corelib/kernel/qmimedata.cpp @@ -583,11 +583,9 @@ QByteArray QMimeData::data(const QString &mimeType) const Note that if you want to use a custom data type in an item view drag and drop operation, you must register it as a Qt \l{QMetaType}{meta type}, using the - Q_DECLARE_METATYPE() macro, and implement stream operators for it. The stream - operators must then be registered with the qRegisterMetaTypeStreamOperators() - function. + Q_DECLARE_METATYPE() macro, and implement stream operators for it. - \sa hasFormat(), QMetaType, {QMetaType::}{qRegisterMetaTypeStreamOperators()} + \sa hasFormat(), QMetaType, {QMetaType::}{Q_DECLARE_METATYPE()} */ void QMimeData::setData(const QString &mimeType, const QByteArray &data) { diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index ff8fd38f0e..a140952559 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2437,7 +2437,8 @@ void QVariant::load(QDataStream &s) } // const cast is safe since we operate on a newly constructed variant - if (!QMetaType::load(s, d.type().id(), const_cast<void *>(constData()))) { + void *data = const_cast<void *>(constData()); + if (!d.type().load(s, data)) { s.setStatus(QDataStream::ReadCorruptData); qWarning("QVariant::load: unable to load type %d.", d.type().id()); } @@ -2512,7 +2513,7 @@ void QVariant::save(QDataStream &s) const return; } - if (!QMetaType::save(s, d.type().id(), constData())) { + if (!d.type().save(s, constData())) { qWarning("QVariant::save: unable to save type '%s' (type id: %d).\n", QMetaType::typeName(d.type().id()), d.type().id()); Q_ASSERT_X(false, "QVariant::save", "Invalid type to save"); @@ -3977,7 +3978,7 @@ QDebug operator<<(QDebug dbg, const QVariant &v) bool userStream = false; bool canConvertToString = false; if (typeId >= QMetaType::User) { - userStream = QMetaType::debugStream(dbg, constData(v.d), typeId); + userStream = v.d.type().debugStream(dbg, constData(v.d)); canConvertToString = v.canConvert<QString>(); } if (!userStream && canConvertToString) diff --git a/src/corelib/serialization/qcborcommon.h b/src/corelib/serialization/qcborcommon.h index 1497da3d2e..f5e38b5a22 100644 --- a/src/corelib/serialization/qcborcommon.h +++ b/src/corelib/serialization/qcborcommon.h @@ -133,7 +133,7 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, QCborKnownTags tg); Q_CORE_EXPORT QDebug operator<<(QDebug, QCborTag tg); #endif -#if !defined(QT_NO_DEBUG_STREAM) +#if !defined(QT_NO_DATASTREAM) QDataStream &operator<<(QDataStream &ds, QCborSimpleType st); QDataStream &operator>>(QDataStream &ds, QCborSimpleType &st); #endif diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h index e8ef032c24..25c95bc2a5 100644 --- a/src/corelib/tools/qbitarray.h +++ b/src/corelib/tools/qbitarray.h @@ -48,8 +48,10 @@ QT_BEGIN_NAMESPACE class QBitRef; class Q_CORE_EXPORT QBitArray { +#ifndef QT_NO_DATASTREAM friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QBitArray &); friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QBitArray &); +#endif friend Q_CORE_EXPORT size_t qHash(const QBitArray &key, size_t seed) noexcept; QByteArray d; diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index d308151984..5162d07e0d 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -139,7 +139,9 @@ static int registerComplexDBusType(const QByteArray &typeName) [](QtPrivate::QMetaTypeInterface *self) { delete static_cast<QDBusRawTypeHandler *>(self); }, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr }, name(name) {} diff --git a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp index 6b59a6f1af..3185dbcaf4 100644 --- a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp +++ b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp @@ -106,6 +106,8 @@ private: QItemSelectionModel *selection; }; +QT_BEGIN_NAMESPACE + QDataStream &operator<<(QDataStream &, const QModelIndex &); QDataStream &operator>>(QDataStream &, QModelIndex &); QDataStream &operator<<(QDataStream &, const QModelIndexList &); @@ -178,6 +180,8 @@ QDataStream &operator>>(QDataStream &s, QModelIndexList &output) return s; } +QT_END_NAMESPACE + tst_QItemSelectionModel::tst_QItemSelectionModel() : model(0), selection(0) { diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 6f916372e5..6f844e2fb4 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -217,7 +217,6 @@ private slots: void isRegisteredStaticLess_data(); void isRegisteredStaticLess(); void isEnum(); - void registerStreamBuiltin(); void automaticTemplateRegistration(); void saveAndLoadBuiltin_data(); void saveAndLoadBuiltin(); @@ -351,12 +350,12 @@ static void *GadgetTypedConstructor(int type, void *where, const void *copy) return it->first->constructor(type, where, copy); } -static void GadgetSaveOperator(QDataStream & out, const void *data) +static void GadgetSaveOperator(const QtPrivate::QMetaTypeInterface *, QDataStream & out, const void *data) { reinterpret_cast<const BaseGenericType *>(data)->saveOperator(out); } -static void GadgetLoadOperator(QDataStream &in, void *data) +static void GadgetLoadOperator(const QtPrivate::QMetaTypeInterface *, QDataStream &in, void *data) { reinterpret_cast<BaseGenericType *>(data)->loadOperator(in); } @@ -424,12 +423,15 @@ void tst_QMetaType::registerGadget(const char *name, const QList<GadgetPropertyT [](const TypeInfo *self, void *ptr) { GadgetTypedDestructor(self->typeId, ptr); }, nullptr, nullptr, - nullptr }; + nullptr, + GadgetSaveOperator, + GadgetLoadOperator, + nullptr + }; QMetaType gadgetMetaType(typeInfo); dynamicGadgetProperties->m_metatype = gadgetMetaType; int gadgetTypeId = QMetaType(typeInfo).id(); QVERIFY(gadgetTypeId > 0); - QMetaType::registerStreamOperators(gadgetTypeId, &GadgetSaveOperator, &GadgetLoadOperator); s_managedTypes[gadgetTypeId] = qMakePair(dynamicGadgetProperties, std::shared_ptr<QMetaObject>{meta, [](QMetaObject *ptr){ ::free(ptr); }}); } @@ -1326,12 +1328,17 @@ void tst_QMetaType::typedConstruct() [](const TypeInfo *self, void *where, const void *copy) { GadgetTypedConstructor(self->typeId, where, copy); }, [](const TypeInfo *self, void *where, void *copy) { GadgetTypedConstructor(self->typeId, where, copy); }, [](const TypeInfo *self, void *ptr) { GadgetTypedDestructor(self->typeId, ptr); }, - nullptr, nullptr, nullptr }; + nullptr, + nullptr, + nullptr, + GadgetSaveOperator, + GadgetLoadOperator, + nullptr + }; QMetaType metatype(typeInfo); dynamicGadgetProperties->m_metatype = metatype; int podTypeId = metatype.id(); QVERIFY(podTypeId > 0); - QMetaType::registerStreamOperators(podTypeId, &GadgetSaveOperator, &GadgetLoadOperator); s_managedTypes[podTypeId] = qMakePair(dynamicGadgetProperties, std::shared_ptr<QMetaObject>{}); // Test POD @@ -1552,13 +1559,6 @@ void tst_QMetaType::isRegisteredStaticLess() QCOMPARE(QMetaType(typeId).isRegistered(), registered); } -void tst_QMetaType::registerStreamBuiltin() -{ - //should not crash; - qRegisterMetaTypeStreamOperators<QString>("QString"); - qRegisterMetaTypeStreamOperators<QVariant>("QVariant"); -} - typedef QHash<int, uint> IntUIntHash; Q_DECLARE_METATYPE(IntUIntHash) typedef QMap<int, uint> IntUIntMap; @@ -2044,7 +2044,6 @@ struct CustomStreamableType { int a; }; -Q_DECLARE_METATYPE(CustomStreamableType) QDataStream &operator<<(QDataStream &out, const CustomStreamableType &t) { @@ -2059,6 +2058,7 @@ QDataStream &operator>>(QDataStream &in, CustomStreamableType &t) t.a = a; return in; } +Q_DECLARE_METATYPE(CustomStreamableType) void tst_QMetaType::saveAndLoadCustom() { @@ -2068,12 +2068,7 @@ void tst_QMetaType::saveAndLoadCustom() int id = ::qMetaTypeId<CustomStreamableType>(); QByteArray ba; QDataStream stream(&ba, QIODevice::ReadWrite); - QVERIFY(!QMetaType::save(stream, id, &t)); - QCOMPARE(stream.status(), QDataStream::Ok); - QVERIFY(!QMetaType::load(stream, id, &t)); - QCOMPARE(stream.status(), QDataStream::Ok); - qRegisterMetaTypeStreamOperators<CustomStreamableType>("CustomStreamableType"); QVERIFY(QMetaType::save(stream, id, &t)); QCOMPARE(stream.status(), QDataStream::Ok); @@ -2278,6 +2273,11 @@ struct CustomDebugStreamableType QString toString() const { return "test"; } }; +struct CustomDebugStreamableType2 +{ + QString toString() const { return "test"; } +}; + QDebug operator<<(QDebug dbg, const CustomDebugStreamableType&) { return dbg << "string-content"; @@ -2607,16 +2607,14 @@ void tst_QMetaType::customDebugStream() { MessageHandlerCustom handler(::qMetaTypeId<CustomDebugStreamableType>()); QVariant v1 = QVariant::fromValue(CustomDebugStreamableType()); - handler.expectedMessage = "QVariant(CustomDebugStreamableType, )"; - qDebug() << v1; - - QMetaType::registerConverter<CustomDebugStreamableType, QString>(&CustomDebugStreamableType::toString); - handler.expectedMessage = "QVariant(CustomDebugStreamableType, \"test\")"; - qDebug() << v1; - - QMetaType::registerDebugStreamOperator<CustomDebugStreamableType>(); handler.expectedMessage = "QVariant(CustomDebugStreamableType, string-content)"; qDebug() << v1; + + MessageHandlerCustom handler2(::qMetaTypeId<CustomDebugStreamableType2>()); + QMetaType::registerConverter<CustomDebugStreamableType2, QString>(&CustomDebugStreamableType2::toString); + handler2.expectedMessage = "QVariant(CustomDebugStreamableType2, \"test\")"; + QVariant v2 = QVariant::fromValue(CustomDebugStreamableType2()); + qDebug() << v2; } void tst_QMetaType::unknownType() diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 231cccc38d..83ec36253a 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -1405,6 +1405,20 @@ struct CustomType int value() { return i1 + i2 + i3; } }; +QDataStream &operator<<(QDataStream &stream, const CustomType &ct) +{ + stream << ct.i1 << ct.i2 << ct.i3; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, CustomType &ct) +{ + stream >> ct.i1; + stream >> ct.i2; + stream >> ct.i3; + return stream; +} + Q_DECLARE_METATYPE(CustomType*) Q_DECLARE_METATYPE(CustomType) @@ -1475,26 +1489,11 @@ void tst_QObject::customTypes() QCOMPARE(instanceCount, 3); } -QDataStream &operator<<(QDataStream &stream, const CustomType &ct) -{ - stream << ct.i1 << ct.i2 << ct.i3; - return stream; -} - -QDataStream &operator>>(QDataStream &stream, CustomType &ct) -{ - stream >> ct.i1; - stream >> ct.i2; - stream >> ct.i3; - return stream; -} - void tst_QObject::streamCustomTypes() { QByteArray ba; int idx = qRegisterMetaType<CustomType>("CustomType"); - qRegisterMetaTypeStreamOperators<CustomType>("CustomType"); { CustomType t1(1, 2, 3); diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index aeac08fc34..02a537a9d6 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -1222,7 +1222,6 @@ struct CustomStreamableClass return i == other.i; } }; -Q_DECLARE_METATYPE(CustomStreamableClass); QDataStream &operator<<(QDataStream &out, const CustomStreamableClass &myObj) { @@ -1233,11 +1232,10 @@ QDataStream &operator>>(QDataStream &in, CustomStreamableClass &myObj) { return in >> myObj.i; } +Q_DECLARE_METATYPE(CustomStreamableClass); void tst_QVariant::writeToReadFromDataStream_data() { - qRegisterMetaTypeStreamOperators<CustomStreamableClass>(); - QTest::addColumn<QVariant>("writeVariant"); QTest::addColumn<bool>("isNull"); { @@ -2184,8 +2182,6 @@ void tst_QVariant::saveLoadCustomTypes() auto tp = QMetaType::fromType<Blah>(); QVariant v = QVariant(tp, &i); - qRegisterMetaTypeStreamOperators<Blah>("Blah"); - QCOMPARE(v.userType(), tp.id()); QCOMPARE(v.type(), QVariant::UserType); { @@ -4639,8 +4635,6 @@ void tst_QVariant::fromStdVariant() void tst_QVariant::qt4UuidDataStream() { - qRegisterMetaTypeStreamOperators<QUuid>(); - QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream.setVersion(QDataStream::Qt_4_8); diff --git a/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp b/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp index 1e9e1f40d6..22ca31fcb7 100644 --- a/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp +++ b/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp @@ -741,8 +741,6 @@ void tst_QGuiVariant::guiVariantAtExit() void tst_QGuiVariant::qt4QPolygonFDataStream() { - qRegisterMetaTypeStreamOperators<QPolygonF>(); - QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream.setVersion(QDataStream::Qt_4_8); diff --git a/tests/auto/other/compiler/tst_compiler.cpp b/tests/auto/other/compiler/tst_compiler.cpp index 10d91894b7..438058aa45 100644 --- a/tests/auto/other/compiler/tst_compiler.cpp +++ b/tests/auto/other/compiler/tst_compiler.cpp @@ -297,35 +297,6 @@ namespace QtTestInternal }; #endif }; - - template<bool> - struct DataStreamOpHelper - { - template <typename T> - struct Getter { - static QMetaType::SaveOperator saveOp() { return 0; } - }; - }; - - template<> - struct DataStreamOpHelper<true> - { - template <typename T> - struct Getter { - static QMetaType::SaveOperator saveOp() - { - return ::QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Save; - } - }; - - }; - - template<typename T> - inline QMetaType::SaveOperator getSaveOperator(T * = 0) - { - typedef typename DataStreamOpHelper<DataStreamChecker<T>::HasDataStream>::template Getter<T> GetterHelper; - return GetterHelper::saveOp(); - } }; struct MyString: public QString {}; @@ -344,14 +315,6 @@ void tst_Compiler::detectDataStream() QVERIFY(QtTestInternal::DataStreamChecker<QString>::HasDataStream); QVERIFY(QtTestInternal::DataStreamChecker<MyString>::HasDataStream); QVERIFY(!QtTestInternal::DataStreamChecker<Qxxx>::HasDataStream); - - QVERIFY(QtTestInternal::getSaveOperator<int>() != 0); - QVERIFY(QtTestInternal::getSaveOperator<uint>() != 0); - QVERIFY(QtTestInternal::getSaveOperator<char *>() != 0); - QVERIFY(QtTestInternal::getSaveOperator<double>() != 0); - QVERIFY(QtTestInternal::getSaveOperator<QString>() != 0); - QVERIFY(QtTestInternal::getSaveOperator<MyString>() != 0); - QVERIFY(!QtTestInternal::getSaveOperator<Qxxx>()); } #else void tst_Compiler::detectDataStream() |