diff options
Diffstat (limited to 'src/corelib/kernel/qmetatype.cpp')
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 106 |
1 files changed, 96 insertions, 10 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 1764c8116e..38e0d6055c 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -825,9 +825,91 @@ void QMetaType::registerStreamOperators(int idx, SaveOperator saveOp, } #endif // QT_NO_DATASTREAM +#if defined(Q_COMPILER_CONSTEXPR) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900) +// 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 Q_DECL_NOTHROW + { + 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 +#endif + /*! - Returns the type name associated with the given \a typeId, or 0 if no - matching type was found. The returned pointer must not be deleted. + 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 */ @@ -837,14 +919,18 @@ const char *QMetaType::typeName(int typeId) #define QT_METATYPE_TYPEID_TYPENAME_CONVERTER(MetaTypeName, TypeId, RealName) \ case QMetaType::MetaTypeName: return #RealName; break; - switch (QMetaType::Type(type)) { - QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_TYPEID_TYPENAME_CONVERTER) - case QMetaType::UnknownType: - case QMetaType::User: - break; - } - - if (Q_UNLIKELY(type < QMetaType::User)) { + if (Q_LIKELY(type <= QMetaType::HighestInternalId)) { +#if defined(Q_COMPILER_CONSTEXPR) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900) + return metaTypeNames[typeId]; +#else + switch (QMetaType::Type(type)) { + QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_TYPEID_TYPENAME_CONVERTER) + case QMetaType::UnknownType: + case QMetaType::User: + break; + } +#endif + } else if (Q_UNLIKELY(type < QMetaType::User)) { return nullptr; // It can happen when someone cast int to QVariant::Type, we should not crash... } |