// Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QTYPEINFO_H #define QTYPEINFO_H #include #include #include QT_BEGIN_NAMESPACE class QDebug; /* QTypeInfo - type trait functionality */ namespace QtPrivate { // A trivially copyable class must also have a trivial, non-deleted // destructor [class.prop/1.3], CWG1734. Some implementations don't // check for a trivial destructor, because of backwards compatibility // with C++98's definition of trivial copyability. // Since trivial copiability has implications for the ABI, implementations // can't "just fix" their traits. So, although formally redundant, we // explicitly check for trivial destruction here. template inline constexpr bool qIsRelocatable = std::is_trivially_copyable_v && std::is_trivially_destructible_v; // Denotes types that are trivially default constructible, and for which // value-initialization can be achieved by filling their storage with 0 bits. // There is no type trait we can use for this, so we hardcode a list of // possibilities that we know are OK on the architectures that we support. // The most notable exception are pointers to data members, which for instance // on the Itanium ABI are initialized to -1. template inline constexpr bool qIsValueInitializationBitwiseZero = std::is_scalar_v && !std::is_member_object_pointer_v; } /* The catch-all template. */ template class QTypeInfo { public: enum { isPointer [[deprecated("Use std::is_pointer instead")]] = std::is_pointer_v, isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral_v, isComplex = !std::is_trivial_v, isRelocatable = QtPrivate::qIsRelocatable, isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero, }; }; template<> class QTypeInfo { public: enum { isPointer [[deprecated("Use std::is_pointer instead")]] = false, isIntegral [[deprecated("Use std::is_integral instead")]] = false, isComplex = false, isRelocatable = false, isValueInitializationBitwiseZero = false, }; }; /*! \class QTypeInfoMerger \inmodule QtCore \internal \brief QTypeInfoMerger merges the QTypeInfo flags of T1, T2... and presents them as a QTypeInfo would do. Let's assume that we have a simple set of structs: \snippet code/src_corelib_global_qglobal.cpp 50 To create a proper QTypeInfo specialization for A struct, we have to check all sub-components; B, C and D, then take the lowest common denominator and call Q_DECLARE_TYPEINFO with the resulting flags. An easier and less fragile approach is to use QTypeInfoMerger, which does that automatically. So struct A would have the following QTypeInfo definition: \snippet code/src_corelib_global_qglobal.cpp 51 */ template class QTypeInfoMerger { static_assert(sizeof...(Ts) > 0); public: static constexpr bool isComplex = ((QTypeInfo::isComplex) || ...); static constexpr bool isRelocatable = ((QTypeInfo::isRelocatable) && ...); [[deprecated("Use std::is_pointer instead")]] static constexpr bool isPointer = false; [[deprecated("Use std::is_integral instead")]] static constexpr bool isIntegral = false; static constexpr bool isValueInitializationBitwiseZero = false; static_assert(!isRelocatable || std::is_copy_constructible_v || std::is_move_constructible_v, "All Ts... are Q_RELOCATABLE_TYPE, but T is neither copy- nor move-constructible, " "so cannot be Q_RELOCATABLE_TYPE. Please mark T as Q_COMPLEX_TYPE manually."); }; // QTypeInfo for std::pair: // std::pair is spec'ed to be struct { T1 first; T2 second; }, so, unlike tuple<>, // we _can_ specialize QTypeInfo for pair<>: template class QTypeInfo> : public QTypeInfoMerger, T1, T2> {}; #define Q_DECLARE_MOVABLE_CONTAINER(CONTAINER) \ template \ class QTypeInfo> \ { \ public: \ enum { \ isPointer [[deprecated("Use std::is_pointer instead")]] = false, \ isIntegral [[deprecated("Use std::is_integral instead")]] = false, \ isComplex = true, \ isRelocatable = true, \ isValueInitializationBitwiseZero = false, \ }; \ } Q_DECLARE_MOVABLE_CONTAINER(QList); Q_DECLARE_MOVABLE_CONTAINER(QQueue); Q_DECLARE_MOVABLE_CONTAINER(QStack); Q_DECLARE_MOVABLE_CONTAINER(QSet); Q_DECLARE_MOVABLE_CONTAINER(QMap); Q_DECLARE_MOVABLE_CONTAINER(QMultiMap); Q_DECLARE_MOVABLE_CONTAINER(QHash); Q_DECLARE_MOVABLE_CONTAINER(QMultiHash); Q_DECLARE_MOVABLE_CONTAINER(QCache); #undef Q_DECLARE_MOVABLE_CONTAINER /* Specialize a specific type with: Q_DECLARE_TYPEINFO(type, flags); where 'type' is the name of the type to specialize and 'flags' is logically-OR'ed combination of the flags below. */ enum { /* TYPEINFO flags */ Q_COMPLEX_TYPE = 0, Q_PRIMITIVE_TYPE = 0x1, Q_RELOCATABLE_TYPE = 0x2, Q_MOVABLE_TYPE = 0x2, Q_DUMMY_TYPE = 0x4, }; #define Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS) \ class QTypeInfo \ { \ public: \ enum { \ isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0) && !std::is_trivial_v, \ isRelocatable = !isComplex || ((FLAGS) & Q_RELOCATABLE_TYPE) || QtPrivate::qIsRelocatable, \ isPointer [[deprecated("Use std::is_pointer instead")]] = std::is_pointer_v< TYPE >, \ isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral< TYPE >::value, \ isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero, \ }; \ static_assert(!isRelocatable || \ std::is_copy_constructible_v || \ std::is_move_constructible_v, \ #TYPE " is neither copy- nor move-constructible, so cannot be Q_RELOCATABLE_TYPE"); \ } #define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \ template<> \ Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS) /* Specialize QTypeInfo for QFlags */ template class QFlags; template Q_DECLARE_TYPEINFO_BODY(QFlags, Q_PRIMITIVE_TYPE); QT_END_NAMESPACE #endif // QTYPEINFO_H