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#ifndef QVARIANT_P_H
42#define QVARIANT_P_H
43
44//
45// W A R N I N G
46// -------------
47//
48// This file is not part of the Qt API. It exists purely as an
49// implementation detail. This header file may change from version to
50// version without notice, or even be removed.
51//
52// We mean it.
53//
54
55#include <QtCore/qglobal.h>
56#include <QtCore/qvariant.h>
57#include <QtCore/private/qmetatype_p.h>
58#include <QtCore/qdebug.h>
59
60#include "qmetatypeswitcher_p.h"
61
62QT_BEGIN_NAMESPACE
63
64template<typename T>
65struct QVariantIntegrator
66{
67 static const bool CanUseInternalSpace = sizeof(T) <= sizeof(QVariant::Private::Data)
68 && ((QTypeInfoQuery<T>::isRelocatable) || std::is_enum<T>::value);
69 typedef std::integral_constant<bool, CanUseInternalSpace> CanUseInternalSpace_t;
70};
71Q_STATIC_ASSERT(QVariantIntegrator<double>::CanUseInternalSpace);
72Q_STATIC_ASSERT(QVariantIntegrator<long int>::CanUseInternalSpace);
73Q_STATIC_ASSERT(QVariantIntegrator<qulonglong>::CanUseInternalSpace);
74
75#ifdef Q_CC_SUN // Sun CC picks the wrong overload, so introduce awful hack
76
77// takes a type, returns the internal void* pointer cast
78// to a pointer of the input type
79template <typename T>
80inline T *v_cast(const QVariant::Private *nd, T * = 0)
81{
82 QVariant::Private *d = const_cast<QVariant::Private *>(nd);
83 return !QVariantIntegrator<T>::CanUseInternalSpace
84 ? static_cast<T *>(d->data.shared->ptr)
85 : static_cast<T *>(static_cast<void *>(&d->data.c));
86}
87
88#else // every other compiler in this world
89
90template <typename T>
91inline const T *v_cast(const QVariant::Private *d, T * = nullptr)
92{
93 return !QVariantIntegrator<T>::CanUseInternalSpace
94 ? static_cast<const T *>(d->data.shared->ptr)
95 : static_cast<const T *>(static_cast<const void *>(&d->data.c));
96}
97
98template <typename T>
99inline T *v_cast(QVariant::Private *d, T * = nullptr)
100{
101 return !QVariantIntegrator<T>::CanUseInternalSpace
102 ? static_cast<T *>(d->data.shared->ptr)
103 : static_cast<T *>(static_cast<void *>(&d->data.c));
104}
105
106#endif
107
108enum QVariantConstructionFlags : uint {
109 Default = 0x0,
110 PointerType = 0x1,
111 ShouldDeleteVariantData = 0x2 // only used in Q*Iterable
112};
113
114//a simple template that avoids to allocate 2 memory chunks when creating a QVariant
115template <class T> class QVariantPrivateSharedEx : public QVariant::PrivateShared
116{
117public:
118 QVariantPrivateSharedEx() : QVariant::PrivateShared(&m_t), m_t() { }
119 QVariantPrivateSharedEx(const T&t) : QVariant::PrivateShared(&m_t), m_t(t) { }
120
121private:
122 T m_t;
123};
124
125template <class T>
126inline void v_construct_helper(QVariant::Private *x, const T &t, std::true_type)
127{
128 new (&x->data) T(t);
129 x->is_shared = false;
130}
131
132template <class T>
133inline void v_construct_helper(QVariant::Private *x, const T &t, std::false_type)
134{
135 x->data.shared = new QVariantPrivateSharedEx<T>(t);
136 x->is_shared = true;
137}
138
139template <class T>
140inline void v_construct_helper(QVariant::Private *x, std::true_type)
141{
142 new (&x->data) T();
143 x->is_shared = false;
144}
145
146template <class T>
147inline void v_construct_helper(QVariant::Private *x, std::false_type)
148{
149 x->data.shared = new QVariantPrivateSharedEx<T>;
150 x->is_shared = true;
151}
152
153template <class T>
154inline void v_construct(QVariant::Private *x, const T &t)
155{
156 // dispatch
157 v_construct_helper(x, t, typename QVariantIntegrator<T>::CanUseInternalSpace_t());
158}
159
160// constructs a new variant if copy is 0, otherwise copy-constructs
161template <class T>
162inline void v_construct(QVariant::Private *x, const void *copy, T * = nullptr)
163{
164 if (copy)
165 v_construct<T>(x, *static_cast<const T *>(copy));
166 else
167 v_construct_helper<T>(x, typename QVariantIntegrator<T>::CanUseInternalSpace_t());
168}
169
170// deletes the internal structures
171template <class T>
172inline void v_clear(QVariant::Private *d, T* = nullptr)
173{
174
175 if (!QVariantIntegrator<T>::CanUseInternalSpace) {
176 //now we need to cast
177 //because QVariant::PrivateShared doesn't have a virtual destructor
178 delete static_cast<QVariantPrivateSharedEx<T>*>(d->data.shared);
179 } else {
180 v_cast<T>(d)->~T();
181 }
182
183}
184
185template <typename T>
186struct PrimitiveIsNull
187{
188public:
189 static bool isNull(const QVariant::Private *d)
190 {
191 return d->is_null;
192 }
193};
194
195template <typename T>
196struct PrimitiveIsNull<T*>
197{
198public:
199 static bool isNull(const QVariant::Private *d)
200 {
201 return d->is_null || d->data.ptr == nullptr;
202 }
203};
204
205template <>
206struct PrimitiveIsNull<std::nullptr_t>
207{
208public:
209 static bool isNull(const QVariant::Private *)
210 {
211 return true;
212 }
213};
214
215template<class Filter>
216class QVariantComparator {
217 template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
218 struct FilteredComparator {
219 static bool compare(const QVariant::Private *a, const QVariant::Private *b)
220 {
221 return *v_cast<T>(a) == *v_cast<T>(b);
222 }
223 };
224 template<typename T>
225 struct FilteredComparator<T, /* IsAcceptedType = */ false> {
226 static bool compare(const QVariant::Private *, const QVariant::Private *)
227 {
228 // It is not possible to construct a QVariant containing not fully defined type
229 Q_ASSERT(false);
230 return false;
231 }
232 };
233public:
234 QVariantComparator(const QVariant::Private *a, const QVariant::Private *b)
235 : m_a(a), m_b(b)
236 {
237 Q_ASSERT(a->type == b->type);
238 }
239
240 template<typename T>
241 bool delegate(const T*)
242 {
243 return FilteredComparator<T>::compare(m_a, m_b);
244 }
245
246 bool delegate(const void*) { Q_ASSERT(false); return true; }
247 bool delegate(const QMetaTypeSwitcher::UnknownType*)
248 {
249 return true; // for historical reason invalid variant == invalid variant
250 }
251 bool delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return false; }
252protected:
253 const QVariant::Private *m_a;
254 const QVariant::Private *m_b;
255};
256
257
258Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler();
259
260template<class Filter>
261class QVariantIsNull
262{
263 /// \internal
264 /// This class checks if a type T has method called isNull. Result is kept in the Value property
265 /// TODO Can we somehow generalize it? A macro version?
266 template<typename T>
267 class HasIsNullMethod {
268 struct Yes { char unused[1]; };
269 struct No { char unused[2]; };
270 Q_STATIC_ASSERT(sizeof(Yes) != sizeof(No));
271
272 template<class C> static decltype(static_cast<const C*>(nullptr)->isNull(), Yes()) test(int);
273 template<class C> static No test(...);
274 public:
275 static const bool Value = (sizeof(test<T>(0)) == sizeof(Yes));
276 };
277
278 // TODO This part should go to autotests during HasIsNullMethod generalization.
279 Q_STATIC_ASSERT(!HasIsNullMethod<bool>::Value);
280 struct SelfTest1 { bool isNull() const; };
281 Q_STATIC_ASSERT(HasIsNullMethod<SelfTest1>::Value);
282 struct SelfTest2 {};
283 Q_STATIC_ASSERT(!HasIsNullMethod<SelfTest2>::Value);
284 struct SelfTest3 : public SelfTest1 {};
285 Q_STATIC_ASSERT(HasIsNullMethod<SelfTest3>::Value);
286 struct SelfTestFinal1 final { bool isNull() const; };
287 Q_STATIC_ASSERT(HasIsNullMethod<SelfTestFinal1>::Value);
288 struct SelfTestFinal2 final {};
289 Q_STATIC_ASSERT(!HasIsNullMethod<SelfTestFinal2>::Value);
290 struct SelfTestFinal3 final : public SelfTest1 {};
291 Q_STATIC_ASSERT(HasIsNullMethod<SelfTestFinal3>::Value);
292
293 template<typename T, bool HasIsNull = HasIsNullMethod<T>::Value>
294 struct CallFilteredIsNull
295 {
296 static bool isNull(const QVariant::Private *d)
297 {
298 return v_cast<T>(d)->isNull();
299 }
300 };
301 template<typename T>
302 struct CallFilteredIsNull<T, /* HasIsNull = */ false>
303 {
304 static bool isNull(const QVariant::Private *d)
305 {
306 return PrimitiveIsNull<T>::isNull(d);
307 }
308 };
309
310 template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
311 struct CallIsNull
312 {
313 static bool isNull(const QVariant::Private *d)
314 {
315 return CallFilteredIsNull<T>::isNull(d);
316 }
317 };
318 template<typename T>
319 struct CallIsNull<T, /* IsAcceptedType = */ false>
320 {
321 static bool isNull(const QVariant::Private *d)
322 {
323 return CallFilteredIsNull<T, false>::isNull(d);
324 }
325 };
326
327public:
328 QVariantIsNull(const QVariant::Private *d)
329 : m_d(d)
330 {}
331 template<typename T>
332 bool delegate(const T*)
333 {
334 return CallIsNull<T>::isNull(m_d);
335 }
336 // we need that as sizof(void) is undefined and it is needed in HasIsNullMethod
337 bool delegate(const void *) { Q_ASSERT(false); return m_d->is_null; }
338 bool delegate(const QMetaTypeSwitcher::UnknownType *) { return m_d->is_null; }
339 bool delegate(const QMetaTypeSwitcher::NotBuiltinType *)
340 {
341 // QVariantIsNull is used only for built-in types
342 Q_ASSERT(false);
343 return m_d->is_null;
344 }
345protected:
346 const QVariant::Private *m_d;
347};
348
349template<class Filter>
350class QVariantConstructor
351{
352 template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
353 struct FilteredConstructor {
354 FilteredConstructor(const QVariantConstructor &tc)
355 {
356 v_construct<T>(tc.m_x, tc.m_copy);
357 tc.m_x->is_null = !tc.m_copy;
358 }
359 };
360 template<typename T>
361 struct FilteredConstructor<T, /* IsAcceptedType = */ false> {
362 FilteredConstructor(const QVariantConstructor &tc)
363 {
364 // ignore types that lives outside of the current library
365 tc.m_x->type = QMetaType::UnknownType;
366 }
367 };
368public:
369 QVariantConstructor(QVariant::Private *x, const void *copy)
370 : m_x(x)
371 , m_copy(copy)
372 {}
373
374 template<typename T>
375 void delegate(const T*)
376 {
377 FilteredConstructor<T>(*this);
378 }
379
380 void delegate(const QMetaTypeSwitcher::NotBuiltinType*)
381 {
382 // QVariantConstructor is used only for built-in types.
383 Q_ASSERT(false);
384 }
385
386 void delegate(const void*)
387 {
388 qWarning(msg: "Trying to create a QVariant instance of QMetaType::Void type, an invalid QVariant will be constructed instead");
389 m_x->type = QMetaType::UnknownType;
390 m_x->is_shared = false;
391 m_x->is_null = !m_copy;
392 }
393
394 void delegate(const QMetaTypeSwitcher::UnknownType*)
395 {
396 if (m_x->type != QMetaType::UnknownType) {
397 qWarning(msg: "Trying to construct an instance of an invalid type, type id: %i", m_x->type);
398 m_x->type = QMetaType::UnknownType;
399 }
400 m_x->is_shared = false;
401 m_x->is_null = !m_copy;
402 }
403private:
404 QVariant::Private *m_x;
405 const void *m_copy;
406};
407
408template<class Filter>
409class QVariantDestructor
410{
411 template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
412 struct FilteredDestructor {
413 FilteredDestructor(QVariant::Private *d)
414 {
415 v_clear<T>(d);
416 }
417 };
418 template<typename T>
419 struct FilteredDestructor<T, /* IsAcceptedType = */ false> {
420 FilteredDestructor(QVariant::Private *)
421 {
422 // It is not possible to create not accepted type
423 Q_ASSERT(false);
424 }
425 };
426
427public:
428 QVariantDestructor(QVariant::Private *d)
429 : m_d(d)
430 {}
431 ~QVariantDestructor()
432 {
433 m_d->type = QMetaType::UnknownType;
434 m_d->is_null = true;
435 m_d->is_shared = false;
436 }
437
438 template<typename T>
439 void delegate(const T*)
440 {
441 FilteredDestructor<T> cleaner(m_d);
442 }
443
444 void delegate(const QMetaTypeSwitcher::NotBuiltinType*)
445 {
446 // QVariantDestructor class is used only for a built-in type
447 Q_ASSERT(false);
448 }
449 // Ignore nonconstructible type
450 void delegate(const QMetaTypeSwitcher::UnknownType*) {}
451 void delegate(const void*) { Q_ASSERT(false); }
452private:
453 QVariant::Private *m_d;
454};
455
456namespace QVariantPrivate {
457Q_CORE_EXPORT void registerHandler(const int /* Modules::Names */ name, const QVariant::Handler *handler);
458}
459
460#if !defined(QT_NO_DEBUG_STREAM)
461template<class Filter>
462class QVariantDebugStream
463{
464 template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
465 struct Filtered {
466 Filtered(QDebug dbg, QVariant::Private *d)
467 {
468 dbg.nospace() << *v_cast<T>(d);
469 }
470 };
471 template<typename T>
472 struct Filtered<T, /* IsAcceptedType = */ false> {
473 Filtered(QDebug /* dbg */, QVariant::Private *)
474 {
475 // It is not possible to construct not acccepted type, QVariantConstructor creates an invalid variant for them
476 Q_ASSERT(false);
477 }
478 };
479
480public:
481 QVariantDebugStream(QDebug dbg, QVariant::Private *d)
482 : m_debugStream(dbg)
483 , m_d(d)
484 {}
485
486 template<typename T>
487 void delegate(const T*)
488 {
489 Filtered<T> streamIt(m_debugStream, m_d);
490 Q_UNUSED(streamIt);
491 }
492
493 void delegate(const QMetaTypeSwitcher::NotBuiltinType*)
494 {
495 // QVariantDebugStream class is used only for a built-in type
496 Q_ASSERT(false);
497 }
498 void delegate(const QMetaTypeSwitcher::UnknownType*)
499 {
500 m_debugStream.nospace() << "QVariant::Invalid";
501 }
502 void delegate(const void*) { Q_ASSERT(false); }
503private:
504 QDebug m_debugStream;
505 QVariant::Private *m_d;
506};
507#endif
508
509QT_END_NAMESPACE
510
511#endif // QVARIANT_P_H
512

source code of qtbase/src/corelib/kernel/qvariant_p.h