1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include <QtCore/qglobal.h>
42#include <QtCore/qcontainerfwd.h>
43#include <variant>
44#include <optional>
45#include <tuple>
46
47#ifndef QTYPEINFO_H
48#define QTYPEINFO_H
49
50QT_BEGIN_NAMESPACE
51
52class QDebug;
53
54/*
55 QTypeInfo - type trait functionality
56*/
57
58template <typename T>
59inline constexpr bool qIsRelocatable = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
60
61/*
62 The catch-all template.
63*/
64
65template <typename T>
66class QTypeInfo
67{
68public:
69 enum {
70 isPointer = std::is_pointer_v<T>,
71 isIntegral = std::is_integral_v<T>,
72 isComplex = !std::is_trivial_v<T>,
73 isRelocatable = qIsRelocatable<T>,
74 };
75};
76
77template<>
78class QTypeInfo<void>
79{
80public:
81 enum {
82 isPointer = false,
83 isIntegral = false,
84 isComplex = false,
85 isRelocatable = false,
86 };
87};
88
89/*!
90 \class QTypeInfoMerger
91 \inmodule QtCore
92 \internal
93
94 \brief QTypeInfoMerger merges the QTypeInfo flags of T1, T2... and presents them
95 as a QTypeInfo<T> would do.
96
97 Let's assume that we have a simple set of structs:
98
99 \snippet code/src_corelib_global_qglobal.cpp 50
100
101 To create a proper QTypeInfo specialization for A struct, we have to check
102 all sub-components; B, C and D, then take the lowest common denominator and call
103 Q_DECLARE_TYPEINFO with the resulting flags. An easier and less fragile approach is to
104 use QTypeInfoMerger, which does that automatically. So struct A would have
105 the following QTypeInfo definition:
106
107 \snippet code/src_corelib_global_qglobal.cpp 51
108*/
109template <class T, class...Ts>
110class QTypeInfoMerger
111{
112 static_assert(sizeof...(Ts) > 0);
113public:
114 static constexpr bool isComplex = ((QTypeInfo<Ts>::isComplex) || ...);
115 static constexpr bool isRelocatable = ((QTypeInfo<Ts>::isRelocatable) && ...);
116 static constexpr bool isPointer = false;
117 static constexpr bool isIntegral = false;
118};
119
120#define Q_DECLARE_MOVABLE_CONTAINER(CONTAINER) \
121template <typename ...T> \
122class QTypeInfo<CONTAINER<T...>> \
123{ \
124public: \
125 enum { \
126 isPointer = false, \
127 isIntegral = false, \
128 isComplex = true, \
129 isRelocatable = true, \
130 }; \
131}
132
133Q_DECLARE_MOVABLE_CONTAINER(QList);
134Q_DECLARE_MOVABLE_CONTAINER(QQueue);
135Q_DECLARE_MOVABLE_CONTAINER(QStack);
136Q_DECLARE_MOVABLE_CONTAINER(QSet);
137Q_DECLARE_MOVABLE_CONTAINER(QMap);
138Q_DECLARE_MOVABLE_CONTAINER(QMultiMap);
139Q_DECLARE_MOVABLE_CONTAINER(QHash);
140Q_DECLARE_MOVABLE_CONTAINER(QMultiHash);
141Q_DECLARE_MOVABLE_CONTAINER(QCache);
142
143#undef Q_DECLARE_MOVABLE_CONTAINER
144
145/*
146 Specialize a specific type with:
147
148 Q_DECLARE_TYPEINFO(type, flags);
149
150 where 'type' is the name of the type to specialize and 'flags' is
151 logically-OR'ed combination of the flags below.
152*/
153enum { /* TYPEINFO flags */
154 Q_COMPLEX_TYPE = 0,
155 Q_PRIMITIVE_TYPE = 0x1,
156 Q_RELOCATABLE_TYPE = 0x2,
157 Q_MOVABLE_TYPE = 0x2,
158 Q_DUMMY_TYPE = 0x4,
159};
160
161#define Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS) \
162class QTypeInfo<TYPE > \
163{ \
164public: \
165 enum { \
166 isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0) && !std::is_trivial_v<TYPE>, \
167 isRelocatable = !isComplex || ((FLAGS) & Q_RELOCATABLE_TYPE) || qIsRelocatable<TYPE>, \
168 isPointer = false, \
169 isIntegral = std::is_integral< TYPE >::value, \
170 }; \
171}
172
173#define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \
174template<> \
175Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS)
176
177/* Specialize QTypeInfo for QFlags<T> */
178template<typename T> class QFlags;
179template<typename T>
180Q_DECLARE_TYPEINFO_BODY(QFlags<T>, Q_PRIMITIVE_TYPE);
181
182/*
183 Specialize a shared type with:
184
185 Q_DECLARE_SHARED(type)
186
187 where 'type' is the name of the type to specialize. NOTE: shared
188 types must define a member-swap, and be defined in the same
189 namespace as Qt for this to work.
190
191 If the type was already released without Q_DECLARE_SHARED applied,
192 _and_ without an explicit Q_DECLARE_TYPEINFO(type, Q_RELOCATABLE_TYPE),
193 then use Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(type) to mark the
194 type shared (incl. swap()), without marking it movable (which
195 would change the memory layout of QList, a BiC change.
196*/
197
198#define Q_DECLARE_SHARED_IMPL(TYPE, FLAGS) \
199Q_DECLARE_TYPEINFO(TYPE, FLAGS); \
200inline void swap(TYPE &value1, TYPE &value2) \
201 noexcept(noexcept(value1.swap(value2))) \
202{ value1.swap(value2); }
203#define Q_DECLARE_SHARED(TYPE) Q_DECLARE_SHARED_IMPL(TYPE, Q_RELOCATABLE_TYPE)
204#define Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(TYPE) \
205 Q_DECLARE_SHARED_IMPL(TYPE, Q_RELOCATABLE_TYPE)
206
207namespace QTypeTraits
208{
209
210/*
211 The templates below aim to find out whether one can safely instantiate an operator==() or
212 operator<() for a type.
213
214 This is tricky for containers, as most containers have unconstrained comparison operators, even though they
215 rely on the corresponding operators for its content.
216 This is especially true for all of the STL template classes that have a comparison operator defined, and
217 leads to the situation, that the compiler would try to instantiate the operator, and fail if any
218 of its template arguments does not have the operator implemented.
219
220 The code tries to cover the relevant cases for Qt and the STL, by checking (recusrsively) the value_type
221 of a container (if it exists), and checking the template arguments of pair, tuple and variant.
222*/
223namespace detail {
224
225// find out whether T is a conteiner
226// this is required to check the value type of containers for the existence of the comparison operator
227template <typename, typename = void>
228struct is_container : std::false_type {};
229template <typename T>
230struct is_container<T, std::void_t<
231 typename T::value_type,
232 std::is_convertible<decltype(std::declval<T>().begin() != std::declval<T>().end()), bool>
233>> : std::true_type {};
234
235
236// Checks the existence of the comparison operator for the class itself
237QT_WARNING_PUSH
238QT_WARNING_DISABLE_FLOAT_COMPARE
239template <typename, typename = void>
240struct has_operator_equal : std::false_type {};
241template <typename T>
242struct has_operator_equal<T, std::void_t<decltype(bool(std::declval<const T&>() == std::declval<const T&>()))>>
243 : std::true_type {};
244QT_WARNING_POP
245
246// Two forward declarations
247template<typename T, bool = is_container<T>::value>
248struct expand_operator_equal_container;
249template<typename T>
250struct expand_operator_equal_tuple;
251
252// the entry point for the public method
253template<typename T>
254using expand_operator_equal = expand_operator_equal_container<T>;
255
256// if T isn't a container check if it's a tuple like object
257template<typename T, bool>
258struct expand_operator_equal_container : expand_operator_equal_tuple<T> {};
259// if T::value_type exists, check first T::value_type, then T itself
260template<typename T>
261struct expand_operator_equal_container<T, true> :
262 std::conjunction<
263 std::disjunction<
264 std::is_same<T, typename T::value_type>, // avoid endless recursion
265 expand_operator_equal<typename T::value_type>
266 >, expand_operator_equal_tuple<T>> {};
267
268// recursively check the template arguments of a tuple like object
269template<typename ...T>
270using expand_operator_equal_recursive = std::conjunction<expand_operator_equal<T>...>;
271
272template<typename T>
273struct expand_operator_equal_tuple : has_operator_equal<T> {};
274template<typename T>
275struct expand_operator_equal_tuple<std::optional<T>> : has_operator_equal<T> {};
276template<typename T1, typename T2>
277struct expand_operator_equal_tuple<std::pair<T1, T2>> : expand_operator_equal_recursive<T1, T2> {};
278template<typename ...T>
279struct expand_operator_equal_tuple<std::tuple<T...>> : expand_operator_equal_recursive<T...> {};
280template<typename ...T>
281struct expand_operator_equal_tuple<std::variant<T...>> : expand_operator_equal_recursive<T...> {};
282
283// the same for operator<(), see above for explanations
284template <typename, typename = void>
285struct has_operator_less_than : std::false_type{};
286template <typename T>
287struct has_operator_less_than<T, std::void_t<decltype(bool(std::declval<const T&>() < std::declval<const T&>()))>>
288 : std::true_type{};
289
290template<typename T, bool = is_container<T>::value>
291struct expand_operator_less_than_container;
292template<typename T>
293struct expand_operator_less_than_tuple;
294
295template<typename T>
296using expand_operator_less_than = expand_operator_less_than_container<T>;
297
298template<typename T, bool>
299struct expand_operator_less_than_container : expand_operator_less_than_tuple<T> {};
300template<typename T>
301struct expand_operator_less_than_container<T, true> :
302 std::conjunction<
303 std::disjunction<
304 std::is_same<T, typename T::value_type>,
305 expand_operator_less_than<typename T::value_type>
306 >, expand_operator_less_than_tuple<T>
307 > {};
308
309template<typename ...T>
310using expand_operator_less_than_recursive = std::conjunction<expand_operator_less_than<T>...>;
311
312template<typename T>
313struct expand_operator_less_than_tuple : has_operator_less_than<T> {};
314template<typename T>
315struct expand_operator_less_than_tuple<std::optional<T>> : has_operator_less_than<T> {};
316template<typename T1, typename T2>
317struct expand_operator_less_than_tuple<std::pair<T1, T2>> : expand_operator_less_than_recursive<T1, T2> {};
318template<typename ...T>
319struct expand_operator_less_than_tuple<std::tuple<T...>> : expand_operator_less_than_recursive<T...> {};
320template<typename ...T>
321struct expand_operator_less_than_tuple<std::variant<T...>> : expand_operator_less_than_recursive<T...> {};
322
323}
324
325template<typename T, typename = void>
326struct is_dereferenceable : std::false_type {};
327
328template<typename T>
329struct is_dereferenceable<T, std::void_t<decltype(std::declval<T>().operator->())> >
330 : std::true_type {};
331
332template <typename T>
333inline constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value;
334
335template<typename T>
336struct has_operator_equal : detail::expand_operator_equal<T> {};
337template<typename T>
338inline constexpr bool has_operator_equal_v = has_operator_equal<T>::value;
339
340template <typename Container, typename T>
341using has_operator_equal_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_equal<T>>;
342
343template<typename T>
344struct has_operator_less_than : detail::expand_operator_less_than<T> {};
345template<typename T>
346inline constexpr bool has_operator_less_than_v = has_operator_less_than<T>::value;
347
348template <typename Container, typename T>
349using has_operator_less_than_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_less_than<T>>;
350
351template <typename ...T>
352using compare_eq_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal<T>...>, bool>;
353
354template <typename Container, typename ...T>
355using compare_eq_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal_container<Container, T>...>, bool>;
356
357template <typename ...T>
358using compare_lt_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than<T>...>, bool>;
359
360template <typename Container, typename ...T>
361using compare_lt_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than_container<Container, T>...>, bool>;
362
363namespace detail {
364
365template<typename T>
366const T &const_reference();
367template<typename T>
368T &reference();
369
370}
371
372template <typename Stream, typename, typename = void>
373struct has_ostream_operator : std::false_type {};
374template <typename Stream, typename T>
375struct has_ostream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() << detail::const_reference<T>())>>
376 : std::true_type {};
377template <typename Stream, typename T>
378inline constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
379
380template <typename Stream, typename Container, typename T>
381using has_ostream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_ostream_operator<Stream, T>>;
382
383template <typename Stream, typename, typename = void>
384struct has_istream_operator : std::false_type {};
385template <typename Stream, typename T>
386struct has_istream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() >> detail::reference<T>())>>
387 : std::true_type {};
388template <typename Stream, typename T>
389inline constexpr bool has_istream_operator_v = has_istream_operator<Stream, T>::value;
390template <typename Stream, typename Container, typename T>
391using has_istream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_istream_operator<Stream, T>>;
392
393template <typename Stream, typename T>
394inline constexpr bool has_stream_operator_v = has_ostream_operator_v<Stream, T> && has_istream_operator_v<Stream, T>;
395
396}
397
398
399QT_END_NAMESPACE
400#endif // QTYPEINFO_H
401

source code of qtbase/src/corelib/global/qtypeinfo.h