summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-02-14 10:05:34 -0800
committerThiago Macieira <thiago.macieira@intel.com>2017-03-09 14:56:35 +0000
commitef26467eb21c5282dcad53c4da109d99ff4395aa (patch)
tree28156259d31f35f03ac840af7c6cbd4f32698ba8 /src/corelib
parentf8218637e9e5fa8f50ef25da293b95f767eaefc2 (diff)
Reintroduce a directed QMetaType::typeName array
Commit fb376e0fcc8d2d0a1731a588bfc6497d05e090e6 removed an array that facilitated returning the names of built-in types, to avoid the jump tables from the switch statement. This commit brings it back but makes the array a compile-time constant string offset table. The array is created by way of a set of C++11 constexpr functions, so we require that compiler feature. I've tested that MSVC 2015 does support it as well as the ICC 17 when masquerading as MSVC 2015, so I've enabled for that too. The only compiler left out is MSVC 2013. If we didn't need to support MSVC 2015, this could have been written more simply with C++14 relaxed constexpr. This also adds unit tests to confirm that QMetaType::typeName() does return null when we said it would. We're testing QMetaType::User-1 (which we'll likely never use) and QMetaType::LastWidgetsType-1 to select something inside the range of the built-in types. Task-number: QTBUG-58851 Change-Id: I4139d5f93dcb4b429ae9fffd14a33982891e2ac1 Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qmetatype.cpp106
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...
}