QTypeInfo: use C++11 type traits to deduce if a type is static or complex

All types that can be trivially copied and destructed are by definition
relocatable, and we should apply those semantics when moving them in
memory.

Types that are trivial, are by definition not complex and should be
treated as such.

[ChangeLog][QtCore] Qt Containers and meta type system now use C++11
type traits (std::is_trivial, std::is_trivially_copyable and
std::is_trivially_destructible) to detect the class of a type not
explicitly set by Q_DECLARE_TYPEINFO. (Q_DECLARE_TYPEINFO is still
needed for QList.)

Done-with: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
Change-Id: Iebb87ece425ea919e86169d06cd509c54a074282
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Lars Knoll 2018-10-06 22:33:57 +02:00
parent ba304af284
commit fc85a6b6b9
4 changed files with 51 additions and 12 deletions

View File

@ -4103,6 +4103,13 @@ bool qunsetenv(const char *varName)
Example of a movable type:
\snippet code/src_corelib_global_qglobal.cpp 39
Qt will try to detect the class of a type using std::is_trivial or
std::is_trivially_copyable. Use this macro to tune the behavior.
For instance many types would be candidates for Q_MOVABLE_TYPE despite
not being trivially-copyable. For binary compatibility reasons, QList
optimizations are only enabled if there is an explicit
Q_DECLARE_TYPEINFO even for trivially-copyable types.
*/
/*!

View File

@ -49,6 +49,26 @@ QT_BEGIN_NAMESPACE
QTypeInfo - type trait functionality
*/
template <typename T>
static constexpr bool qIsRelocatable()
{
#if defined(Q_CC_CLANG) || !defined(Q_CC_GNU) || Q_CC_GNU >= 501
return std::is_trivially_copyable<T>::value && std::is_trivially_destructible<T>::value;
#else
return std::is_enum<T>::value || std::is_integral<T>::value;
#endif
}
template <typename T>
static constexpr bool qIsTrivial()
{
#if defined(Q_CC_CLANG) || !defined(Q_CC_GNU) || Q_CC_GNU >= 501
return std::is_trivial<T>::value;
#else
return std::is_enum<T>::value || std::is_integral<T>::value;
#endif
}
/*
The catch-all template.
*/
@ -61,9 +81,9 @@ public:
isSpecialized = std::is_enum<T>::value, // don't require every enum to be marked manually
isPointer = false,
isIntegral = std::is_integral<T>::value,
isComplex = !isIntegral && !std::is_enum<T>::value,
isComplex = !qIsTrivial<T>(),
isStatic = true,
isRelocatable = std::is_enum<T>::value,
isRelocatable = qIsRelocatable<T>(),
isLarge = (sizeof(T)>sizeof(void*)),
isDummy = false, //### Qt6: remove
sizeOf = sizeof(T)
@ -248,9 +268,9 @@ class QTypeInfo<TYPE > \
public: \
enum { \
isSpecialized = true, \
isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0), \
isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0) && !qIsTrivial<TYPE>(), \
isStatic = (((FLAGS) & (Q_MOVABLE_TYPE | Q_PRIMITIVE_TYPE)) == 0), \
isRelocatable = !isStatic || ((FLAGS) & Q_RELOCATABLE_TYPE), \
isRelocatable = !isStatic || ((FLAGS) & Q_RELOCATABLE_TYPE) || qIsRelocatable<TYPE>(), \
isLarge = (sizeof(TYPE)>sizeof(void*)), \
isPointer = false, \
isIntegral = std::is_integral< TYPE >::value, \

View File

@ -342,6 +342,7 @@ struct Bar
++failureCount;
}
}
~Bar() {}
public:
static int failureCount;
@ -458,7 +459,7 @@ void tst_QMetaType::threadSafety()
namespace TestSpace
{
struct Foo { double d; };
struct Foo { double d; public: ~Foo() {} };
struct QungTfu {};
}
Q_DECLARE_METATYPE(TestSpace::Foo)
@ -515,11 +516,17 @@ void tst_QMetaType::properties()
}
template <typename T>
struct Whity { T t; };
struct Whity { T t; Whity() {} };
Q_DECLARE_METATYPE( Whity < int > )
Q_DECLARE_METATYPE(Whity<double>)
#if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(Whity<double>, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif
void tst_QMetaType::normalizedTypes()
{
int WhityIntId = ::qMetaTypeId<Whity<int> >();
@ -818,10 +825,13 @@ void tst_QMetaType::sizeOfStaticLess()
QCOMPARE(size_t(QMetaType(type).sizeOf()), size);
}
struct CustomMovable {};
struct CustomMovable { CustomMovable() {} };
#if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif
Q_DECLARE_METATYPE(CustomMovable);
class CustomObject : public QObject
@ -850,13 +860,15 @@ public:
};
Q_DECLARE_METATYPE(CustomMultiInheritanceObject*);
class C { char _[4]; };
class M { char _[4]; };
class C { char _[4]; public: C() = default; C(const C&) {} };
class M { char _[4]; public: M() {} };
class P { char _[4]; };
QT_BEGIN_NAMESPACE
#if defined(Q_CC_GNU) && Q_CC_GNU < 501
Q_DECLARE_TYPEINFO(M, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(P, Q_PRIMITIVE_TYPE);
#endif
QT_END_NAMESPACE
// avoid the comma:
@ -902,7 +914,7 @@ QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(ADD_METATYPE_TEST_ROW)
QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW)
#undef ADD_METATYPE_TEST_ROW
QTest::newRow("TestSpace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << false << true << false << false;
QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << false << true << false << false;
QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << true << true << false << false;
QTest::newRow("CustomMovable") << ::qMetaTypeId<CustomMovable>() << true << true << false << false;
QTest::newRow("CustomObject*") << ::qMetaTypeId<CustomObject*>() << true << false << true << false;
QTest::newRow("CustomMultiInheritanceObject*") << ::qMetaTypeId<CustomMultiInheritanceObject*>() << true << false << true << false;

View File

@ -41,8 +41,8 @@ private Q_SLOTS:
void taskQTBUG_48780_pairContainingCArray();
};
class C { char _[4]; };
class M { char _[4]; };
class C { C() {} char _[4]; };
class M { M() {} char _[4]; };
class P { char _[4]; };
QT_BEGIN_NAMESPACE