| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtCore module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qmetatype.h" |
| #include "qmetatype_p.h" |
| #include "qobjectdefs.h" |
| #include "qdatetime.h" |
| #include "qbytearray.h" |
| #include "qreadwritelock.h" |
| #include "qstring.h" |
| #include "qstringlist.h" |
| #include "qvector.h" |
| #include "qlocale.h" |
| #if QT_CONFIG(easingcurve) |
| #include "qeasingcurve.h" |
| #endif |
| #include "quuid.h" |
| #include "qvariant.h" |
| #include "qdatastream.h" |
| #include "qregexp.h" |
| #include "qmetatypeswitcher_p.h" |
| |
| #if QT_CONFIG(regularexpression) |
| # include "qregularexpression.h" |
| #endif |
| |
| #ifndef QT_BOOTSTRAPPED |
| # include "qbitarray.h" |
| # include "qurl.h" |
| # include "qvariant.h" |
| # include "qjsonvalue.h" |
| # include "qjsonobject.h" |
| # include "qjsonarray.h" |
| # include "qjsondocument.h" |
| # include "qcborvalue.h" |
| # include "qcborarray.h" |
| # include "qcbormap.h" |
| # include "qbytearraylist.h" |
| #endif |
| |
| #if QT_CONFIG(itemmodel) |
| # include "qabstractitemmodel.h" |
| #endif |
| |
| #ifndef QT_NO_GEOM_VARIANT |
| # include "qsize.h" |
| # include "qpoint.h" |
| # include "qrect.h" |
| # include "qline.h" |
| #endif |
| |
| QT_BEGIN_NAMESPACE |
| |
| #define NS(x) QT_PREPEND_NAMESPACE(x) |
| |
| |
| namespace { |
| struct DefinedTypesFilter { |
| template<typename T> |
| struct Acceptor { |
| static const bool IsAccepted = QtMetaTypePrivate::TypeDefinition<T>::IsAvailable && QModulesPrivate::QTypeModuleInfo<T>::IsCore; |
| }; |
| }; |
| } // namespace |
| |
| /*! |
| \macro Q_DECLARE_OPAQUE_POINTER(PointerType) |
| \relates QMetaType |
| \since 5.0 |
| |
| This macro enables pointers to forward-declared types (\a PointerType) |
| to be registered with QMetaType using either Q_DECLARE_METATYPE() |
| or qRegisterMetaType(). |
| |
| \sa Q_DECLARE_METATYPE(), qRegisterMetaType() |
| */ |
| |
| /*! |
| \macro Q_DECLARE_METATYPE(Type) |
| \relates QMetaType |
| |
| This macro makes the type \a Type known to QMetaType as long as it |
| provides a public default constructor, a public copy constructor and |
| a public destructor. |
| It is needed to use the type \a Type as a custom type in QVariant. |
| |
| This macro requires that \a Type is a fully defined type at the point where |
| it is used. For pointer types, it also requires that the pointed to type is |
| fully defined. Use in conjunction with Q_DECLARE_OPAQUE_POINTER() to |
| register pointers to forward declared types. |
| |
| Ideally, this macro should be placed below the declaration of |
| the class or struct. If that is not possible, it can be put in |
| a private header file which has to be included every time that |
| type is used in a QVariant. |
| |
| Adding a Q_DECLARE_METATYPE() makes the type known to all template |
| based functions, including QVariant. Note that if you intend to |
| use the type in \e queued signal and slot connections or in |
| QObject's property system, you also have to call |
| qRegisterMetaType() since the names are resolved at runtime. |
| |
| This example shows a typical use case of Q_DECLARE_METATYPE(): |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 0 |
| |
| If \c MyStruct is in a namespace, the Q_DECLARE_METATYPE() macro |
| has to be outside the namespace: |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 1 |
| |
| Since \c{MyStruct} is now known to QMetaType, it can be used in QVariant: |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 2 |
| |
| Some types are registered automatically and do not need this macro: |
| |
| \list |
| \li Pointers to classes derived from QObject |
| \li QList<T>, QVector<T>, QQueue<T>, QStack<T>, QSet<T> or QLinkedList<T> |
| where T is a registered meta type |
| \li QHash<T1, T2>, QMap<T1, T2> or QPair<T1, T2> where T1 and T2 are |
| registered meta types |
| \li QPointer<T>, QSharedPointer<T>, QWeakPointer<T>, where T is a class that derives from QObject |
| \li Enumerations registered with Q_ENUM or Q_FLAG |
| \li Classes that have a Q_GADGET macro |
| \endlist |
| |
| \sa qRegisterMetaType() |
| */ |
| |
| /*! |
| \macro Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(Container) |
| \relates QMetaType |
| |
| This macro makes the container \a Container known to QMetaType as a sequential |
| container. This makes it possible to put an instance of Container<T> into |
| a QVariant, if T itself is known to QMetaType. |
| |
| Note that all of the Qt sequential containers already have built-in |
| support, and it is not necessary to use this macro with them. The |
| std::vector and std::list containers also have built-in support. |
| |
| This example shows a typical use of Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(): |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 10 |
| */ |
| |
| /*! |
| \macro Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(Container) |
| \relates QMetaType |
| |
| This macro makes the container \a Container known to QMetaType as an associative |
| container. This makes it possible to put an instance of Container<T, U> into |
| a QVariant, if T and U are themselves known to QMetaType. |
| |
| Note that all of the Qt associative containers already have built-in |
| support, and it is not necessary to use this macro with them. The |
| std::map container also has built-in support. |
| |
| This example shows a typical use of Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(): |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 11 |
| */ |
| |
| /*! |
| \macro Q_DECLARE_SMART_POINTER_METATYPE(SmartPointer) |
| \relates QMetaType |
| |
| This macro makes the smart pointer \a SmartPointer known to QMetaType as a |
| smart pointer. This makes it possible to put an instance of SmartPointer<T> into |
| a QVariant, if T is a type which inherits QObject. |
| |
| Note that the QWeakPointer, QSharedPointer and QPointer already have built-in |
| support, and it is not necessary to use this macro with them. |
| |
| This example shows a typical use of Q_DECLARE_SMART_POINTER_METATYPE(): |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 13 |
| */ |
| |
| /*! |
| \enum QMetaType::Type |
| |
| These are the built-in types supported by QMetaType: |
| |
| \value Void \c void |
| \value Bool \c bool |
| \value Int \c int |
| \value UInt \c{unsigned int} |
| \value Double \c double |
| \value QChar QChar |
| \value QString QString |
| \value QByteArray QByteArray |
| \value Nullptr \c{std::nullptr_t} |
| |
| \value VoidStar \c{void *} |
| \value Long \c{long} |
| \value LongLong LongLong |
| \value Short \c{short} |
| \value Char \c{char} |
| \value ULong \c{unsigned long} |
| \value ULongLong ULongLong |
| \value UShort \c{unsigned short} |
| \value SChar \c{signed char} |
| \value UChar \c{unsigned char} |
| \value Float \c float |
| \value QObjectStar QObject * |
| \value QVariant QVariant |
| |
| \value QCursor QCursor |
| \value QDate QDate |
| \value QSize QSize |
| \value QTime QTime |
| \value QVariantList QVariantList |
| \value QPolygon QPolygon |
| \value QPolygonF QPolygonF |
| \value QColor QColor |
| \value QSizeF QSizeF |
| \value QRectF QRectF |
| \value QLine QLine |
| \value QTextLength QTextLength |
| \value QStringList QStringList |
| \value QVariantMap QVariantMap |
| \value QVariantHash QVariantHash |
| \value QIcon QIcon |
| \value QPen QPen |
| \value QLineF QLineF |
| \value QTextFormat QTextFormat |
| \value QRect QRect |
| \value QPoint QPoint |
| \value QUrl QUrl |
| \value QRegExp QRegExp |
| \value QRegularExpression QRegularExpression |
| \value QDateTime QDateTime |
| \value QPointF QPointF |
| \value QPalette QPalette |
| \value QFont QFont |
| \value QBrush QBrush |
| \value QRegion QRegion |
| \value QBitArray QBitArray |
| \value QImage QImage |
| \value QKeySequence QKeySequence |
| \value QSizePolicy QSizePolicy |
| \value QPixmap QPixmap |
| \value QLocale QLocale |
| \value QBitmap QBitmap |
| \value QMatrix QMatrix |
| \value QTransform QTransform |
| \value QMatrix4x4 QMatrix4x4 |
| \value QVector2D QVector2D |
| \value QVector3D QVector3D |
| \value QVector4D QVector4D |
| \value QQuaternion QQuaternion |
| \value QEasingCurve QEasingCurve |
| \value QJsonValue QJsonValue |
| \value QJsonObject QJsonObject |
| \value QJsonArray QJsonArray |
| \value QJsonDocument QJsonDocument |
| \value QCborValue QCborValue |
| \value QCborArray QCborArray |
| \value QCborMap QCborMap |
| \value QCborSimpleType QCborSimpleType |
| \value QModelIndex QModelIndex |
| \value QPersistentModelIndex QPersistentModelIndex (since 5.5) |
| \value QUuid QUuid |
| \value QByteArrayList QByteArrayList |
| |
| \value User Base value for user types |
| \value UnknownType This is an invalid type id. It is returned from QMetaType for types that are not registered |
| \omitvalue LastCoreType |
| \omitvalue LastGuiType |
| |
| Additional types can be registered using Q_DECLARE_METATYPE(). |
| |
| \sa type(), typeName() |
| */ |
| |
| /*! |
| \enum QMetaType::TypeFlag |
| |
| The enum describes attributes of a type supported by QMetaType. |
| |
| \value NeedsConstruction This type has non-trivial constructors. If the flag is not set instances can be safely initialized with memset to 0. |
| \value NeedsDestruction This type has a non-trivial destructor. If the flag is not set calls to the destructor are not necessary before discarding objects. |
| \value MovableType An instance of a type having this attribute can be safely moved by memcpy. |
| \omitvalue SharedPointerToQObject |
| \value IsEnumeration This type is an enumeration |
| \value PointerToQObject This type is a pointer to a derived of QObject |
| \omitvalue WeakPointerToQObject |
| \omitvalue TrackingPointerToQObject |
| \omitvalue WasDeclaredAsMetaType |
| \omitvalue IsGadget \omit This type is a Q_GADGET and it's corresponding QMetaObject can be accessed with QMetaType::metaObject Since 5.5. \endomit |
| \omitvalue PointerToGadget |
| */ |
| |
| /*! |
| \class QMetaType |
| \inmodule QtCore |
| \brief The QMetaType class manages named types in the meta-object system. |
| |
| \ingroup objectmodel |
| \threadsafe |
| |
| The class is used as a helper to marshall types in QVariant and |
| in queued signals and slots connections. It associates a type |
| name to a type so that it can be created and destructed |
| dynamically at run-time. Declare new types with Q_DECLARE_METATYPE() |
| to make them available to QVariant and other template-based functions. |
| Call qRegisterMetaType() to make types available to non-template based |
| functions, such as the queued signal and slot connections. |
| |
| Any class or struct that has a public default |
| constructor, a public copy constructor, and a public destructor |
| can be registered. |
| |
| The following code allocates and destructs an instance of |
| \c{MyClass}: |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 3 |
| |
| If we want the stream operators \c operator<<() and \c |
| operator>>() to work on QVariant objects that store custom types, |
| the custom type must provide \c operator<<() and \c operator>>() |
| operators. |
| |
| \sa Q_DECLARE_METATYPE(), QVariant::setValue(), QVariant::value(), QVariant::fromValue() |
| */ |
| |
| /*! |
| \fn bool QMetaType::isValid() const |
| \since 5.0 |
| |
| Returns \c true if this QMetaType object contains valid |
| information about a type, false otherwise. |
| */ |
| |
| /*! |
| \fn bool QMetaType::isRegistered() const |
| \since 5.0 |
| |
| Returns \c true if this QMetaType object contains valid |
| information about a type, false otherwise. |
| */ |
| |
| /*! |
| \fn int QMetaType::id() const |
| \since 5.13 |
| |
| Returns id type hold by this QMetatype instance. |
| */ |
| |
| /*! |
| \fn bool QMetaType::sizeOf() const |
| \since 5.0 |
| |
| Returns the size of the type in bytes (i.e. sizeof(T), |
| where T is the actual type for which this QMetaType instance |
| was constructed for). |
| |
| This function is typically used together with construct() |
| to perform low-level management of the memory used by a type. |
| |
| \sa QMetaType::construct(), QMetaType::sizeOf() |
| */ |
| |
| /*! |
| \fn TypeFlags QMetaType::flags() const |
| \since 5.0 |
| |
| Returns flags of the type for which this QMetaType instance was constructed. |
| |
| \sa QMetaType::TypeFlags, QMetaType::typeFlags() |
| */ |
| |
| /*! |
| \fn const QMetaObject *QMetaType::metaObject() const |
| \since 5.5 |
| |
| return a QMetaObject relative to this type. |
| |
| If the type is a pointer type to a subclass of QObject, flags() contains |
| QMetaType::PointerToQObject and this function returns the corresponding QMetaObject. This can |
| be used to in combinaison with QMetaObject::construct to create QObject of this type. |
| |
| If the type is a Q_GADGET, flags() contains QMetaType::IsGadget, and this function returns its |
| QMetaObject. This can be used to retrieve QMetaMethod and QMetaProperty and use them on a |
| pointer of this type. (given by QVariant::data for example) |
| |
| If the type is an enumeration, flags() contains QMetaType::IsEnumeration, and this function |
| returns the QMetaObject of the enclosing object if the enum was registered as a Q_ENUM or |
| \nullptr otherwise |
| |
| \sa QMetaType::metaObjectForType(), QMetaType::flags() |
| */ |
| |
| /*! |
| \fn void *QMetaType::create(const void *copy = 0) const |
| \since 5.0 |
| |
| Returns a copy of \a copy, assuming it is of the type that this |
| QMetaType instance was created for. If \a copy is \nullptr, creates |
| a default constructed instance. |
| |
| \sa QMetaType::destroy() |
| */ |
| |
| /*! |
| \fn void QMetaType::destroy(void *data) const |
| \since 5.0 |
| |
| Destroys the \a data, assuming it is of the type that this |
| QMetaType instance was created for. |
| |
| \sa QMetaType::create() |
| */ |
| |
| /*! |
| \fn void *QMetaType::construct(int type, const void *copy) |
| \deprecated |
| |
| Constructs a value of the given type which is a copy of \a copy. |
| The default value for \a copy is 0. |
| |
| Deprecated, use the static function QMetaType::create(int type, |
| const void *copy) instead. |
| */ |
| /*! |
| \fn void *QMetaType::construct(void *where, const void *copy = 0) const |
| \since 5.0 |
| |
| Constructs a value of the type that this QMetaType instance |
| was constructed for in the existing memory addressed by \a where, |
| that is a copy of \a copy, and returns \a where. If \a copy is |
| zero, the value is default constructed. |
| |
| This is a low-level function for explicitly managing the memory |
| used to store the type. Consider calling create() if you don't |
| need this level of control (that is, use "new" rather than |
| "placement new"). |
| |
| You must ensure that \a where points to a location where the new |
| value can be stored and that \a where is suitably aligned. |
| The type's size can be queried by calling sizeOf(). |
| |
| The rule of thumb for alignment is that a type is aligned to its |
| natural boundary, which is the smallest power of 2 that is bigger |
| than the type, unless that alignment is larger than the maximum |
| useful alignment for the platform. For practical purposes, |
| alignment larger than 2 * sizeof(void*) is only necessary for |
| special hardware instructions (e.g., aligned SSE loads and stores |
| on x86). |
| */ |
| |
| /*! |
| \fn void QMetaType::destruct(void *data) const |
| \since 5.0 |
| |
| Destructs the value, located at \a data, assuming that it is |
| of the type for which this QMetaType instance was constructed for. |
| |
| Unlike destroy(), this function only invokes the type's |
| destructor, it doesn't invoke the delete operator. |
| \sa QMetaType::construct() |
| */ |
| |
| /*! |
| \fn QMetaType::~QMetaType() |
| |
| Destructs this object. |
| */ |
| |
| #define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \ |
| { #RealName, sizeof(#RealName) - 1, MetaTypeId }, |
| |
| #define QT_ADD_STATIC_METATYPE_ALIASES_ITER(MetaTypeName, MetaTypeId, AliasingName, RealNameStr) \ |
| { RealNameStr, sizeof(RealNameStr) - 1, QMetaType::MetaTypeName }, |
| |
| #define QT_ADD_STATIC_METATYPE_HACKS_ITER(MetaTypeName, TypeId, Name) \ |
| QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeName, Name) |
| |
| static const struct { const char * typeName; int typeNameLength; int type; } types[] = { |
| QT_FOR_EACH_STATIC_TYPE(QT_ADD_STATIC_METATYPE) |
| QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER) |
| QT_FOR_EACH_STATIC_HACKS_TYPE(QT_ADD_STATIC_METATYPE_HACKS_ITER) |
| {nullptr, 0, QMetaType::UnknownType} |
| }; |
| |
| Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeGuiHelper = nullptr; |
| Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeWidgetsHelper = nullptr; |
| Q_CORE_EXPORT const QMetaObject *qMetaObjectWidgetsHelper = nullptr; |
| |
| class QCustomTypeInfo : public QMetaTypeInterface |
| { |
| public: |
| QCustomTypeInfo() |
| : alias(-1) |
| { |
| QMetaTypeInterface empty = QT_METATYPE_INTERFACE_INIT(void); |
| *static_cast<QMetaTypeInterface*>(this) = empty; |
| } |
| QByteArray typeName; |
| int alias; |
| }; |
| |
| template<typename T, typename Key> |
| class QMetaTypeFunctionRegistry |
| { |
| public: |
| ~QMetaTypeFunctionRegistry() |
| { |
| const QWriteLocker locker(&lock); |
| map.clear(); |
| } |
| |
| bool contains(Key k) const |
| { |
| const QReadLocker locker(&lock); |
| return map.contains(k); |
| } |
| |
| bool insertIfNotContains(Key k, const T *f) |
| { |
| const QWriteLocker locker(&lock); |
| const T* &fun = map[k]; |
| if (fun) |
| return false; |
| fun = f; |
| return true; |
| } |
| |
| const T *function(Key k) const |
| { |
| const QReadLocker locker(&lock); |
| return map.value(k, nullptr); |
| } |
| |
| void remove(int from, int to) |
| { |
| const Key k(from, to); |
| const QWriteLocker locker(&lock); |
| map.remove(k); |
| } |
| private: |
| mutable QReadWriteLock lock; |
| QHash<Key, const T *> map; |
| }; |
| |
| typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractConverterFunction,QPair<int,int> > |
| QMetaTypeConverterRegistry; |
| typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractComparatorFunction,int> |
| QMetaTypeComparatorRegistry; |
| typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int> |
| QMetaTypeDebugStreamRegistry; |
| |
| Q_STATIC_ASSERT(std::is_pod<QMetaTypeInterface>::value); |
| |
| Q_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE); |
| Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes) |
| Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock) |
| Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry) |
| Q_GLOBAL_STATIC(QMetaTypeComparatorRegistry, customTypesComparatorRegistry) |
| Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry) |
| |
| /*! |
| \fn bool QMetaType::registerConverter() |
| \since 5.2 |
| Registers the possibility of an implicit conversion from type From to type To in the meta |
| type system. Returns \c true if the registration succeeded, otherwise false. |
| */ |
| |
| /*! |
| \fn template<typename MemberFunction, int> bool QMetaType::registerConverter(MemberFunction function) |
| \since 5.2 |
| \overload |
| Registers a method \a function like To From::function() const as converter from type From |
| to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false. |
| */ |
| |
| /*! |
| \fn template<typename MemberFunctionOk, char> bool QMetaType::registerConverter(MemberFunctionOk function) |
| \since 5.2 |
| \overload |
| Registers a method \a function like To From::function(bool *ok) const as converter from type From |
| to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false. |
| */ |
| |
| /*! |
| \fn template<typename UnaryFunction> bool QMetaType::registerConverter(UnaryFunction function) |
| \since 5.2 |
| \overload |
| Registers a unary function object \a function as converter from type From |
| to type To in the meta type system. Returns \c true if the registration succeeded, otherwise false. |
| */ |
| |
| /*! |
| \fn bool QMetaType::registerComparators() |
| \since 5.2 |
| Registers comparison operators for the user-registered type T. This requires T to have |
| both an operator== and an operator<. |
| Returns \c true if the registration succeeded, otherwise false. |
| */ |
| |
| /*! |
| \fn bool QMetaType::registerEqualsComparator() |
| \since 5.5 |
| Registers equals operator for the user-registered type T. This requires T to have |
| an operator==. |
| 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. |
| Returns \c true if the registration succeeded, otherwise false. |
| \since 5.2 |
| \internal |
| */ |
| bool QMetaType::registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to) |
| { |
| if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from, to), f)) { |
| qWarning("Type conversion already registered from type %s to type %s", |
| QMetaType::typeName(from), QMetaType::typeName(to)); |
| return false; |
| } |
| return true; |
| } |
| |
| /*! |
| \internal |
| |
| Invoked automatically when a converter function object is destroyed. |
| */ |
| void QMetaType::unregisterConverterFunction(int from, int to) |
| { |
| if (customTypesConversionRegistry.isDestroyed()) |
| return; |
| customTypesConversionRegistry()->remove(from, to); |
| } |
| |
| bool QMetaType::registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type) |
| { |
| if (!customTypesComparatorRegistry()->insertIfNotContains(type, f)) { |
| qWarning("Comparators already registered for type %s", QMetaType::typeName(type)); |
| return false; |
| } |
| return true; |
| } |
| |
| /*! |
| \fn bool QMetaType::hasRegisteredComparators() |
| Returns \c true, if the meta type system has registered comparators for type T. |
| \since 5.2 |
| */ |
| |
| /*! |
| Returns \c true, if the meta type system has registered comparators for type id \a typeId. |
| \since 5.2 |
| */ |
| bool QMetaType::hasRegisteredComparators(int typeId) |
| { |
| return customTypesComparatorRegistry()->contains(typeId); |
| } |
| |
| #ifndef QT_NO_DEBUG_STREAM |
| bool QMetaType::registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f, |
| int type) |
| { |
| if (!customTypesDebugStreamRegistry()->insertIfNotContains(type, f)) { |
| qWarning("Debug stream operator already registered for type %s", QMetaType::typeName(type)); |
| return false; |
| } |
| return true; |
| } |
| |
| /*! |
| \fn bool QMetaType::hasRegisteredDebugStreamOperator() |
| Returns \c true, if the meta type system has a registered debug stream operator for type T. |
| \since 5.2 |
| */ |
| |
| /*! |
| 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) |
| { |
| return customTypesDebugStreamRegistry()->contains(typeId); |
| } |
| #endif |
| |
| /*! |
| Converts the object at \a from from \a fromTypeId to the preallocated space at \a to |
| typed \a toTypeId. Returns \c true, if the conversion succeeded, otherwise false. |
| \since 5.2 |
| */ |
| bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId) |
| { |
| const QtPrivate::AbstractConverterFunction * const f = |
| customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId)); |
| return f && f->convert(f, from, to); |
| } |
| |
| /*! |
| Compares the objects at \a lhs and \a rhs. Both objects need to be of type \a typeId. |
| \a result is set to less than, equal to or greater than zero, if \a lhs is less than, equal to |
| or greater than \a rhs. Returns \c true, if the comparison succeeded, otherwise \c false. |
| \since 5.2 |
| */ |
| bool QMetaType::compare(const void *lhs, const void *rhs, int typeId, int* result) |
| { |
| const QtPrivate::AbstractComparatorFunction * const f = |
| customTypesComparatorRegistry()->function(typeId); |
| if (!f) |
| return false; |
| if (f->equals(f, lhs, rhs)) |
| *result = 0; |
| else if (f->lessThan) |
| *result = f->lessThan(f, lhs, rhs) ? -1 : 1; |
| else |
| return false; |
| return true; |
| } |
| |
| /*! |
| Compares the objects at \a lhs and \a rhs. Both objects need to be of type \a typeId. |
| \a result is set to zero, if \a lhs equals to rhs. Returns \c true, if the comparison |
| succeeded, otherwise \c false. |
| \since 5.5 |
| */ |
| bool QMetaType::equals(const void *lhs, const void *rhs, int typeId, int *result) |
| { |
| const QtPrivate::AbstractComparatorFunction * const f |
| = customTypesComparatorRegistry()->function(typeId); |
| if (!f) |
| return false; |
| if (f->equals(f, lhs, rhs)) |
| *result = 0; |
| else |
| *result = -1; |
| return true; |
| } |
| |
| /*! |
| 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 |
| \overload |
| */ |
| |
| /*! |
| Returns \c true, if the meta type system has a registered conversion from meta type id \a fromTypeId |
| to \a toTypeId |
| \since 5.2 |
| */ |
| 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; |
| QVector<QCustomTypeInfo> *ct = customTypes(); |
| if (!ct) |
| return; |
| QWriteLocker locker(customTypesLock()); |
| QCustomTypeInfo &inf = (*ct)[idx - User]; |
| inf.saveOp = saveOp; |
| inf.loadOp = 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. |
| |
| #define STRINGIFY_TYPE_NAME(MetaTypeName, TypeId, RealName) \ |
| #RealName "\0" |
| #define CALCULATE_TYPE_LEN(MetaTypeName, TypeId, RealName) \ |
| short(sizeof(#RealName)), |
| #define MAP_TYPE_ID_TO_IDX(MetaTypeName, TypeId, RealName) \ |
| TypeId, |
| |
| namespace { |
| // All type names in one long string. |
| constexpr char metaTypeStrings[] = QT_FOR_EACH_STATIC_TYPE(STRINGIFY_TYPE_NAME); |
| |
| // The sizes of the strings in the metaTypeStrings string (including terminating null) |
| constexpr short metaTypeNameSizes[] = { |
| QT_FOR_EACH_STATIC_TYPE(CALCULATE_TYPE_LEN) |
| }; |
| |
| // The type IDs, in the order of the metaTypeStrings data |
| constexpr short metaTypeIds[] = { |
| QT_FOR_EACH_STATIC_TYPE(MAP_TYPE_ID_TO_IDX) |
| }; |
| |
| constexpr int MetaTypeNameCount = sizeof(metaTypeNameSizes) / sizeof(metaTypeNameSizes[0]); |
| |
| template <typename IntegerSequence> struct MetaTypeOffsets; |
| template <int... TypeIds> struct MetaTypeOffsets<QtPrivate::IndexesList<TypeIds...>> |
| { |
| // This would have been a lot easier if the meta types that the macro |
| // QT_FOR_EACH_STATIC_TYPE declared were in sorted, ascending order, but |
| // they're not (i.e., the first one declared is QMetaType::Void == 43, |
| // followed by QMetaType::Bool == 1)... As a consequence, we need to use |
| // the C++11 constexpr function calculateOffsetForTypeId below in order to |
| // create the offset array. |
| |
| static constexpr int findTypeId(int typeId, int i = 0) |
| { |
| return i >= MetaTypeNameCount ? -1 : |
| metaTypeIds[i] == typeId ? i : findTypeId(typeId, i + 1); |
| } |
| |
| static constexpr short calculateOffsetForIdx(int i) |
| { |
| return i < 0 ? -1 : |
| i == 0 ? 0 : metaTypeNameSizes[i - 1] + calculateOffsetForIdx(i - 1); |
| } |
| |
| static constexpr short calculateOffsetForTypeId(int typeId) |
| { |
| return calculateOffsetForIdx(findTypeId(typeId)); |
| #if 0 |
| // same as, but this is only valid in C++14: |
| short offset = 0; |
| for (int i = 0; i < MetaTypeNameCount; ++i) { |
| if (metaTypeIds[i] == typeId) |
| return offset; |
| offset += metaTypeNameSizes[i]; |
| } |
| return -1; |
| #endif |
| } |
| |
| short offsets[sizeof...(TypeIds)]; |
| constexpr MetaTypeOffsets() : offsets{calculateOffsetForTypeId(TypeIds)...} {} |
| |
| const char *operator[](int typeId) const noexcept |
| { |
| short o = offsets[typeId]; |
| return o < 0 ? nullptr : metaTypeStrings + o; |
| } |
| }; |
| } // anonymous namespace |
| |
| constexpr MetaTypeOffsets<QtPrivate::Indexes<QMetaType::HighestInternalId + 1>::Value> metaTypeNames {}; |
| #undef STRINGIFY_TYPE_NAME |
| #undef CALCULATE_TYPE_LEN |
| #undef MAP_TYPE_ID_TO_IDX |
| |
| /*! |
| Returns the type name associated with the given \a typeId, or a null |
| pointer if no matching type was found. The returned pointer must not be |
| deleted. |
| |
| \sa type(), isRegistered(), Type |
| */ |
| const char *QMetaType::typeName(int typeId) |
| { |
| const uint type = typeId; |
| if (Q_LIKELY(type <= QMetaType::HighestInternalId)) { |
| return metaTypeNames[typeId]; |
| } else if (Q_UNLIKELY(type < QMetaType::User)) { |
| return nullptr; // It can happen when someone cast int to QVariant::Type, we should not crash... |
| } |
| |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| QReadLocker locker(customTypesLock()); |
| return ct && uint(ct->count()) > type - QMetaType::User && !ct->at(type - QMetaType::User).typeName.isEmpty() |
| ? ct->at(type - QMetaType::User).typeName.constData() |
| : nullptr; |
| |
| #undef QT_METATYPE_TYPEID_TYPENAME_CONVERTER |
| } |
| |
| /* |
| Similar to QMetaType::type(), but only looks in the static set of types. |
| */ |
| static inline int qMetaTypeStaticType(const char *typeName, int length) |
| { |
| int i = 0; |
| while (types[i].typeName && ((length != types[i].typeNameLength) |
| || memcmp(typeName, types[i].typeName, length))) { |
| ++i; |
| } |
| return types[i].type; |
| } |
| |
| /* |
| Similar to QMetaType::type(), but only looks in the custom set of |
| types, and doesn't lock the mutex. |
| The extra \a firstInvalidIndex parameter is an easy way to avoid |
| iterating over customTypes() a second time in registerNormalizedType(). |
| */ |
| static int qMetaTypeCustomType_unlocked(const char *typeName, int length, int *firstInvalidIndex = nullptr) |
| { |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| if (!ct) |
| return QMetaType::UnknownType; |
| |
| if (firstInvalidIndex) |
| *firstInvalidIndex = -1; |
| for (int v = 0; v < ct->count(); ++v) { |
| const QCustomTypeInfo &customInfo = ct->at(v); |
| if ((length == customInfo.typeName.size()) |
| && !memcmp(typeName, customInfo.typeName.constData(), length)) { |
| if (customInfo.alias >= 0) |
| return customInfo.alias; |
| return v + QMetaType::User; |
| } |
| if (firstInvalidIndex && (*firstInvalidIndex < 0) && customInfo.typeName.isEmpty()) |
| *firstInvalidIndex = v; |
| } |
| return QMetaType::UnknownType; |
| } |
| |
| /*! |
| \internal |
| |
| This function is needed until existing code outside of qtbase |
| has been changed to call the new version of registerType(). |
| */ |
| int QMetaType::registerType(const char *typeName, Deleter deleter, |
| Creator creator) |
| { |
| return registerType(typeName, deleter, creator, |
| QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct, |
| QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct, 0, TypeFlags(), nullptr); |
| } |
| |
| /*! |
| \internal |
| \since 5.5 |
| |
| Unregisters the user type with the given \a typeId and all its aliases. |
| Returns \c true if the type was unregistered or \c false otherwise. |
| |
| This function was added for QML to be able to deregister types after |
| they are unloaded to prevent an infinite increase in custom types for |
| applications that are unloading/reloading components often. |
| */ |
| bool QMetaType::unregisterType(int type) |
| { |
| QWriteLocker locker(customTypesLock()); |
| QVector<QCustomTypeInfo> *ct = customTypes(); |
| |
| // check if user type |
| if ((type < User) || ((type - User) >= ct->size())) |
| return false; |
| |
| // only types without Q_DECLARE_METATYPE can be unregistered |
| if (ct->data()[type - User].flags & WasDeclaredAsMetaType) |
| return false; |
| |
| // invalidate type and all its alias entries |
| for (int v = 0; v < ct->count(); ++v) { |
| if (((v + User) == type) || (ct->at(v).alias == type)) |
| ct->data()[v].typeName.clear(); |
| } |
| return true; |
| } |
| |
| |
| /*! |
| \internal |
| \since 5.0 |
| |
| Registers a user type for marshalling, with \a typeName, a \a |
| deleter, a \a creator, a \a destructor, a \a constructor, and |
| a \a size. Returns the type's handle, or -1 if the type could |
| not be registered. |
| */ |
| int QMetaType::registerType(const char *typeName, Deleter deleter, |
| Creator creator, |
| Destructor destructor, |
| Constructor constructor, |
| int size, TypeFlags flags, const QMetaObject *metaObject) |
| { |
| #ifdef QT_NO_QOBJECT |
| NS(QByteArray) normalizedTypeName = typeName; |
| #else |
| NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); |
| #endif |
| |
| return registerNormalizedType(normalizedTypeName, deleter, creator, destructor, constructor, size, flags, metaObject); |
| } |
| |
| /*! |
| \internal |
| \since 5.12 |
| |
| Registers a user type for marshalling, with \a typeName, a |
| \a destructor, a \a constructor, and a \a size. Returns the |
| type's handle, or -1 if the type could not be registered. |
| */ |
| int QMetaType::registerType(const char *typeName, |
| TypedDestructor destructor, |
| TypedConstructor constructor, |
| int size, |
| TypeFlags flags, |
| const QMetaObject *metaObject) |
| { |
| #ifdef QT_NO_QOBJECT |
| NS(QByteArray) normalizedTypeName = typeName; |
| #else |
| NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); |
| #endif |
| |
| return registerNormalizedType(normalizedTypeName, destructor, constructor, size, flags, metaObject); |
| } |
| |
| |
| static int registerNormalizedType(const NS(QByteArray) &normalizedTypeName, |
| QMetaType::Destructor destructor, |
| QMetaType::Constructor constructor, |
| QMetaType::TypedDestructor typedDestructor, |
| QMetaType::TypedConstructor typedConstructor, |
| int size, QMetaType::TypeFlags flags, const QMetaObject *metaObject) |
| { |
| QVector<QCustomTypeInfo> *ct = customTypes(); |
| if (!ct || normalizedTypeName.isEmpty() || (!destructor && !typedDestructor) || (!constructor && !typedConstructor)) |
| return -1; |
| |
| int idx = qMetaTypeStaticType(normalizedTypeName.constData(), |
| normalizedTypeName.size()); |
| |
| int previousSize = 0; |
| QMetaType::TypeFlags::Int previousFlags = 0; |
| if (idx == QMetaType::UnknownType) { |
| QWriteLocker locker(customTypesLock()); |
| int posInVector = -1; |
| idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), |
| normalizedTypeName.size(), |
| &posInVector); |
| if (idx == QMetaType::UnknownType) { |
| QCustomTypeInfo inf; |
| inf.typeName = normalizedTypeName; |
| #ifndef QT_NO_DATASTREAM |
| inf.loadOp = 0; |
| inf.saveOp = 0; |
| #endif |
| inf.alias = -1; |
| inf.typedConstructor = typedConstructor; |
| inf.typedDestructor = typedDestructor; |
| inf.constructor = constructor; |
| inf.destructor = destructor; |
| inf.size = size; |
| inf.flags = flags; |
| inf.metaObject = metaObject; |
| if (posInVector == -1) { |
| idx = ct->size() + QMetaType::User; |
| ct->append(inf); |
| } else { |
| idx = posInVector + QMetaType::User; |
| ct->data()[posInVector] = inf; |
| } |
| return idx; |
| } |
| |
| if (idx >= QMetaType::User) { |
| previousSize = ct->at(idx - QMetaType::User).size; |
| previousFlags = ct->at(idx - QMetaType::User).flags; |
| |
| // Set new/additional flags in case of old library/app. |
| // Ensures that older code works in conjunction with new Qt releases |
| // requiring the new flags. |
| if (flags != previousFlags) { |
| QCustomTypeInfo &inf = ct->data()[idx - QMetaType::User]; |
| inf.flags |= flags; |
| if (metaObject) |
| inf.metaObject = metaObject; |
| } |
| } |
| } |
| |
| if (idx < QMetaType::User) { |
| previousSize = QMetaType::sizeOf(idx); |
| previousFlags = QMetaType::typeFlags(idx); |
| } |
| |
| if (Q_UNLIKELY(previousSize != size)) { |
| qFatal("QMetaType::registerType: Binary compatibility break " |
| "-- Size mismatch for type '%s' [%i]. Previously registered " |
| "size %i, now registering size %i.", |
| normalizedTypeName.constData(), idx, previousSize, size); |
| } |
| |
| // these flags cannot change in a binary compatible way: |
| const int binaryCompatibilityFlag = QMetaType::PointerToQObject | QMetaType::IsEnumeration | QMetaType::SharedPointerToQObject |
| | QMetaType::WeakPointerToQObject | QMetaType::TrackingPointerToQObject; |
| if (Q_UNLIKELY((previousFlags ^ flags) & binaryCompatibilityFlag)) { |
| |
| const char *msg = "QMetaType::registerType: Binary compatibility break. " |
| "\nType flags for type '%s' [%i] don't match. Previously " |
| "registered TypeFlags(0x%x), now registering TypeFlags(0x%x). "; |
| |
| qFatal(msg, normalizedTypeName.constData(), idx, previousFlags, int(flags)); |
| } |
| |
| return idx; |
| } |
| |
| /*! |
| \internal |
| \since 5.0 |
| \overload |
| Don't use, kept for binary compatibility |
| |
| ### TODO Qt6: remove me |
| */ |
| int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, Deleter deleter, |
| Creator creator, |
| Destructor destructor, |
| Constructor constructor, |
| int size, TypeFlags flags, const QMetaObject *metaObject) |
| { |
| Q_UNUSED(deleter); |
| Q_UNUSED(creator); |
| return registerNormalizedType(normalizedTypeName, destructor, constructor, size, flags, metaObject); |
| } |
| |
| |
| /*! |
| \internal |
| \since 5.5 |
| |
| Registers a user type for marshalling, with \a normalizedTypeName, |
| a \a destructor, a \a constructor, and a \a size. Returns the type's |
| handle, or -1 if the type could not be registered. |
| |
| \note normalizedTypeName is not checked for conformance with |
| Qt's normalized format, so it must already conform. |
| |
| ### TODO Qt6: remove me |
| */ |
| int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, |
| Destructor destructor, |
| Constructor constructor, |
| int size, TypeFlags flags, const QMetaObject *metaObject) |
| { |
| return NS(registerNormalizedType)(normalizedTypeName, destructor, constructor, nullptr, nullptr, size, flags, metaObject); |
| } |
| |
| /*! |
| \internal |
| \since 5.12 |
| |
| Registers a user type for marshalling, with \a normalizedTypeName, |
| a \a destructor, a \a constructor, and a \a size. Returns the type's |
| handle, or -1 if the type could not be registered. |
| |
| \note normalizedTypeName is not checked for conformance with |
| Qt's normalized format, so it must already conform. |
| */ |
| int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, |
| TypedDestructor destructor, |
| TypedConstructor constructor, |
| int size, TypeFlags flags, const QMetaObject *metaObject) |
| { |
| return NS(registerNormalizedType)(normalizedTypeName, nullptr, nullptr, destructor, constructor, size, flags, metaObject); |
| } |
| |
| /*! |
| \internal |
| \since 4.7 |
| |
| Registers a user type for marshalling, as an alias of another type (typedef) |
| */ |
| int QMetaType::registerTypedef(const char* typeName, int aliasId) |
| { |
| #ifdef QT_NO_QOBJECT |
| NS(QByteArray) normalizedTypeName = typeName; |
| #else |
| NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); |
| #endif |
| |
| return registerNormalizedTypedef(normalizedTypeName, aliasId); |
| } |
| |
| /*! |
| \internal |
| \since 5.0 |
| |
| Registers a user type for marshalling, as an alias of another type (typedef). |
| Note that normalizedTypeName is not checked for conformance with Qt's normalized format, |
| so it must already conform. |
| */ |
| int QMetaType::registerNormalizedTypedef(const NS(QByteArray) &normalizedTypeName, int aliasId) |
| { |
| QVector<QCustomTypeInfo> *ct = customTypes(); |
| if (!ct || normalizedTypeName.isEmpty()) |
| return -1; |
| |
| int idx = qMetaTypeStaticType(normalizedTypeName.constData(), |
| normalizedTypeName.size()); |
| |
| if (idx == UnknownType) { |
| QWriteLocker locker(customTypesLock()); |
| int posInVector = -1; |
| idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), |
| normalizedTypeName.size(), |
| &posInVector); |
| |
| if (idx == UnknownType) { |
| QCustomTypeInfo inf; |
| inf.typeName = normalizedTypeName; |
| inf.alias = aliasId; |
| if (posInVector == -1) |
| ct->append(inf); |
| else |
| ct->data()[posInVector] = inf; |
| return aliasId; |
| } |
| } |
| |
| if (idx != aliasId) { |
| qWarning("QMetaType::registerTypedef: " |
| "-- Type name '%s' previously registered as typedef of '%s' [%i], " |
| "now registering as typedef of '%s' [%i].", |
| normalizedTypeName.constData(), QMetaType::typeName(idx), idx, |
| QMetaType::typeName(aliasId), aliasId); |
| } |
| return idx; |
| } |
| |
| /*! |
| Returns \c true if the datatype with ID \a type is registered; |
| otherwise returns \c false. |
| |
| \sa type(), typeName(), Type |
| */ |
| bool QMetaType::isRegistered(int type) |
| { |
| // predefined type |
| if ((type >= FirstCoreType && type <= LastCoreType) |
| || (type >= FirstGuiType && type <= LastGuiType) |
| || (type >= FirstWidgetsType && type <= LastWidgetsType)) { |
| return true; |
| } |
| |
| QReadLocker locker(customTypesLock()); |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| return ((type >= User) && (ct && ct->count() > type - User) && !ct->at(type - User).typeName.isEmpty()); |
| } |
| |
| template <bool tryNormalizedType> |
| static inline int qMetaTypeTypeImpl(const char *typeName, int length) |
| { |
| if (!length) |
| return QMetaType::UnknownType; |
| int type = qMetaTypeStaticType(typeName, length); |
| if (type == QMetaType::UnknownType) { |
| QReadLocker locker(customTypesLock()); |
| type = qMetaTypeCustomType_unlocked(typeName, length); |
| #ifndef QT_NO_QOBJECT |
| if ((type == QMetaType::UnknownType) && tryNormalizedType) { |
| const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); |
| type = qMetaTypeStaticType(normalizedTypeName.constData(), |
| normalizedTypeName.size()); |
| if (type == QMetaType::UnknownType) { |
| type = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), |
| normalizedTypeName.size()); |
| } |
| } |
| #endif |
| } |
| return type; |
| } |
| |
| /*! |
| Returns a handle to the type called \a typeName, or QMetaType::UnknownType if there is |
| no such type. |
| |
| \sa isRegistered(), typeName(), Type |
| */ |
| int QMetaType::type(const char *typeName) |
| { |
| return qMetaTypeTypeImpl</*tryNormalizedType=*/true>(typeName, qstrlen(typeName)); |
| } |
| |
| /*! |
| \a internal |
| |
| Similar to QMetaType::type(); the only difference is that this function |
| doesn't attempt to normalize the type name (i.e., the lookup will fail |
| for type names in non-normalized form). |
| */ |
| int qMetaTypeTypeInternal(const char *typeName) |
| { |
| return qMetaTypeTypeImpl</*tryNormalizedType=*/false>(typeName, qstrlen(typeName)); |
| } |
| |
| /*! |
| \since 5.5 |
| \overload |
| |
| Returns a handle to the type called \a typeName, or 0 if there is |
| no such type. |
| |
| \sa isRegistered(), typeName() |
| */ |
| int QMetaType::type(const QT_PREPEND_NAMESPACE(QByteArray) &typeName) |
| { |
| return qMetaTypeTypeImpl</*tryNormalizedType=*/true>(typeName.constData(), typeName.size()); |
| } |
| |
| #ifndef QT_NO_DATASTREAM |
| |
| namespace |
| { |
| |
| template<typename T> |
| class HasStreamOperator |
| { |
| struct Yes { char unused[1]; }; |
| struct No { char unused[2]; }; |
| Q_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 |
| Q_STATIC_ASSERT(HasStreamOperator<NS(QJsonDocument)>::Value); |
| Q_STATIC_ASSERT(!HasStreamOperator<void*>::Value); |
| Q_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 QMetaTypeInterface* getMetaTypeInterface(int type) |
| { |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsGui && qMetaTypeGuiHelper) |
| return &qMetaTypeGuiHelper[type - QMetaType::FirstGuiType]; |
| else if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget && qMetaTypeWidgetsHelper) |
| return &qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType]; |
| return nullptr; |
| } |
| static bool save(QDataStream &stream, const T *data, int type) |
| { |
| if (auto interface = getMetaTypeInterface(type)) { |
| interface->saveOp(stream, data); |
| return true; |
| } |
| return false; |
| } |
| static bool load(QDataStream &stream, T *data, int type) |
| { |
| if (auto interface = getMetaTypeInterface(type)) { |
| interface->loadOp(stream, data); |
| return true; |
| } |
| 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) |
| { |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| if (!ct) |
| return false; |
| QMetaType::SaveOperator saveOp = nullptr; |
| { |
| QReadLocker locker(customTypesLock()); |
| saveOp = ct->at(m_type - QMetaType::User).saveOp; |
| } |
| if (!saveOp) |
| return false; |
| saveOp(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) |
| { |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| if (!ct) |
| return false; |
| QMetaType::LoadOperator loadOp = nullptr; |
| { |
| QReadLocker locker(customTypesLock()); |
| loadOp = ct->at(m_type - QMetaType::User).loadOp; |
| } |
| if (!loadOp) |
| return false; |
| loadOp(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. |
| |
| 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() |
| */ |
| bool QMetaType::save(QDataStream &stream, int type, const void *data) |
| { |
| if (!data) |
| return false; |
| SaveOperatorSwitch saveOp{stream, type}; |
| return QMetaTypeSwitcher::switcher<bool>(saveOp, type, data); |
| } |
| |
| /*! |
| 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. |
| |
| 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() |
| */ |
| bool QMetaType::load(QDataStream &stream, int type, void *data) |
| { |
| if (!data) |
| return false; |
| LoadOperatorSwitch loadOp{stream, type}; |
| return QMetaTypeSwitcher::switcher<bool>(loadOp, type, data); |
| } |
| #endif // QT_NO_DATASTREAM |
| |
| /*! |
| Returns a copy of \a copy, assuming it is of type \a type. If \a |
| copy is zero, creates a default constructed instance. |
| |
| \sa destroy(), isRegistered(), Type |
| */ |
| void *QMetaType::create(int type, const void *copy) |
| { |
| QMetaType info(type); |
| if (int size = info.sizeOf()) |
| return info.construct(operator new(size), copy); |
| return nullptr; |
| } |
| |
| /*! |
| Destroys the \a data, assuming it is of the \a type given. |
| |
| \sa create(), isRegistered(), Type |
| */ |
| void QMetaType::destroy(int type, void *data) |
| { |
| QMetaType info(type); |
| info.destruct(data); |
| operator delete(data); |
| } |
| |
| namespace { |
| class TypeConstructor { |
| template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted> |
| struct ConstructorImpl { |
| static void *Construct(const int /*type*/, void *where, const void *copy) { return QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Construct(where, copy); } |
| }; |
| template<typename T> |
| struct ConstructorImpl<T, /* IsAcceptedType = */ false> { |
| static void *Construct(const int type, void *where, const void *copy) |
| { |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsGui) |
| return Q_LIKELY(qMetaTypeGuiHelper) |
| ? qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].constructor(where, copy) |
| : nullptr; |
| |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget) |
| return Q_LIKELY(qMetaTypeWidgetsHelper) |
| ? qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].constructor(where, copy) |
| : nullptr; |
| |
| // This point can be reached only for known types that definition is not available, for example |
| // in bootstrap mode. We have no other choice then ignore it. |
| return nullptr; |
| } |
| }; |
| public: |
| TypeConstructor(const int type, void *where) |
| : m_type(type) |
| , m_where(where) |
| {} |
| |
| template<typename T> |
| void *delegate(const T *copy) { return ConstructorImpl<T>::Construct(m_type, m_where, copy); } |
| void *delegate(const void *) { return m_where; } |
| void *delegate(const QMetaTypeSwitcher::UnknownType*) { return m_where; } |
| void *delegate(const QMetaTypeSwitcher::NotBuiltinType *copy) { return customTypeConstructor(m_type, m_where, copy); } |
| |
| private: |
| static void *customTypeConstructor(const int type, void *where, const void *copy) |
| { |
| QMetaType::Constructor ctor; |
| QMetaType::TypedConstructor tctor; |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| { |
| QReadLocker locker(customTypesLock()); |
| if (Q_UNLIKELY(type < QMetaType::User || !ct || ct->count() <= type - QMetaType::User)) |
| return nullptr; |
| const auto &typeInfo = ct->at(type - QMetaType::User); |
| ctor = typeInfo.constructor; |
| tctor = typeInfo.typedConstructor; |
| } |
| Q_ASSERT_X((ctor || tctor) , "void *QMetaType::construct(int type, void *where, const void *copy)", "The type was not properly registered"); |
| if (Q_UNLIKELY(tctor)) |
| return tctor(type, where, copy); |
| return ctor(where, copy); |
| } |
| |
| const int m_type; |
| void *m_where; |
| }; |
| } // namespace |
| |
| /*! |
| \since 5.0 |
| |
| Constructs a value of the given \a type in the existing memory |
| addressed by \a where, that is a copy of \a copy, and returns |
| \a where. If \a copy is zero, the value is default constructed. |
| |
| This is a low-level function for explicitly managing the memory |
| used to store the type. Consider calling create() if you don't |
| need this level of control (that is, use "new" rather than |
| "placement new"). |
| |
| You must ensure that \a where points to a location that can store |
| a value of type \a type, and that \a where is suitably aligned. |
| The type's size can be queried by calling sizeOf(). |
| |
| The rule of thumb for alignment is that a type is aligned to its |
| natural boundary, which is the smallest power of 2 that is bigger |
| than the type, unless that alignment is larger than the maximum |
| useful alignment for the platform. For practical purposes, |
| alignment larger than 2 * sizeof(void*) is only necessary for |
| special hardware instructions (e.g., aligned SSE loads and stores |
| on x86). |
| |
| \sa destruct(), sizeOf() |
| */ |
| void *QMetaType::construct(int type, void *where, const void *copy) |
| { |
| if (!where) |
| return nullptr; |
| TypeConstructor constructor(type, where); |
| return QMetaTypeSwitcher::switcher<void*>(constructor, type, copy); |
| } |
| |
| |
| namespace { |
| class TypeDestructor { |
| template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted> |
| struct DestructorImpl { |
| static void Destruct(const int /* type */, void *where) { QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct(where); } |
| }; |
| template<typename T> |
| struct DestructorImpl<T, /* IsAcceptedType = */ false> { |
| static void Destruct(const int type, void *where) |
| { |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsGui) { |
| if (Q_LIKELY(qMetaTypeGuiHelper)) |
| qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].destructor(where); |
| return; |
| } |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget) { |
| if (Q_LIKELY(qMetaTypeWidgetsHelper)) |
| qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].destructor(where); |
| return; |
| } |
| // This point can be reached only for known types that definition is not available, for example |
| // in bootstrap mode. We have no other choice then ignore it. |
| } |
| }; |
| public: |
| TypeDestructor(const int type) |
| : m_type(type) |
| {} |
| |
| template<typename T> |
| void delegate(const T *where) { DestructorImpl<T>::Destruct(m_type, const_cast<T*>(where)); } |
| // MSVC2013 and earlier can not const_cast a std::nullptr_t pointer. |
| void delegate(const std::nullptr_t *) {} |
| void delegate(const void *) {} |
| void delegate(const QMetaTypeSwitcher::UnknownType*) {} |
| void delegate(const QMetaTypeSwitcher::NotBuiltinType *where) |
| { customTypeDestructor(m_type, const_cast<void *>(static_cast<const void *>(where))); } |
| |
| private: |
| static void customTypeDestructor(const int type, void *where) |
| { |
| QMetaType::Destructor dtor; |
| QMetaType::TypedDestructor tdtor; |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| { |
| QReadLocker locker(customTypesLock()); |
| if (Q_UNLIKELY(type < QMetaType::User || !ct || ct->count() <= type - QMetaType::User)) |
| return; |
| const auto &typeInfo = ct->at(type - QMetaType::User); |
| dtor = typeInfo.destructor; |
| tdtor = typeInfo.typedDestructor; |
| } |
| Q_ASSERT_X((dtor || tdtor), "void QMetaType::destruct(int type, void *where)", "The type was not properly registered"); |
| if (Q_UNLIKELY(tdtor)) |
| return tdtor(type, where); |
| dtor(where); |
| } |
| |
| const int m_type; |
| }; |
| } // namespace |
| |
| /*! |
| \since 5.0 |
| |
| Destructs the value of the given \a type, located at \a where. |
| |
| Unlike destroy(), this function only invokes the type's |
| destructor, it doesn't invoke the delete operator. |
| |
| \sa construct() |
| */ |
| void QMetaType::destruct(int type, void *where) |
| { |
| if (!where) |
| return; |
| TypeDestructor destructor(type); |
| QMetaTypeSwitcher::switcher<void>(destructor, type, where); |
| } |
| |
| |
| namespace { |
| class SizeOf { |
| template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted> |
| struct SizeOfImpl { |
| static int Size(const int) { return QTypeInfo<T>::sizeOf; } |
| }; |
| template<typename T> |
| struct SizeOfImpl<T, /* IsAcceptedType = */ false> { |
| static int Size(const int type) |
| { |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsGui) |
| return Q_LIKELY(qMetaTypeGuiHelper) ? qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].size : 0; |
| |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget) |
| return Q_LIKELY(qMetaTypeWidgetsHelper) ? qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].size : 0; |
| |
| // This point can be reached only for known types that definition is not available, for example |
| // in bootstrap mode. We have no other choice then ignore it. |
| return 0; |
| } |
| }; |
| |
| public: |
| SizeOf(int type) |
| : m_type(type) |
| {} |
| |
| template<typename T> |
| int delegate(const T*) { return SizeOfImpl<T>::Size(m_type); } |
| int delegate(const QMetaTypeSwitcher::UnknownType*) { return 0; } |
| int delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customTypeSizeOf(m_type); } |
| private: |
| static int customTypeSizeOf(const int type) |
| { |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| QReadLocker locker(customTypesLock()); |
| if (Q_UNLIKELY(type < QMetaType::User || !ct || ct->count() <= type - QMetaType::User)) |
| return 0; |
| return ct->at(type - QMetaType::User).size; |
| } |
| |
| const int m_type; |
| }; |
| } // namespace |
| |
| /*! |
| \since 5.0 |
| |
| Returns the size of the given \a type in bytes (i.e. sizeof(T), |
| where T is the actual type identified by the \a type argument). |
| |
| This function is typically used together with construct() |
| to perform low-level management of the memory used by a type. |
| |
| \sa construct() |
| */ |
| int QMetaType::sizeOf(int type) |
| { |
| SizeOf sizeOf(type); |
| return QMetaTypeSwitcher::switcher<int>(sizeOf, type); |
| } |
| |
| namespace { |
| class Flags |
| { |
| template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted> |
| struct FlagsImpl |
| { |
| static quint32 Flags(const int /* type */) |
| { |
| return QtPrivate::QMetaTypeTypeFlags<T>::Flags; |
| } |
| }; |
| template<typename T> |
| struct FlagsImpl<T, /* IsAcceptedType = */ false> |
| { |
| static quint32 Flags(const int type) |
| { |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsGui) |
| return Q_LIKELY(qMetaTypeGuiHelper) ? qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].flags : 0; |
| |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget) |
| return Q_LIKELY(qMetaTypeWidgetsHelper) ? qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].flags : 0; |
| |
| // This point can be reached only for known types that definition is not available, for example |
| // in bootstrap mode. We have no other choice then ignore it. |
| return 0; |
| } |
| }; |
| public: |
| Flags(const int type) |
| : m_type(type) |
| {} |
| template<typename T> |
| quint32 delegate(const T*) { return FlagsImpl<T>::Flags(m_type); } |
| quint32 delegate(const void*) { return 0; } |
| quint32 delegate(const QMetaTypeSwitcher::UnknownType*) { return 0; } |
| quint32 delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customTypeFlags(m_type); } |
| private: |
| const int m_type; |
| static quint32 customTypeFlags(const int type) |
| { |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| if (Q_UNLIKELY(!ct || type < QMetaType::User)) |
| return 0; |
| QReadLocker locker(customTypesLock()); |
| if (Q_UNLIKELY(ct->count() <= type - QMetaType::User)) |
| return 0; |
| return ct->at(type - QMetaType::User).flags; |
| } |
| }; |
| } // namespace |
| |
| /*! |
| \since 5.0 |
| |
| Returns flags of the given \a type. |
| |
| \sa QMetaType::TypeFlags |
| */ |
| QMetaType::TypeFlags QMetaType::typeFlags(int type) |
| { |
| Flags flags(type); |
| return static_cast<QMetaType::TypeFlags>(QMetaTypeSwitcher::switcher<quint32>(flags, type)); |
| } |
| |
| #ifndef QT_BOOTSTRAPPED |
| namespace { |
| class MetaObject |
| { |
| public: |
| MetaObject(const int type) |
| : m_type(type) |
| {} |
| |
| template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted> |
| struct MetaObjectImpl |
| { |
| static const QMetaObject *MetaObject(int /*type*/) |
| { return QtPrivate::MetaObjectForType<T>::value(); } |
| }; |
| template<typename T> |
| struct MetaObjectImpl<T, /* IsAcceptedType = */ false> |
| { |
| static const QMetaObject *MetaObject(int type) { |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsGui) |
| return Q_LIKELY(qMetaTypeGuiHelper) |
| ? qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].metaObject |
| : nullptr; |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget) |
| return Q_LIKELY(qMetaTypeWidgetsHelper) |
| ? qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].metaObject |
| : nullptr; |
| return 0; |
| } |
| }; |
| |
| template <typename T> |
| const QMetaObject *delegate(const T *) { return MetaObjectImpl<T>::MetaObject(m_type); } |
| const QMetaObject *delegate(const void*) { return nullptr; } |
| const QMetaObject *delegate(const QMetaTypeSwitcher::UnknownType*) { return nullptr; } |
| const QMetaObject *delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customMetaObject(m_type); } |
| private: |
| const int m_type; |
| static const QMetaObject *customMetaObject(const int type) |
| { |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| if (Q_UNLIKELY(!ct || type < QMetaType::User)) |
| return nullptr; |
| QReadLocker locker(customTypesLock()); |
| if (Q_UNLIKELY(ct->count() <= type - QMetaType::User)) |
| return nullptr; |
| return ct->at(type - QMetaType::User).metaObject; |
| } |
| }; |
| } // namespace |
| #endif |
| |
| /*! |
| \since 5.0 |
| |
| returns QMetaType::metaObject for \a type |
| |
| \sa metaObject() |
| */ |
| const QMetaObject *QMetaType::metaObjectForType(int type) |
| { |
| #ifndef QT_BOOTSTRAPPED |
| MetaObject mo(type); |
| return QMetaTypeSwitcher::switcher<const QMetaObject*>(mo, type); |
| #else |
| Q_UNUSED(type); |
| return nullptr; |
| #endif |
| } |
| |
| /*! |
| \fn int qRegisterMetaType(const char *typeName) |
| \relates QMetaType |
| \threadsafe |
| |
| Registers the type name \a typeName for the type \c{T}. Returns |
| the internal ID used by QMetaType. Any class or struct that has a |
| public default constructor, a public copy constructor and a public |
| destructor can be registered. |
| |
| This function requires that \c{T} is a fully defined type at the point |
| where the function is called. For pointer types, it also requires that the |
| pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able |
| to register pointers to forward declared types. |
| |
| After a type has been registered, you can create and destroy |
| objects of that type dynamically at run-time. |
| |
| This example registers the class \c{MyClass}: |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 4 |
| |
| This function is useful to register typedefs so they can be used |
| by QMetaProperty, or in QueuedConnections |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 9 |
| |
| \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() |
| */ |
| |
| /*! \typedef QMetaType::Deleter |
| \internal |
| */ |
| /*! \typedef QMetaType::Creator |
| \internal |
| */ |
| /*! \typedef QMetaType::SaveOperator |
| \internal |
| */ |
| /*! \typedef QMetaType::LoadOperator |
| \internal |
| */ |
| /*! \typedef QMetaType::Destructor |
| \internal |
| */ |
| /*! \typedef QMetaType::Constructor |
| \internal |
| */ |
| |
| /*! |
| \fn int qRegisterMetaType() |
| \relates QMetaType |
| \threadsafe |
| \since 4.2 |
| |
| Call this function to register the type \c T. \c T must be declared with |
| Q_DECLARE_METATYPE(). Returns the meta type Id. |
| |
| Example: |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 7 |
| |
| This function requires that \c{T} is a fully defined type at the point |
| where the function is called. For pointer types, it also requires that the |
| pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able |
| to register pointers to forward declared types. |
| |
| After a type has been registered, you can create and destroy |
| objects of that type dynamically at run-time. |
| |
| To use the type \c T in QVariant, using Q_DECLARE_METATYPE() is |
| sufficient. To use the type \c T in queued signal and slot connections, |
| \c{qRegisterMetaType<T>()} must be called before the first connection |
| is established. |
| |
| Also, to use type \c T with the QObject::property() API, |
| \c{qRegisterMetaType<T>()} must be called before it is used, typically |
| in the constructor of the class that uses \c T, or in the \c{main()} |
| function. |
| |
| \sa Q_DECLARE_METATYPE() |
| */ |
| |
| /*! |
| \fn int qMetaTypeId() |
| \relates QMetaType |
| \threadsafe |
| \since 4.1 |
| |
| Returns the meta type id of type \c T at compile time. If the |
| type was not declared with Q_DECLARE_METATYPE(), compilation will |
| fail. |
| |
| Typical usage: |
| |
| \snippet code/src_corelib_kernel_qmetatype.cpp 8 |
| |
| QMetaType::type() returns the same ID as qMetaTypeId(), but does |
| a lookup at runtime based on the name of the type. |
| QMetaType::type() is a bit slower, but compilation succeeds if a |
| type is not registered. |
| |
| \sa Q_DECLARE_METATYPE(), QMetaType::type() |
| */ |
| |
| namespace { |
| class TypeInfo { |
| template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted> |
| struct TypeInfoImpl |
| { |
| TypeInfoImpl(const uint /* type */, QMetaTypeInterface &info) |
| { |
| QMetaTypeInterface tmp = QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(T); |
| info = tmp; |
| } |
| }; |
| |
| template<typename T> |
| struct TypeInfoImpl<T, /* IsAcceptedType = */ false> |
| { |
| TypeInfoImpl(const uint type, QMetaTypeInterface &info) |
| { |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsGui) { |
| if (Q_LIKELY(qMetaTypeGuiHelper)) |
| info = qMetaTypeGuiHelper[type - QMetaType::FirstGuiType]; |
| return; |
| } |
| if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget) { |
| if (Q_LIKELY(qMetaTypeWidgetsHelper)) |
| info = qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType]; |
| return; |
| } |
| } |
| }; |
| public: |
| QMetaTypeInterface info; |
| TypeInfo(const uint type) |
| : m_type(type) |
| { |
| QMetaTypeInterface tmp = QT_METATYPE_INTERFACE_INIT_EMPTY(); |
| info = tmp; |
| } |
| template<typename T> |
| void delegate(const T*) { TypeInfoImpl<T>(m_type, info); } |
| void delegate(const QMetaTypeSwitcher::UnknownType*) {} |
| void delegate(const QMetaTypeSwitcher::NotBuiltinType*) { customTypeInfo(m_type); } |
| private: |
| void customTypeInfo(const uint type) |
| { |
| const QVector<QCustomTypeInfo> * const ct = customTypes(); |
| if (Q_UNLIKELY(!ct)) |
| return; |
| QReadLocker locker(customTypesLock()); |
| if (Q_LIKELY(uint(ct->count()) > type - QMetaType::User)) |
| info = ct->at(type - QMetaType::User); |
| } |
| |
| const uint m_type; |
| }; |
| } // namespace |
| |
| /*! |
| \fn QMetaType QMetaType::typeInfo(const int type) |
| \internal |
| */ |
| QMetaType QMetaType::typeInfo(const int type) |
| { |
| TypeInfo typeInfo(type); |
| QMetaTypeSwitcher::switcher<void>(typeInfo, type); |
| return (typeInfo.info.constructor || typeInfo.info.typedConstructor) |
| ? QMetaType(static_cast<ExtensionFlag>(QMetaType::CreateEx | QMetaType::DestroyEx | |
| (typeInfo.info.typedConstructor ? QMetaType::ConstructEx | QMetaType::DestructEx : 0)) |
| , static_cast<const QMetaTypeInterface *>(nullptr) // typeInfo::info is a temporary variable, we can't return address of it. |
| , typeInfo.info.typedConstructor |
| , typeInfo.info.typedDestructor |
| , typeInfo.info.saveOp |
| , typeInfo.info.loadOp |
| , typeInfo.info.constructor |
| , typeInfo.info.destructor |
| , typeInfo.info.size |
| , typeInfo.info.flags |
| , type |
| , typeInfo.info.metaObject) |
| : QMetaType(UnknownType); |
| } |
| |
| /*! |
| \fn QMetaType::QMetaType(const int typeId) |
| \since 5.0 |
| |
| Constructs a QMetaType object that contains all information about type \a typeId. |
| */ |
| QMetaType::QMetaType(const int typeId) |
| : m_typeId(typeId) |
| { |
| if (Q_UNLIKELY(typeId == UnknownType)) { |
| // Constructs invalid QMetaType instance. |
| m_extensionFlags = 0xffffffff; |
| Q_ASSERT(!isValid()); |
| } else { |
| // TODO it can be better. |
| *this = QMetaType::typeInfo(typeId); |
| if (m_typeId == UnknownType) |
| m_extensionFlags = 0xffffffff; |
| else if (m_typeId == QMetaType::Void) |
| m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx; |
| } |
| } |
| |
| /*! |
| \fn QMetaType::QMetaType(const QMetaType &other) |
| \since 5.0 |
| |
| Copy constructs a QMetaType object. |
| */ |
| QMetaType::QMetaType(const QMetaType &other) |
| : m_typedConstructor(other.m_typedConstructor) |
| , m_typedDestructor(other.m_typedDestructor) |
| , m_saveOp(other.m_saveOp) |
| , m_loadOp(other.m_loadOp) |
| , m_constructor(other.m_constructor) |
| , m_destructor(other.m_destructor) |
| , m_extension(other.m_extension) // space reserved for future use |
| , m_size(other.m_size) |
| , m_typeFlags(other.m_typeFlags) |
| , m_extensionFlags(other.m_extensionFlags) |
| , m_typeId(other.m_typeId) |
| , m_metaObject(other.m_metaObject) |
| {} |
| |
| QMetaType &QMetaType::operator =(const QMetaType &other) |
| { |
| m_typedConstructor = other.m_typedConstructor; |
| m_typedDestructor = other.m_typedDestructor; |
| m_saveOp = other.m_saveOp; |
| m_loadOp = other.m_loadOp; |
| m_constructor = other.m_constructor; |
| m_destructor = other.m_destructor; |
| m_size = other.m_size; |
| m_typeFlags = other.m_typeFlags; |
| m_extensionFlags = other.m_extensionFlags; |
| m_extension = other.m_extension; // space reserved for future use |
| m_typeId = other.m_typeId; |
| m_metaObject = other.m_metaObject; |
| return *this; |
| } |
| |
| /*! |
| \fn void QMetaType::ctor(const QMetaTypeInterface *info) |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be |
| called from within QMetaType's constructor to force a library call from |
| inlined code. |
| */ |
| void QMetaType::ctor(const QMetaTypeInterface *info) |
| { |
| // Special case for Void type, the type is valid but not constructible. |
| // In future we may consider to remove this assert and extend this function to initialize |
| // differently m_extensionFlags for different types. Currently it is not needed. |
| Q_ASSERT(m_typeId == QMetaType::Void); |
| Q_UNUSED(info); |
| m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx; |
| } |
| |
| /*! |
| \fn void QMetaType::dtor() |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be |
| called from within QMetaType's destructor to force a library call from |
| inlined code. |
| */ |
| void QMetaType::dtor() |
| {} |
| |
| /*! |
| \fn void *QMetaType::createExtended(const void *copy) const |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be called |
| during QMetaType::create to force library call from inlined code. |
| |
| ### TODO Qt6 remove the extension |
| */ |
| void *QMetaType::createExtended(const void *copy) const |
| { |
| if (m_typeId == QMetaType::UnknownType) |
| return nullptr; |
| if (Q_UNLIKELY(m_typedConstructor && !m_constructor)) |
| return m_typedConstructor(m_typeId, operator new(m_size), copy); |
| return m_constructor(operator new(m_size), copy); |
| } |
| |
| /*! |
| \fn void QMetaType::destroyExtended(void *data) const |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be called |
| during QMetaType::destroy to force library call from inlined code. |
| |
| ### TODO Qt6 remove the extension |
| */ |
| void QMetaType::destroyExtended(void *data) const |
| { |
| if (m_typeId == QMetaType::UnknownType) |
| return; |
| if (Q_UNLIKELY(m_typedDestructor && !m_destructor)) |
| m_typedDestructor(m_typeId, data); |
| else |
| m_destructor(data); |
| operator delete(data); |
| } |
| |
| /*! |
| \fn void *QMetaType::constructExtended(void *where, const void *copy) const |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be called |
| during QMetaType::construct to force library call from inlined code. |
| */ |
| void *QMetaType::constructExtended(void *where, const void *copy) const |
| { |
| if (m_typeId == QMetaType::UnknownType) |
| return nullptr; |
| if (m_typedConstructor && !m_constructor) |
| return m_typedConstructor(m_typeId, where, copy); |
| return nullptr; |
| } |
| |
| /*! |
| \fn void QMetaType::destructExtended(void *data) const |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be called |
| during QMetaType::destruct to force library call from inlined code. |
| */ |
| void QMetaType::destructExtended(void *data) const |
| { |
| if (m_typeId == QMetaType::UnknownType) |
| return; |
| if (m_typedDestructor && !m_destructor) |
| m_typedDestructor(m_typeId, data); |
| } |
| |
| /*! |
| \fn uint QMetaType::sizeExtended() const |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be |
| called from within QMetaType::size to force a library call from |
| inlined code. |
| */ |
| uint QMetaType::sizeExtended() const |
| { |
| return 0; |
| } |
| |
| /*! |
| \fn QMetaType::TypeFlags QMetaType::flagsExtended() const |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be |
| called from within QMetaType::flags to force a library call from |
| inlined code. |
| */ |
| QMetaType::TypeFlags QMetaType::flagsExtended() const |
| { |
| return { }; |
| } |
| |
| /*! |
| \brief QMetaType::metaObjectExtended |
| \internal |
| |
| Method used for future binary compatible extensions. The function may be |
| called from within QMetaType::metaObject to force a library call from |
| inlined code. |
| */ |
| const QMetaObject *QMetaType::metaObjectExtended() const |
| { |
| return nullptr; |
| } |
| |
| |
| namespace QtPrivate |
| { |
| const QMetaObject *metaObjectForQWidget() |
| { |
| if (!qMetaTypeWidgetsHelper) |
| return nullptr; |
| return qMetaObjectWidgetsHelper; |
| } |
| } |
| |
| namespace QtMetaTypePrivate { |
| const bool VectorBoolElements::true_element = true; |
| const bool VectorBoolElements::false_element = false; |
| } |
| |
| QT_END_NAMESPACE |