diff options
author | Jędrzej Nowacki <jedrzej.nowacki@nokia.com> | 2011-12-20 17:11:46 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-02-16 02:00:15 +0100 |
commit | 214e031d56714ba69ef929f1e763e243b393e460 (patch) | |
tree | 4732bd79e015eecb85e66ba3a3facc58d5fba9ae /src | |
parent | b9eb3715f55378802a1a0ae2f61d799ab84ee49a (diff) |
Implement new static less API for QMetaType.
Currently QMetaType API contains almost only static methods. This works
nice until someone needs more information or needs to do more operations
on a type. In this case every function call has to do type dispatch.
This API allows to avoid redundant type dispatching, by caching a
type information in a QMetaType instance. It gives significant
performance boost especially for custom types (up to 9x).
Change-Id: I223d066268402e072e41ca1d0a3e7bc160655d7f
Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 170 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 145 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype_p.h | 43 |
3 files changed, 348 insertions, 10 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index d965c48255..a1baf28f10 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1753,4 +1753,174 @@ QMetaType::TypeFlags QMetaType::typeFlags(int type) \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 (QTypeModuleInfo<T>::IsGui) { + if (Q_LIKELY(qMetaTypeGuiHelper)) + info = qMetaTypeGuiHelper[type - QMetaType::FirstGuiType]; + return; + } + if (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 void*) {} + void delegate(const QMetaTypeSwitcher::UnknownType*) { 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 + +QMetaType QMetaType::typeInfo(const int type) +{ + TypeInfo typeInfo(type); + QMetaTypeSwitcher::switcher<void>(typeInfo, type, 0); + return typeInfo.info.creator || !type ? QMetaType(QMetaType::NoExtensionFlags + , static_cast<const QMetaTypeInterface *>(0) // typeInfo::info is a temporary variable, we can't return address of it. + , typeInfo.info.creator + , typeInfo.info.deleter + , typeInfo.info.saveOp + , typeInfo.info.loadOp + , typeInfo.info.constructor + , typeInfo.info.destructor + , typeInfo.info.size + , typeInfo.info.flags + , type) + : QMetaType(-1); +} + +QMetaType::QMetaType(const int typeId) + : m_typeId(typeId) +{ + if (Q_UNLIKELY(typeId == -1)) { + // Constructs invalid QMetaType instance. + m_extensionFlags = 0xffffffff; + Q_ASSERT(!isValid()); + } else { + // TODO it can be better. + *this = QMetaType::typeInfo(typeId); + if (m_typeId > 0 && !m_creator) { + m_extensionFlags = 0xffffffff; + m_typeId = -1; + } + if (m_typeId == QMetaType::Void) { + m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx; + } + } +} + +QMetaType::QMetaType(const QMetaType &other) + : m_creator(other.m_creator) + , m_deleter(other.m_deleter) + , 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) +{} + +QMetaType &QMetaType::operator =(const QMetaType &other) +{ + m_creator = other.m_creator; + m_deleter = other.m_deleter; + 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; + return *this; +} + +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; +} + +void QMetaType::dtor() +{} + +void *QMetaType::createExtended(const void *copy) const +{ + Q_UNUSED(copy); + return 0; +} + +void QMetaType::destroyExtended(void *data) const +{ + Q_UNUSED(data); +} + +void *QMetaType::constructExtended(void *where, const void *copy) const +{ + Q_UNUSED(where); + Q_UNUSED(copy); + return 0; +} + +void QMetaType::destructExtended(void *data) const +{ + Q_UNUSED(data); +} + +uint QMetaType::sizeExtended() const +{ + return 0; +} + +QMetaType::TypeFlags QMetaType::flagsExtended() const +{ + return 0; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index ff3f9341e4..0b6a62e5c8 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -177,8 +177,16 @@ QT_BEGIN_NAMESPACE TypeName = Id, class QDataStream; +class QMetaTypeInterface; class Q_CORE_EXPORT QMetaType { + enum ExtensionFlag { NoExtensionFlags, + CreateEx = 0x1, DestroyEx = 0x2, + ConstructEx = 0x4, DestructEx = 0x8, + NameEx = 0x10, SizeEx = 0x20, + CtorEx = 0x40, DtorEx = 0x80, + FlagsEx = 0x100 + }; public: enum Type { // these are merged with QVariant @@ -218,9 +226,9 @@ public: typedef void (*Destructor)(void *); typedef void *(*Constructor)(void *, const void *); -#ifndef QT_NO_DATASTREAM 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, @@ -253,6 +261,56 @@ public: static bool save(QDataStream &stream, int type, const void *data); static bool load(QDataStream &stream, int type, void *data); #endif + + QMetaType(const int type); + inline ~QMetaType(); + + inline bool isValid() const; + inline bool isRegistered() const; + inline int sizeOf() const; + inline TypeFlags flags() const; + + inline void *create(const void *copy = 0) const; + inline void destroy(void *data) const; + inline void *construct(void *where, const void *copy = 0) const; + inline void destruct(void *data) const; +private: + static QMetaType typeInfo(const int type); + inline QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info, + Creator creator, + Deleter deleter, + SaveOperator saveOp, + LoadOperator loadOp, + Constructor constructor, + Destructor destructor, + uint sizeOf, + uint typeFlags, + int typeId); + QMetaType(const QMetaType &other); + QMetaType &operator =(const QMetaType &); + inline bool isExtended(const ExtensionFlag flag) const { return m_extensionFlags & flag; } + + // Methods used for future binary compatibile extensions + void ctor(const QMetaTypeInterface *info); + void dtor(); + uint sizeExtended() const; + QMetaType::TypeFlags flagsExtended() const; + void *createExtended(const void *copy = 0) const; + void destroyExtended(void *data) const; + void *constructExtended(void *where, const void *copy = 0) const; + void destructExtended(void *data) const; + + Creator m_creator; + Deleter m_deleter; + SaveOperator m_saveOp; + LoadOperator m_loadOp; + Constructor m_constructor; + Destructor m_destructor; + void *m_extension; // space reserved for future use + uint m_size; + uint m_typeFlags; + uint m_extensionFlags; + int m_typeId; }; #undef QT_DEFINE_METATYPE_ID @@ -555,6 +613,91 @@ Q_DECLARE_METATYPE_TEMPLATE_1ARG(QSet) Q_DECLARE_METATYPE_TEMPLATE_1ARG(QSharedPointer) Q_DECLARE_METATYPE_TEMPLATE_1ARG(QLinkedList) +inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info, + Creator creator, + Deleter deleter, + SaveOperator saveOp, + LoadOperator loadOp, + Constructor constructor, + Destructor destructor, + uint size, + uint typeFlags, + int typeId) + : m_creator(creator) + , m_deleter(deleter) + , m_saveOp(saveOp) + , m_loadOp(loadOp) + , m_constructor(constructor) + , m_destructor(destructor) + , m_size(size) + , m_typeFlags(typeFlags) + , m_extensionFlags(extensionFlags) + , m_typeId(typeId) +{ + if (Q_UNLIKELY(isExtended(CtorEx) || typeId == QMetaType::Void)) + ctor(info); +} + +inline QMetaType::~QMetaType() +{ + if (Q_UNLIKELY(isExtended(DtorEx))) + dtor(); +} + +inline bool QMetaType::isValid() const +{ + return m_typeId >= 0; +} + +inline bool QMetaType::isRegistered() const +{ + return isValid(); +} + +inline void *QMetaType::create(const void *copy) const +{ + if (Q_UNLIKELY(isExtended(CreateEx))) + return createExtended(copy); + return m_creator(copy); +} + +inline void QMetaType::destroy(void *data) const +{ + if (Q_UNLIKELY(isExtended(DestroyEx))) + return destroyExtended(data); + m_deleter(data); +} + +inline void *QMetaType::construct(void *where, const void *copy) const +{ + if (Q_UNLIKELY(isExtended(ConstructEx))) + return constructExtended(where, copy); + return m_constructor(where, copy); +} + +inline void QMetaType::destruct(void *data) const +{ + if (Q_UNLIKELY(isExtended(DestructEx))) + return destructExtended(data); + if (Q_UNLIKELY(!data)) + return; + m_destructor(data); +} + +inline int QMetaType::sizeOf() const +{ + if (Q_UNLIKELY(isExtended(SizeEx))) + return sizeExtended(); + return m_size; +} + +inline QMetaType::TypeFlags QMetaType::flags() const +{ + if (Q_UNLIKELY(isExtended(FlagsEx))) + return flagsExtended(); + return QMetaType::TypeFlags(m_typeFlags); +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h index b1edc350a1..e48c5d3033 100644 --- a/src/corelib/kernel/qmetatype_p.h +++ b/src/corelib/kernel/qmetatype_p.h @@ -132,10 +132,8 @@ public: } static void deleter(T *t) { delete t; } - #ifndef QT_NO_DATASTREAM static void saver(QDataStream &stream, const T *t) { stream << *t; } static void loader(QDataStream &stream, T *t) { stream >> *t; } - #endif // QT_NO_DATASTREAM static void destructor(T *t) { Q_UNUSED(t) // Silence MSVC that warns for POD types. @@ -151,10 +149,8 @@ public: QMetaType::Creator creator; QMetaType::Deleter deleter; -#ifndef QT_NO_DATASTREAM QMetaType::SaveOperator saveOp; QMetaType::LoadOperator loadOp; -#endif QMetaType::Constructor constructor; QMetaType::Destructor destructor; int size; @@ -165,10 +161,8 @@ template<> struct QMetaTypeInterface::Impl<void> { static void *creator(const void *) { return 0; } static void deleter(void *) {} -#ifndef QT_NO_DATASTREAM static void saver(QDataStream &, const void *) {} static void loader(QDataStream &, void *) {} -#endif // QT_NO_DATASTREAM static void destructor(void *){} static void *constructor(void *, const void *) { return 0; } }; @@ -177,15 +171,22 @@ struct QMetaTypeInterface::Impl<void> { # define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \ /*saveOp*/(reinterpret_cast<QMetaType::SaveOperator>(QMetaTypeInterface::Impl<Type>::saver)), \ /*loadOp*/(reinterpret_cast<QMetaType::LoadOperator>(QMetaTypeInterface::Impl<Type>::loader)), +# define QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) \ + /*saveOp*/ 0, \ + /*loadOp*/ 0, #else -# define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) +# define QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) \ + /*saveOp*/ 0, \ + /*loadOp*/ 0, +# define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \ + QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) #endif -#define QT_METATYPE_INTERFACE_INIT(Type) \ +#define QT_METATYPE_INTERFACE_INIT_IMPL(Type, DATASTREAM_DELEGATE) \ { \ /*creator*/(reinterpret_cast<QMetaType::Creator>(QMetaTypeInterface::Impl<Type>::creator)), \ /*deleter*/(reinterpret_cast<QMetaType::Deleter>(QMetaTypeInterface::Impl<Type>::deleter)), \ - QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \ + DATASTREAM_DELEGATE(Type) \ /*constructor*/(reinterpret_cast<QMetaType::Constructor>(QMetaTypeInterface::Impl<Type>::constructor)), \ /*destructor*/(reinterpret_cast<QMetaType::Destructor>(QMetaTypeInterface::Impl<Type>::destructor)), \ /*size*/(QTypeInfo<Type>::sizeOf), \ @@ -194,6 +195,30 @@ struct QMetaTypeInterface::Impl<void> { | (QTypeInfo<Type>::isComplex * QMetaType::NeedsDestruction) \ } + +/* These QT_METATYPE_INTERFACE_INIT* macros are used to initialize QMetaTypeInterface instance. + + - QT_METATYPE_INTERFACE_INIT(Type) -> It takes Type argument and creates all necessary wrapper functions for the Type, + it detects if QT_NO_DATASTREAM was defined. Probably it is the macro that you want to use. + + - QT_METATYPE_INTERFACE_INIT_EMPTY() -> It initializes an empty QMetaTypeInterface instance. + + - QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(Type) -> Temporary workaround for missing auto-detection of data stream + operators. It creates same instance as QT_METATYPE_INTERFACE_INIT(Type) but with null stream operators callbacks. + */ +#define QT_METATYPE_INTERFACE_INIT(Type) QT_METATYPE_INTERFACE_INIT_IMPL(Type, QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL) +#define QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(Type) QT_METATYPE_INTERFACE_INIT_IMPL(Type, QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL) +#define QT_METATYPE_INTERFACE_INIT_EMPTY() \ +{ \ + /*creator*/ 0, \ + /*deleter*/ 0, \ + QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL() \ + /*constructor*/ 0, \ + /*destructor*/ 0, \ + /*size*/ 0, \ + /*flags*/ 0 \ +} + QT_END_NAMESPACE #endif // QMETATYPE_P_H |