1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QTYPEINFO_H
6#define QTYPEINFO_H
7
8#include <QtCore/qcompilerdetection.h>
9#include <QtCore/qcontainerfwd.h>
10
11#include <type_traits>
12
13QT_BEGIN_NAMESPACE
14
15class QDebug;
16
17/*
18 QTypeInfo - type trait functionality
19*/
20
21namespace QtPrivate {
22
23// A trivially copyable class must also have a trivial, non-deleted
24// destructor [class.prop/1.3], CWG1734. Some implementations don't
25// check for a trivial destructor, because of backwards compatibility
26// with C++98's definition of trivial copyability.
27// Since trivial copiability has implications for the ABI, implementations
28// can't "just fix" their traits. So, although formally redundant, we
29// explicitly check for trivial destruction here.
30template <typename T>
31inline constexpr bool qIsRelocatable = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
32
33// Denotes types that are trivially default constructible, and for which
34// value-initialization can be achieved by filling their storage with 0 bits.
35// There is no type trait we can use for this, so we hardcode a list of
36// possibilities that we know are OK on the architectures that we support.
37// The most notable exception are pointers to data members, which for instance
38// on the Itanium ABI are initialized to -1.
39template <typename T>
40inline constexpr bool qIsValueInitializationBitwiseZero =
41 std::is_scalar_v<T> && !std::is_member_object_pointer_v<T>;
42
43}
44
45/*
46 The catch-all template.
47*/
48
49template <typename T>
50class QTypeInfo
51{
52public:
53 enum {
54 isPointer [[deprecated("Use std::is_pointer instead")]] = std::is_pointer_v<T>,
55 isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral_v<T>,
56 isComplex = !std::is_trivial_v<T>,
57 isRelocatable = QtPrivate::qIsRelocatable<T>,
58 isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero<T>,
59 };
60};
61
62template<>
63class QTypeInfo<void>
64{
65public:
66 enum {
67 isPointer [[deprecated("Use std::is_pointer instead")]] = false,
68 isIntegral [[deprecated("Use std::is_integral instead")]] = false,
69 isComplex = false,
70 isRelocatable = false,
71 isValueInitializationBitwiseZero = false,
72 };
73};
74
75/*!
76 \class QTypeInfoMerger
77 \inmodule QtCore
78 \internal
79
80 \brief QTypeInfoMerger merges the QTypeInfo flags of T1, T2... and presents them
81 as a QTypeInfo<T> would do.
82
83 Let's assume that we have a simple set of structs:
84
85 \snippet code/src_corelib_global_qglobal.cpp 50
86
87 To create a proper QTypeInfo specialization for A struct, we have to check
88 all sub-components; B, C and D, then take the lowest common denominator and call
89 Q_DECLARE_TYPEINFO with the resulting flags. An easier and less fragile approach is to
90 use QTypeInfoMerger, which does that automatically. So struct A would have
91 the following QTypeInfo definition:
92
93 \snippet code/src_corelib_global_qglobal.cpp 51
94*/
95template <class T, class...Ts>
96class QTypeInfoMerger
97{
98 static_assert(sizeof...(Ts) > 0);
99public:
100 static constexpr bool isComplex = ((QTypeInfo<Ts>::isComplex) || ...);
101 static constexpr bool isRelocatable = ((QTypeInfo<Ts>::isRelocatable) && ...);
102 [[deprecated("Use std::is_pointer instead")]] static constexpr bool isPointer = false;
103 [[deprecated("Use std::is_integral instead")]] static constexpr bool isIntegral = false;
104 static constexpr bool isValueInitializationBitwiseZero = false;
105 static_assert(!isRelocatable ||
106 std::is_copy_constructible_v<T> ||
107 std::is_move_constructible_v<T>,
108 "All Ts... are Q_RELOCATABLE_TYPE, but T is neither copy- nor move-constructible, "
109 "so cannot be Q_RELOCATABLE_TYPE. Please mark T as Q_COMPLEX_TYPE manually.");
110};
111
112// QTypeInfo for std::pair:
113// std::pair is spec'ed to be struct { T1 first; T2 second; }, so, unlike tuple<>,
114// we _can_ specialize QTypeInfo for pair<>:
115template <class T1, class T2>
116class QTypeInfo<std::pair<T1, T2>> : public QTypeInfoMerger<std::pair<T1, T2>, T1, T2> {};
117
118#define Q_DECLARE_MOVABLE_CONTAINER(CONTAINER) \
119template <typename ...T> \
120class QTypeInfo<CONTAINER<T...>> \
121{ \
122public: \
123 enum { \
124 isPointer [[deprecated("Use std::is_pointer instead")]] = false, \
125 isIntegral [[deprecated("Use std::is_integral instead")]] = false, \
126 isComplex = true, \
127 isRelocatable = true, \
128 isValueInitializationBitwiseZero = false, \
129 }; \
130}
131
132Q_DECLARE_MOVABLE_CONTAINER(QList);
133Q_DECLARE_MOVABLE_CONTAINER(QQueue);
134Q_DECLARE_MOVABLE_CONTAINER(QStack);
135Q_DECLARE_MOVABLE_CONTAINER(QSet);
136Q_DECLARE_MOVABLE_CONTAINER(QMap);
137Q_DECLARE_MOVABLE_CONTAINER(QMultiMap);
138Q_DECLARE_MOVABLE_CONTAINER(QHash);
139Q_DECLARE_MOVABLE_CONTAINER(QMultiHash);
140Q_DECLARE_MOVABLE_CONTAINER(QCache);
141
142#undef Q_DECLARE_MOVABLE_CONTAINER
143
144/*
145 Specialize a specific type with:
146
147 Q_DECLARE_TYPEINFO(type, flags);
148
149 where 'type' is the name of the type to specialize and 'flags' is
150 logically-OR'ed combination of the flags below.
151*/
152enum { /* TYPEINFO flags */
153 Q_COMPLEX_TYPE = 0,
154 Q_PRIMITIVE_TYPE = 0x1,
155 Q_RELOCATABLE_TYPE = 0x2,
156 Q_MOVABLE_TYPE = 0x2,
157 Q_DUMMY_TYPE = 0x4,
158};
159
160#define Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS) \
161class QTypeInfo<TYPE > \
162{ \
163public: \
164 enum { \
165 isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0) && !std::is_trivial_v<TYPE>, \
166 isRelocatable = !isComplex || ((FLAGS) & Q_RELOCATABLE_TYPE) || QtPrivate::qIsRelocatable<TYPE>, \
167 isPointer [[deprecated("Use std::is_pointer instead")]] = std::is_pointer_v< TYPE >, \
168 isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral< TYPE >::value, \
169 isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero<TYPE>, \
170 }; \
171 static_assert(!isRelocatable || \
172 std::is_copy_constructible_v<TYPE > || \
173 std::is_move_constructible_v<TYPE >, \
174 #TYPE " is neither copy- nor move-constructible, so cannot be Q_RELOCATABLE_TYPE"); \
175}
176
177#define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \
178template<> \
179Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS)
180
181/* Specialize QTypeInfo for QFlags<T> */
182template<typename T> class QFlags;
183template<typename T>
184Q_DECLARE_TYPEINFO_BODY(QFlags<T>, Q_PRIMITIVE_TYPE);
185
186QT_END_NAMESPACE
187#endif // QTYPEINFO_H
188