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 T1, typename T2>
315struct expand_operator_less_than_tuple<std::pair<T1, T2>> : expand_operator_less_than_recursive<T1, T2> {};
316template<typename ...T>
317struct expand_operator_less_than_tuple<std::tuple<T...>> : expand_operator_less_than_recursive<T...> {};
318template<typename ...T>
319struct expand_operator_less_than_tuple<std::variant<T...>> : expand_operator_less_than_recursive<T...> {};
320
321}
322
323template<typename T, typename = void>
324struct is_dereferenceable : std::false_type {};
325
326template<typename T>
327struct is_dereferenceable<T, std::void_t<decltype(std::declval<T>().operator->())> >
328 : std::true_type {};
329
330template <typename T>
331inline constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value;
332
333template<typename T>
334struct has_operator_equal : detail::expand_operator_equal<T> {};
335template<typename T>
336inline constexpr bool has_operator_equal_v = has_operator_equal<T>::value;
337
338template<typename T>
339struct has_operator_less_than : detail::expand_operator_less_than<T> {};
340template<typename T>
341inline constexpr bool has_operator_less_than_v = has_operator_less_than<T>::value;
342
343template <typename ...T>
344using compare_eq_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal<T>...>, bool>;
345
346template <typename ...T>
347using compare_lt_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than<T>...>, bool>;
348
349namespace detail {
350
351template<typename T>
352const T &const_reference();
353template<typename T>
354T &reference();
355
356}
357
358template <typename Stream, typename, typename = void>
359struct has_ostream_operator : std::false_type {};
360template <typename Stream, typename T>
361struct has_ostream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() << detail::const_reference<T>())>>
362 : std::true_type {};
363template <typename Stream, typename T>
364inline constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
365
366template <typename Stream, typename, typename = void>
367struct has_istream_operator : std::false_type {};
368template <typename Stream, typename T>
369struct has_istream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() >> detail::reference<T>())>>
370 : std::true_type {};
371template <typename Stream, typename T>
372inline constexpr bool has_istream_operator_v = has_istream_operator<Stream, T>::value;
373
374template <typename Stream, typename T>
375inline constexpr bool has_stream_operator_v = has_ostream_operator_v<Stream, T> && has_istream_operator_v<Stream, T>;
376
377}
378
379
380QT_END_NAMESPACE
381#endif // QTYPEINFO_H
382