1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QVARIANT_H
5#define QVARIANT_H
6
7#include <QtCore/qatomic.h>
8#include <QtCore/qcontainerfwd.h>
9#include <QtCore/qmetatype.h>
10#ifndef QT_NO_DEBUG_STREAM
11#include <QtCore/qdebug.h>
12#endif
13
14#include <memory>
15#include <QtCore/q20type_traits.h>
16#include <QtCore/q23utility.h>
17#include <variant>
18
19#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1
20# include <QtCore/qlist.h>
21# include <QtCore/qstringlist.h>
22# include <QtCore/qbytearraylist.h>
23# include <QtCore/qhash.h>
24# include <QtCore/qmap.h>
25# include <QtCore/qobject.h>
26#endif
27
28QT_BEGIN_NAMESPACE
29
30QT_ENABLE_P0846_SEMANTICS_FOR(get_if)
31QT_ENABLE_P0846_SEMANTICS_FOR(get)
32
33class QBitArray;
34class QDataStream;
35class QDate;
36class QDateTime;
37class QEasingCurve;
38class QLine;
39class QLineF;
40class QLocale;
41class QModelIndex;
42class QPersistentModelIndex;
43class QPoint;
44class QPointF;
45class QRect;
46class QRectF;
47class QRegularExpression;
48class QSize;
49class QSizeF;
50class QTextFormat;
51class QTextLength;
52class QTime;
53class QTransform;
54class QUrl;
55class QVariant;
56
57template<typename T>
58inline T qvariant_cast(const QVariant &);
59
60namespace QtPrivate {
61template<> constexpr inline bool qIsRelocatable<QVariant> = true;
62}
63class Q_CORE_EXPORT QVariant
64{
65 template <typename T, typename... Args>
66 using if_constructible = std::enable_if_t<
67 std::conjunction_v<
68 std::is_copy_constructible<q20::remove_cvref_t<T>>,
69 std::is_destructible<q20::remove_cvref_t<T>>,
70 std::is_constructible<q20::remove_cvref_t<T>, Args...>
71 >,
72 bool>;
73
74 template <typename T>
75 using if_rvalue = std::enable_if_t<!std::is_reference_v<T>, bool>;
76
77 struct CborValueStandIn { qint64 n; void *c; int t; };
78public:
79 struct PrivateShared
80 {
81 private:
82 inline PrivateShared() : ref(1) { }
83 public:
84 static int computeOffset(PrivateShared *ps, size_t align);
85 static size_t computeAllocationSize(size_t size, size_t align);
86 static PrivateShared *create(size_t size, size_t align);
87 static void free(PrivateShared *p);
88
89 alignas(8) QAtomicInt ref;
90 int offset;
91
92 const void *data() const { return reinterpret_cast<const uchar *>(this) + offset; }
93 void *data() { return reinterpret_cast<uchar *>(this) + offset; }
94 };
95
96 struct Private
97 {
98 static constexpr size_t MaxInternalSize = 3 * sizeof(void *);
99 template <size_t S> static constexpr bool FitsInInternalSize = S <= MaxInternalSize;
100 template<typename T> static constexpr bool CanUseInternalSpace =
101 (QTypeInfo<T>::isRelocatable && FitsInInternalSize<sizeof(T)> && alignof(T) <= alignof(double));
102 static constexpr bool canUseInternalSpace(const QtPrivate::QMetaTypeInterface *type)
103 {
104 Q_ASSERT(type);
105 return QMetaType::TypeFlags(type->flags) & QMetaType::RelocatableType &&
106 size_t(type->size) <= MaxInternalSize && size_t(type->alignment) <= alignof(double);
107 }
108
109 union
110 {
111 uchar data[MaxInternalSize] = {};
112 PrivateShared *shared;
113 double _forAlignment; // we want an 8byte alignment on 32bit systems as well
114 } data;
115 quintptr is_shared : 1;
116 quintptr is_null : 1;
117 quintptr packedType : sizeof(QMetaType) * 8 - 2;
118
119 constexpr Private() noexcept : is_shared(false), is_null(true), packedType(0) {}
120 explicit Private(const QtPrivate::QMetaTypeInterface *iface) noexcept;
121 template <typename T> explicit Private(std::piecewise_construct_t, const T &t);
122
123 const void *storage() const
124 { return is_shared ? data.shared->data() : &data.data; }
125
126 // determine internal storage at compile time
127 template<typename T> const T &get() const
128 { return *static_cast<const T *>(CanUseInternalSpace<T> ? &data.data : data.shared->data()); }
129
130 inline const QtPrivate::QMetaTypeInterface *typeInterface() const
131 {
132 return reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(packedType << 2);
133 }
134
135 inline QMetaType type() const
136 {
137 return QMetaType(typeInterface());
138 }
139 };
140
141#if QT_DEPRECATED_SINCE(6, 0)
142 enum QT_DEPRECATED_VERSION_X_6_0("Use QMetaType::Type instead.") Type
143 {
144 Invalid = QMetaType::UnknownType,
145 Bool = QMetaType::Bool,
146 Int = QMetaType::Int,
147 UInt = QMetaType::UInt,
148 LongLong = QMetaType::LongLong,
149 ULongLong = QMetaType::ULongLong,
150 Double = QMetaType::Double,
151 Char = QMetaType::QChar,
152 Map = QMetaType::QVariantMap,
153 List = QMetaType::QVariantList,
154 String = QMetaType::QString,
155 StringList = QMetaType::QStringList,
156 ByteArray = QMetaType::QByteArray,
157 BitArray = QMetaType::QBitArray,
158 Date = QMetaType::QDate,
159 Time = QMetaType::QTime,
160 DateTime = QMetaType::QDateTime,
161 Url = QMetaType::QUrl,
162 Locale = QMetaType::QLocale,
163 Rect = QMetaType::QRect,
164 RectF = QMetaType::QRectF,
165 Size = QMetaType::QSize,
166 SizeF = QMetaType::QSizeF,
167 Line = QMetaType::QLine,
168 LineF = QMetaType::QLineF,
169 Point = QMetaType::QPoint,
170 PointF = QMetaType::QPointF,
171#if QT_CONFIG(regularexpression)
172 RegularExpression = QMetaType::QRegularExpression,
173#endif
174 Hash = QMetaType::QVariantHash,
175#if QT_CONFIG(easingcurve)
176 EasingCurve = QMetaType::QEasingCurve,
177#endif
178 Uuid = QMetaType::QUuid,
179#if QT_CONFIG(itemmodel)
180 ModelIndex = QMetaType::QModelIndex,
181 PersistentModelIndex = QMetaType::QPersistentModelIndex,
182#endif
183 LastCoreType = QMetaType::LastCoreType,
184
185 Font = QMetaType::QFont,
186 Pixmap = QMetaType::QPixmap,
187 Brush = QMetaType::QBrush,
188 Color = QMetaType::QColor,
189 Palette = QMetaType::QPalette,
190 Image = QMetaType::QImage,
191 Polygon = QMetaType::QPolygon,
192 Region = QMetaType::QRegion,
193 Bitmap = QMetaType::QBitmap,
194 Cursor = QMetaType::QCursor,
195#if QT_CONFIG(shortcut)
196 KeySequence = QMetaType::QKeySequence,
197#endif
198 Pen = QMetaType::QPen,
199 TextLength = QMetaType::QTextLength,
200 TextFormat = QMetaType::QTextFormat,
201 Transform = QMetaType::QTransform,
202 Matrix4x4 = QMetaType::QMatrix4x4,
203 Vector2D = QMetaType::QVector2D,
204 Vector3D = QMetaType::QVector3D,
205 Vector4D = QMetaType::QVector4D,
206 Quaternion = QMetaType::QQuaternion,
207 PolygonF = QMetaType::QPolygonF,
208 Icon = QMetaType::QIcon,
209 LastGuiType = QMetaType::LastGuiType,
210
211 SizePolicy = QMetaType::QSizePolicy,
212
213 UserType = QMetaType::User,
214 LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type
215 };
216#endif
217 QVariant() noexcept : d() {}
218 ~QVariant();
219 explicit QVariant(QMetaType type, const void *copy = nullptr);
220 QVariant(const QVariant &other);
221
222private:
223 template <typename T, typename ...Args>
224 using is_noexcept_constructible = std::conjunction<
225 std::bool_constant<Private::CanUseInternalSpace<T>>,
226 std::is_nothrow_constructible<T, Args...>
227 >;
228
229public:
230 template <typename T, typename... Args,
231 if_constructible<T, Args...> = true>
232 explicit QVariant(std::in_place_type_t<T>, Args&&... args)
233 noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, Args...>::value)
234 : QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<T>>() )
235 {
236 void *data = const_cast<void *>(constData());
237 new (data) T(std::forward<Args>(args)...);
238 }
239
240 template <typename T, typename U, typename... Args,
241 if_constructible<T, std::initializer_list<U> &, Args...> = true>
242 explicit QVariant(std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args)
243 noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>,
244 std::initializer_list<U> &,
245 Args...
246 >::value)
247 : QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<T>>())
248 {
249 char *data = static_cast<char *>(const_cast<void *>(constData()));
250 new (data) T(il, std::forward<Args>(args)...);
251 }
252
253 // primitives
254 QVariant(int i) noexcept;
255 QVariant(uint ui) noexcept;
256 QVariant(qlonglong ll) noexcept;
257 QVariant(qulonglong ull) noexcept;
258 QVariant(bool b) noexcept;
259 QVariant(double d) noexcept;
260 QVariant(float f) noexcept;
261
262 // trivial, trivially-copyable or COW
263 QVariant(QChar qchar) noexcept;
264 QVariant(QDate date) noexcept;
265 QVariant(QTime time) noexcept;
266#ifndef QT_BOOTSTRAPPED
267 QVariant(const QBitArray &bitarray) noexcept;
268#endif
269 QVariant(const QByteArray &bytearray) noexcept;
270 QVariant(const QDateTime &datetime) noexcept;
271 QVariant(const QHash<QString, QVariant> &hash) noexcept;
272 QVariant(const QJsonArray &jsonArray) noexcept;
273 QVariant(const QJsonObject &jsonObject) noexcept;
274 QVariant(const QList<QVariant> &list) noexcept;
275 QVariant(const QLocale &locale) noexcept;
276 QVariant(const QMap<QString, QVariant> &map) noexcept;
277 QVariant(const QRegularExpression &re) noexcept;
278 QVariant(const QString &string) noexcept;
279 QVariant(const QStringList &stringlist) noexcept;
280 QVariant(const QUrl &url) noexcept;
281
282 // conditionally noexcept trivial or trivially-copyable
283 // (most of these are noexcept on 64-bit)
284 QVariant(const QJsonValue &jsonValue) noexcept(Private::FitsInInternalSize<sizeof(CborValueStandIn)>);
285 QVariant(const QModelIndex &modelIndex) noexcept(Private::FitsInInternalSize<8 + 2 * sizeof(quintptr)>);
286 QVariant(QUuid uuid) noexcept(Private::FitsInInternalSize<16>);
287#ifndef QT_NO_GEOM_VARIANT
288 QVariant(QSize size) noexcept;
289 QVariant(QSizeF size) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 2>);
290 QVariant(QPoint pt) noexcept;
291 QVariant(QPointF pt) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 2>);
292 QVariant(QLine line) noexcept(Private::FitsInInternalSize<sizeof(int) * 4>);
293 QVariant(QLineF line) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 4>);
294 QVariant(QRect rect) noexcept(Private::FitsInInternalSize<sizeof(int) * 4>);
295 QVariant(QRectF rect) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 4>);
296#endif
297
298 // not noexcept
299 QVariant(const QEasingCurve &easing) noexcept(false);
300 QVariant(const QJsonDocument &jsonDocument) noexcept(false);
301 QVariant(const QPersistentModelIndex &modelIndex) noexcept(false);
302
303#ifndef QT_NO_CAST_FROM_ASCII
304 QT_ASCII_CAST_WARN QVariant(const char *str) noexcept(false)
305 : QVariant(QString::fromUtf8(str))
306 {}
307#endif
308 QVariant(QLatin1StringView string) noexcept(false); // converts to QString
309
310#if !defined(Q_CC_GHS)
311 // GHS has an ICE with this code; use the simplified version below
312 template <typename T,
313 std::enable_if_t<std::disjunction_v<std::is_pointer<T>, std::is_member_pointer<T>>, bool> = false>
314 QVariant(T) = delete;
315#else
316 QVariant(const volatile void *) = delete;
317#endif
318
319#if QT_CORE_REMOVED_SINCE(6, 5)
320 QVariant(const QSize &size);
321 QVariant(const QSizeF &size);
322 QVariant(const QPoint &pt);
323 QVariant(const QPointF &pt);
324 QVariant(const QLine &line);
325 QVariant(const QLineF &line);
326 QVariant(const QRect &rect);
327 QVariant(const QRectF &rect);
328 QVariant(const QUuid &uuid);
329#endif
330
331 QVariant& operator=(const QVariant &other);
332 inline QVariant(QVariant &&other) noexcept : d(other.d)
333 { other.d = Private(); }
334 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QVariant)
335
336 inline void swap(QVariant &other) noexcept { std::swap(a&: d, b&: other.d); }
337
338 int userType() const { return typeId(); }
339 int typeId() const { return metaType().id(); }
340
341 const char *typeName() const;
342 QMetaType metaType() const;
343
344 bool canConvert(QMetaType targetType) const
345 { return QMetaType::canConvert(fromType: d.type(), toType: targetType); }
346 bool convert(QMetaType type);
347
348 bool canView(QMetaType targetType) const
349 { return QMetaType::canView(fromType: d.type(), toType: targetType); }
350
351#if QT_DEPRECATED_SINCE(6, 0)
352 QT_DEPRECATED_VERSION_6_0
353 bool canConvert(int targetTypeId) const
354 { return QMetaType::canConvert(fromType: d.type(), toType: QMetaType(targetTypeId)); }
355 QT_DEPRECATED_VERSION_6_0
356 bool convert(int targetTypeId)
357 { return convert(type: QMetaType(targetTypeId)); }
358#endif
359
360 inline bool isValid() const;
361 bool isNull() const;
362
363 void clear();
364
365 void detach();
366 inline bool isDetached() const;
367
368 int toInt(bool *ok = nullptr) const;
369 uint toUInt(bool *ok = nullptr) const;
370 qlonglong toLongLong(bool *ok = nullptr) const;
371 qulonglong toULongLong(bool *ok = nullptr) const;
372 bool toBool() const;
373 double toDouble(bool *ok = nullptr) const;
374 float toFloat(bool *ok = nullptr) const;
375 qreal toReal(bool *ok = nullptr) const;
376 QByteArray toByteArray() const;
377#ifndef QT_BOOTSTRAPPED
378 QBitArray toBitArray() const;
379#endif
380 QString toString() const;
381 QStringList toStringList() const;
382 QChar toChar() const;
383 QDate toDate() const;
384 QTime toTime() const;
385 QDateTime toDateTime() const;
386 QList<QVariant> toList() const;
387 QMap<QString, QVariant> toMap() const;
388 QHash<QString, QVariant> toHash() const;
389
390#ifndef QT_NO_GEOM_VARIANT
391 QPoint toPoint() const;
392 QPointF toPointF() const;
393 QRect toRect() const;
394 QSize toSize() const;
395 QSizeF toSizeF() const;
396 QLine toLine() const;
397 QLineF toLineF() const;
398 QRectF toRectF() const;
399#endif
400 QLocale toLocale() const;
401#if QT_CONFIG(regularexpression)
402 QRegularExpression toRegularExpression() const;
403#endif // QT_CONFIG(regularexpression)
404#if QT_CONFIG(easingcurve)
405 QEasingCurve toEasingCurve() const;
406#endif
407 QUuid toUuid() const;
408#ifndef QT_BOOTSTRAPPED
409 QUrl toUrl() const;
410 QJsonValue toJsonValue() const;
411 QJsonObject toJsonObject() const;
412 QJsonArray toJsonArray() const;
413 QJsonDocument toJsonDocument() const;
414#endif // QT_BOOTSTRAPPED
415#if QT_CONFIG(itemmodel)
416 QModelIndex toModelIndex() const;
417 QPersistentModelIndex toPersistentModelIndex() const;
418#endif
419
420#ifndef QT_NO_DATASTREAM
421 void load(QDataStream &ds);
422 void save(QDataStream &ds) const;
423#endif
424#if QT_DEPRECATED_SINCE(6, 0)
425 QT_WARNING_PUSH
426 QT_WARNING_DISABLE_DEPRECATED
427 QT_DEPRECATED_VERSION_X_6_0("Use the constructor taking a QMetaType instead.")
428 explicit QVariant(Type type)
429 : QVariant(QMetaType(int(type)))
430 {}
431 QT_DEPRECATED_VERSION_X_6_0("Use typeId() or metaType().")
432 Type type() const
433 {
434 int type = d.type().id();
435 return type >= QMetaType::User ? UserType : static_cast<Type>(type);
436 }
437 QT_DEPRECATED_VERSION_6_0
438 static const char *typeToName(int typeId)
439 { return QMetaType(typeId).name(); }
440 QT_DEPRECATED_VERSION_6_0
441 static Type nameToType(const char *name)
442 {
443 int metaType = QMetaType::fromName(name).id();
444 return metaType <= int(UserType) ? QVariant::Type(metaType) : UserType;
445 }
446 QT_WARNING_POP
447#endif
448
449 void *data();
450 const void *constData() const
451 { return d.storage(); }
452 inline const void *data() const { return constData(); }
453
454private:
455 template <typename T>
456 void verifySuitableForEmplace()
457 {
458 static_assert(!std::is_reference_v<T>,
459 "QVariant does not support reference types");
460 static_assert(!std::is_const_v<T>,
461 "QVariant does not support const types");
462 static_assert(std::is_copy_constructible_v<T>,
463 "QVariant requires that the type is copyable");
464 static_assert(std::is_destructible_v<T>,
465 "QVariant requires that the type is destructible");
466 }
467
468 template <typename T, typename... Args>
469 T &emplaceImpl(Args&&... args)
470 {
471 verifySuitableForEmplace<T>();
472 auto data = static_cast<T *>(prepareForEmplace(type: QMetaType::fromType<T>()));
473 return *q20::construct_at(data, std::forward<Args>(args)...);
474 }
475
476public:
477 template <typename T, typename... Args,
478 if_constructible<T, Args...> = true>
479 T &emplace(Args&&... args)
480 {
481 return emplaceImpl<T>(std::forward<Args>(args)...);
482 }
483
484 template <typename T, typename U, typename... Args,
485 if_constructible<T, std::initializer_list<U> &, Args...> = true>
486 T &emplace(std::initializer_list<U> list, Args&&... args)
487 {
488 return emplaceImpl<T>(list, std::forward<Args>(args)...);
489 }
490
491 template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>>
492 void setValue(T &&avalue)
493 {
494 using VT = std::decay_t<T>;
495 QMetaType metaType = QMetaType::fromType<VT>();
496 // If possible we reuse the current QVariant private.
497 if (isDetached() && d.type() == metaType) {
498 *reinterpret_cast<VT *>(const_cast<void *>(constData())) = std::forward<T>(avalue);
499 d.is_null = false;
500 } else {
501 *this = QVariant::fromValue<VT>(std::forward<T>(avalue));
502 }
503 }
504
505 void setValue(const QVariant &avalue)
506 {
507 *this = avalue;
508 }
509
510 void setValue(QVariant &&avalue)
511 {
512 *this = std::move(avalue);
513 }
514
515 template<typename T>
516 inline T value() const &
517 { return qvariant_cast<T>(*this); }
518
519 template<typename T>
520 inline T view()
521 {
522 T t{};
523 QMetaType::view(fromType: metaType(), from: data(), toType: QMetaType::fromType<T>(), to: &t);
524 return t;
525 }
526
527 template<typename T>
528 inline T value() &&
529 { return qvariant_cast<T>(std::move(*this)); }
530
531 template<typename T, if_rvalue<T> = true>
532#ifndef Q_QDOC
533 /* needs is_copy_constructible for variants semantics, is_move_constructible so that moveConstruct works
534 (but copy_constructible implies move_constructble, so don't bother checking)
535 */
536 static inline auto fromValue(T &&value)
537 noexcept(std::is_nothrow_copy_constructible_v<T> && Private::CanUseInternalSpace<T>)
538 -> std::enable_if_t<std::conjunction_v<std::is_copy_constructible<T>,
539 std::is_destructible<T>>, QVariant>
540#else
541 static inline QVariant fromValue(T &&value)
542#endif
543 {
544 // handle special cases
545 using Type = std::remove_cv_t<T>;
546 if constexpr (std::is_null_pointer_v<Type>)
547 return QVariant::fromMetaType(type: QMetaType::fromType<std::nullptr_t>());
548 else if constexpr (std::is_same_v<Type, QVariant>)
549 return std::forward<T>(value);
550 else if constexpr (std::is_same_v<Type, std::monostate>)
551 return QVariant();
552 QMetaType mt = QMetaType::fromType<Type>();
553 mt.registerType(); // we want the type stored in QVariant to always be registered
554 // T is a forwarding reference, so if T satifies the enable-ifery,
555 // we get this overload even if T is an lvalue reference and thus must check here
556 // Moreover, we only try to move if the type is actually moveable and not if T is const
557 // as in const int i; QVariant::fromValue(std::move(i));
558 if constexpr (std::conjunction_v<std::is_move_constructible<Type>, std::negation<std::is_const<T>>>)
559 return moveConstruct(type: QMetaType::fromType<Type>(), data: std::addressof(value));
560 else
561 return copyConstruct(type: mt, data: std::addressof(value));
562 }
563
564 template<typename T>
565#ifndef Q_QDOC
566 static inline auto fromValue(const T &value)
567 noexcept(std::is_nothrow_copy_constructible_v<T> && Private::CanUseInternalSpace<T>)
568 -> std::enable_if_t<std::is_copy_constructible_v<T> && std::is_destructible_v<T>, QVariant>
569#else
570 static inline QVariant fromValue(const T &value)
571#endif
572 {
573 if constexpr (std::is_null_pointer_v<T>)
574 return QVariant(QMetaType::fromType<std::nullptr_t>());
575 else if constexpr (std::is_same_v<T, QVariant>)
576 return value;
577 else if constexpr (std::is_same_v<T, std::monostate>)
578 return QVariant();
579 return QVariant(QMetaType::fromType<T>(), std::addressof(value));
580 }
581
582 template<typename... Types>
583 static inline QVariant fromStdVariant(const std::variant<Types...> &value)
584 {
585 return fromStdVariantImpl(value);
586 }
587
588 template<typename... Types>
589 static QVariant fromStdVariant(std::variant<Types...> &&value)
590 {
591 return fromStdVariantImpl(std::move(value));
592 }
593
594 static QVariant fromMetaType(QMetaType type, const void *copy = nullptr);
595
596 template<typename T>
597 bool canConvert() const
598 { return canConvert(QMetaType::fromType<T>()); }
599
600 template<typename T>
601 bool canView() const
602 { return canView(QMetaType::fromType<T>()); }
603
604 static QPartialOrdering compare(const QVariant &lhs, const QVariant &rhs);
605
606private:
607 template <typename StdVariant>
608 static QVariant fromStdVariantImpl(StdVariant &&v)
609 {
610 if (Q_UNLIKELY(v.valueless_by_exception()))
611 return QVariant();
612 auto visitor = [](auto &&arg) {
613 return QVariant::fromValue(q23::forward_like<StdVariant>(arg));
614 };
615 return std::visit(visitor, std::forward<StdVariant>(v));
616 }
617
618 friend inline bool operator==(const QVariant &a, const QVariant &b)
619 { return a.equals(other: b); }
620 friend inline bool operator!=(const QVariant &a, const QVariant &b)
621 { return !a.equals(other: b); }
622#ifndef QT_NO_DEBUG_STREAM
623 template <typename T>
624 friend auto operator<<(const QDebug &debug, const T &variant) -> std::enable_if_t<std::is_same_v<T, QVariant>, QDebug> {
625 return variant.qdebugHelper(debug);
626 }
627 QDebug qdebugHelper(QDebug) const;
628#endif
629
630 template <typename T>
631 friend T *get_if(QVariant *v) noexcept
632 {
633 // data() will detach from is_null, returning non-nullptr
634 if (!v || v->d.type() != QMetaType::fromType<T>())
635 return nullptr;
636 return static_cast<T*>(v->data());
637 }
638 template <typename T>
639 friend const T *get_if(const QVariant *v) noexcept
640 {
641 // (const) data() will not detach from is_null, return nullptr
642 if (!v || v->d.is_null || v->d.type() != QMetaType::fromType<T>())
643 return nullptr;
644 return static_cast<const T*>(v->data());
645 }
646
647#define Q_MK_GET(cvref) \
648 template <typename T> \
649 friend T cvref get(QVariant cvref v) \
650 { \
651 if constexpr (std::is_const_v<T cvref>) \
652 Q_ASSERT(!v.d.is_null); \
653 Q_ASSERT(v.d.type() == QMetaType::fromType<q20::remove_cvref_t<T>>()); \
654 return static_cast<T cvref>(*get_if<T>(&v)); \
655 } \
656 /* end */
657 Q_MK_GET(&)
658 Q_MK_GET(const &)
659 Q_MK_GET(&&)
660 Q_MK_GET(const &&)
661#undef Q_MK_GET
662
663 static QVariant moveConstruct(QMetaType type, void *data);
664 static QVariant copyConstruct(QMetaType type, const void *data);
665
666 template<typename T>
667 friend inline T qvariant_cast(const QVariant &);
668 template<typename T>
669 friend inline T qvariant_cast(QVariant &&);
670
671protected:
672 Private d;
673 void create(int type, const void *copy);
674 void create(QMetaType type, const void *copy);
675 bool equals(const QVariant &other) const;
676 bool convert(int type, void *ptr) const;
677 bool view(int type, void *ptr);
678
679private:
680 // force compile error, prevent QVariant(bool) to be called
681 inline QVariant(void *) = delete;
682 // QVariant::Type is marked as \obsolete, but we don't want to
683 // provide a constructor from its intended replacement,
684 // QMetaType::Type, instead, because the idea behind these
685 // constructors is flawed in the first place. But we also don't
686 // want QVariant(QMetaType::String) to compile and falsely be an
687 // int variant, so delete this constructor:
688 QVariant(QMetaType::Type) = delete;
689
690 // used to setup the QVariant internals for the "real" inplace ctor
691 QVariant(std::in_place_t, QMetaType type);
692 // helper for emplace
693 void *prepareForEmplace(QMetaType type);
694
695 // These constructors don't create QVariants of the type associated
696 // with the enum, as expected, but they would create a QVariant of
697 // type int with the value of the enum value.
698 // Use QVariant v = QColor(Qt::red) instead of QVariant v = Qt::red for
699 // example.
700 QVariant(Qt::GlobalColor) = delete;
701 QVariant(Qt::BrushStyle) = delete;
702 QVariant(Qt::PenStyle) = delete;
703 QVariant(Qt::CursorShape) = delete;
704#ifdef QT_NO_CAST_FROM_ASCII
705 // force compile error when implicit conversion is not wanted
706 inline QVariant(const char *) = delete;
707#endif
708public:
709 typedef Private DataPtr;
710 inline DataPtr &data_ptr() { return d; }
711 inline const DataPtr &data_ptr() const { return d; }
712};
713
714inline bool QVariant::isValid() const
715{
716 return d.type().isValid();
717}
718
719#ifndef QT_NO_DATASTREAM
720Q_CORE_EXPORT QDataStream &operator>>(QDataStream &s, QVariant &p);
721Q_CORE_EXPORT QDataStream &operator<<(QDataStream &s, const QVariant &p);
722
723#if QT_DEPRECATED_SINCE(6, 0)
724QT_WARNING_PUSH
725QT_WARNING_DISABLE_DEPRECATED
726QT_DEPRECATED_VERSION_6_0
727inline QDataStream &operator>>(QDataStream &s, QVariant::Type &p)
728{
729 quint32 u;
730 s >> u;
731 p = static_cast<QVariant::Type>(u);
732 return s;
733}
734QT_DEPRECATED_VERSION_6_0
735inline QDataStream &operator<<(QDataStream &s, const QVariant::Type p)
736{
737 s << static_cast<quint32>(p);
738 return s;
739}
740QT_WARNING_POP
741#endif
742
743#endif
744
745inline bool QVariant::isDetached() const
746{ return !d.is_shared || d.data.shared->ref.loadRelaxed() == 1; }
747
748inline void swap(QVariant &value1, QVariant &value2) noexcept
749{ value1.swap(other&: value2); }
750
751#ifndef QT_MOC
752
753template<typename T> inline T qvariant_cast(const QVariant &v)
754{
755 QMetaType targetType = QMetaType::fromType<T>();
756 if (v.d.type() == targetType)
757 return v.d.get<T>();
758 if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
759 using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
760 QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
761 if (v.d.type() == nonConstTargetType)
762 return v.d.get<nonConstT>();
763 }
764
765 T t{};
766 QMetaType::convert(v.metaType(), v.constData(), targetType, &t);
767 return t;
768}
769
770template<typename T> inline T qvariant_cast(QVariant &&v)
771{
772 QMetaType targetType = QMetaType::fromType<T>();
773 if (v.d.type() == targetType) {
774 if constexpr (QVariant::Private::CanUseInternalSpace<T>) {
775 return std::move(*reinterpret_cast<T *>(v.d.data.data));
776 } else {
777 if (v.d.data.shared->ref.loadRelaxed() == 1)
778 return std::move(*reinterpret_cast<T *>(v.d.data.shared->data()));
779 else
780 return v.d.get<T>();
781 }
782 }
783 if constexpr (std::is_same_v<T, QVariant>) {
784 // if the metatype doesn't match, but we want a QVariant, just return the current variant
785 return v;
786 } if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
787 // moving a pointer is pointless, just do the same as the const & overload
788 using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
789 QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
790 if (v.d.type() == nonConstTargetType)
791 return v.d.get<nonConstT>();
792 }
793
794 T t{};
795 QMetaType::convert(v.metaType(), v.constData(), targetType, &t);
796 return t;
797}
798
799template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v)
800{
801 if (v.metaType().id() == QMetaType::QVariant)
802 return *reinterpret_cast<const QVariant *>(v.constData());
803 return v;
804}
805
806#endif
807
808#ifndef QT_NO_DEBUG_STREAM
809#if QT_DEPRECATED_SINCE(6, 0)
810QT_WARNING_PUSH
811QT_WARNING_DISABLE_DEPRECATED
812QT_DEPRECATED_VERSION_6_0
813Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant::Type);
814QT_WARNING_POP
815#endif
816#endif
817
818namespace QtPrivate {
819class Q_CORE_EXPORT QVariantTypeCoercer
820{
821public:
822 // ### Qt7: Pass QMetaType as value rather than const ref.
823 const void *convert(const QVariant &value, const QMetaType &type);
824 const void *coerce(const QVariant &value, const QMetaType &type);
825
826private:
827 QVariant converted;
828};
829}
830
831template<typename Pointer>
832class QVariantRef
833{
834private:
835 const Pointer *m_pointer = nullptr;
836
837public:
838 explicit QVariantRef(const Pointer *reference) : m_pointer(reference) {}
839 QVariantRef(const QVariantRef &) = default;
840 QVariantRef(QVariantRef &&) = default;
841 ~QVariantRef() = default;
842
843 operator QVariant() const;
844 QVariantRef &operator=(const QVariant &value);
845 QVariantRef &operator=(const QVariantRef &value) { return operator=(QVariant(value)); }
846 QVariantRef &operator=(QVariantRef &&value) { return operator=(QVariant(value)); }
847
848 friend void swap(QVariantRef a, QVariantRef b)
849 {
850 QVariant tmp = a;
851 a = b;
852 b = std::move(tmp);
853 }
854};
855
856class Q_CORE_EXPORT QVariantConstPointer
857{
858private:
859 QVariant m_variant;
860
861public:
862 explicit QVariantConstPointer(QVariant variant);
863
864 QVariant operator*() const;
865 const QVariant *operator->() const;
866};
867
868template<typename Pointer>
869class QVariantPointer
870{
871private:
872 const Pointer *m_pointer = nullptr;
873
874public:
875 explicit QVariantPointer(const Pointer *pointer) : m_pointer(pointer) {}
876 QVariantRef<Pointer> operator*() const { return QVariantRef<Pointer>(m_pointer); }
877 Pointer operator->() const { return *m_pointer; }
878};
879
880QT_END_NAMESPACE
881
882#endif // QVARIANT_H
883