/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QVARIANT_H #define QVARIANT_H #include #include #include #include #include #include #include #include #include #ifndef QT_BOOTSTRAPPED #include #endif #include #if __has_include() && __cplusplus >= 201703L #include #elif defined(Q_CLANG_QDOC) namespace std { template struct variant; } #endif QT_BEGIN_NAMESPACE class QBitArray; class QDataStream; class QDate; class QDateTime; #if QT_CONFIG(easingcurve) class QEasingCurve; #endif class QLine; class QLineF; class QLocale; class QTransform; class QStringList; class QTime; class QPoint; class QPointF; class QSize; class QSizeF; class QRect; class QRectF; #if QT_CONFIG(regularexpression) class QRegularExpression; #endif // QT_CONFIG(regularexpression) class QTextFormat; class QTextLength; class QUrl; class QVariant; class QVariantComparisonHelper; template inline T qvariant_cast(const QVariant &); namespace QtPrivate { template struct ObjectInvoker { static ReturnType invoke(Argument a) { return Derived::object(a); } }; template struct MetaTypeInvoker { static ReturnType invoke(Argument a) { return Derived::metaType(a); } }; template ::Value> struct TreatAsQObjectBeforeMetaType : ObjectInvoker { }; template struct TreatAsQObjectBeforeMetaType : MetaTypeInvoker { }; template struct QVariantValueHelper; } class Q_CORE_EXPORT QVariant { public: enum Type { Invalid = QMetaType::UnknownType, Bool = QMetaType::Bool, Int = QMetaType::Int, UInt = QMetaType::UInt, LongLong = QMetaType::LongLong, ULongLong = QMetaType::ULongLong, Double = QMetaType::Double, Char = QMetaType::QChar, Map = QMetaType::QVariantMap, List = QMetaType::QVariantList, String = QMetaType::QString, StringList = QMetaType::QStringList, ByteArray = QMetaType::QByteArray, BitArray = QMetaType::QBitArray, Date = QMetaType::QDate, Time = QMetaType::QTime, DateTime = QMetaType::QDateTime, Url = QMetaType::QUrl, Locale = QMetaType::QLocale, Rect = QMetaType::QRect, RectF = QMetaType::QRectF, Size = QMetaType::QSize, SizeF = QMetaType::QSizeF, Line = QMetaType::QLine, LineF = QMetaType::QLineF, Point = QMetaType::QPoint, PointF = QMetaType::QPointF, #if QT_CONFIG(regularexpression) RegularExpression = QMetaType::QRegularExpression, #endif Hash = QMetaType::QVariantHash, #if QT_CONFIG(easingcurve) EasingCurve = QMetaType::QEasingCurve, #endif Uuid = QMetaType::QUuid, #if QT_CONFIG(itemmodel) ModelIndex = QMetaType::QModelIndex, PersistentModelIndex = QMetaType::QPersistentModelIndex, #endif LastCoreType = QMetaType::LastCoreType, Font = QMetaType::QFont, Pixmap = QMetaType::QPixmap, Brush = QMetaType::QBrush, Color = QMetaType::QColor, Palette = QMetaType::QPalette, Image = QMetaType::QImage, Polygon = QMetaType::QPolygon, Region = QMetaType::QRegion, Bitmap = QMetaType::QBitmap, Cursor = QMetaType::QCursor, #if QT_CONFIG(shortcut) KeySequence = QMetaType::QKeySequence, #endif Pen = QMetaType::QPen, TextLength = QMetaType::QTextLength, TextFormat = QMetaType::QTextFormat, Transform = QMetaType::QTransform, Matrix4x4 = QMetaType::QMatrix4x4, Vector2D = QMetaType::QVector2D, Vector3D = QMetaType::QVector3D, Vector4D = QMetaType::QVector4D, Quaternion = QMetaType::QQuaternion, PolygonF = QMetaType::QPolygonF, Icon = QMetaType::QIcon, LastGuiType = QMetaType::LastGuiType, SizePolicy = QMetaType::QSizePolicy, UserType = QMetaType::User, LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type }; QVariant() noexcept : d() {} ~QVariant(); QVariant(Type type); QVariant(int typeId, const void *copy, uint flags = 0); // ### Qt6 TODO deprecate explicit QVariant(QMetaType type, const void *copy); QVariant(const QVariant &other); #ifndef QT_NO_DATASTREAM QVariant(QDataStream &s); #endif QVariant(int i); QVariant(uint ui); QVariant(qlonglong ll); QVariant(qulonglong ull); QVariant(bool b); QVariant(double d); QVariant(float f); #ifndef QT_NO_CAST_FROM_ASCII QT_ASCII_CAST_WARN QVariant(const char *str) : QVariant(QString::fromUtf8(str)) {} #endif QVariant(const QByteArray &bytearray); QVariant(const QBitArray &bitarray); QVariant(const QString &string); QVariant(QLatin1String string); QVariant(const QStringList &stringlist); QVariant(QChar qchar); QVariant(QDate date); QVariant(QTime time); QVariant(const QDateTime &datetime); QVariant(const QList &list); QVariant(const QMap &map); QVariant(const QHash &hash); #ifndef QT_NO_GEOM_VARIANT QVariant(const QSize &size); QVariant(const QSizeF &size); QVariant(const QPoint &pt); QVariant(const QPointF &pt); QVariant(const QLine &line); QVariant(const QLineF &line); QVariant(const QRect &rect); QVariant(const QRectF &rect); #endif QVariant(const QLocale &locale); #if QT_CONFIG(regularexpression) QVariant(const QRegularExpression &re); #endif // QT_CONFIG(regularexpression) #if QT_CONFIG(easingcurve) QVariant(const QEasingCurve &easing); #endif QVariant(const QUuid &uuid); #ifndef QT_BOOTSTRAPPED QVariant(const QUrl &url); QVariant(const QJsonValue &jsonValue); QVariant(const QJsonObject &jsonObject); QVariant(const QJsonArray &jsonArray); QVariant(const QJsonDocument &jsonDocument); #endif // QT_BOOTSTRAPPED #if QT_CONFIG(itemmodel) QVariant(const QModelIndex &modelIndex); QVariant(const QPersistentModelIndex &modelIndex); #endif QVariant& operator=(const QVariant &other); inline QVariant(QVariant &&other) noexcept : d(other.d) { other.d = Private(); } inline QVariant &operator=(QVariant &&other) noexcept { QVariant moved(std::move(other)); swap(moved); return *this; } inline void swap(QVariant &other) noexcept { qSwap(d, other.d); } Type type() const; int userType() const; const char *typeName() const; QMetaType metaType() const; bool canConvert(int targetTypeId) const; bool convert(int targetTypeId); inline bool isValid() const; bool isNull() const; void clear(); void detach(); inline bool isDetached() const; int toInt(bool *ok = nullptr) const; uint toUInt(bool *ok = nullptr) const; qlonglong toLongLong(bool *ok = nullptr) const; qulonglong toULongLong(bool *ok = nullptr) const; bool toBool() const; double toDouble(bool *ok = nullptr) const; float toFloat(bool *ok = nullptr) const; qreal toReal(bool *ok = nullptr) const; QByteArray toByteArray() const; QBitArray toBitArray() const; QString toString() const; QStringList toStringList() const; QChar toChar() const; QDate toDate() const; QTime toTime() const; QDateTime toDateTime() const; QList toList() const; QMap toMap() const; QHash toHash() const; #ifndef QT_NO_GEOM_VARIANT QPoint toPoint() const; QPointF toPointF() const; QRect toRect() const; QSize toSize() const; QSizeF toSizeF() const; QLine toLine() const; QLineF toLineF() const; QRectF toRectF() const; #endif QLocale toLocale() const; #if QT_CONFIG(regularexpression) QRegularExpression toRegularExpression() const; #endif // QT_CONFIG(regularexpression) #if QT_CONFIG(easingcurve) QEasingCurve toEasingCurve() const; #endif QUuid toUuid() const; #ifndef QT_BOOTSTRAPPED QUrl toUrl() const; QJsonValue toJsonValue() const; QJsonObject toJsonObject() const; QJsonArray toJsonArray() const; QJsonDocument toJsonDocument() const; #endif // QT_BOOTSTRAPPED #if QT_CONFIG(itemmodel) QModelIndex toModelIndex() const; QPersistentModelIndex toPersistentModelIndex() const; #endif #ifndef QT_NO_DATASTREAM void load(QDataStream &ds); void save(QDataStream &ds) const; #endif static const char *typeToName(int typeId); static Type nameToType(const char *name); void *data(); const void *constData() const; inline const void *data() const { return constData(); } template inline void setValue(const T &value); template inline T value() const { return qvariant_cast(*this); } template static inline QVariant fromValue(const T &value) { return QVariant(QMetaType::fromType(), std::addressof(value)); } #if (__has_include() && __cplusplus >= 201703L) || defined(Q_CLANG_QDOC) template static inline QVariant fromStdVariant(const std::variant &value) { if (value.valueless_by_exception()) return QVariant(); return std::visit([](const auto &arg) { return fromValue(arg); }, value); } #endif template bool canConvert() const { return canConvert(qMetaTypeId()); } public: struct PrivateShared { inline PrivateShared(void *v) : ptr(v), ref(1) { } void *ptr; QAtomicInt ref; }; struct Private { Private() noexcept : packedType(0), is_shared(false), is_null(true) {} explicit Private(const QMetaType &type) noexcept : is_shared(false), is_null(false) { if (type.d_ptr) type.d_ptr->ref.ref(); quintptr mt = quintptr(type.d_ptr); Q_ASSERT((mt & 0x3) == 0); packedType = mt >> 2; } explicit Private(int type) noexcept : Private(QMetaType(type)) {} Private(const Private &other) : Private(other.type()) { data = other.data; is_shared = other.is_shared; is_null = other.is_null; } Private &operator=(const Private &other) { if (&other != this) { this->~Private(); new (this) Private(other); } return *this; } Q_CORE_EXPORT ~Private(); union Data { void *threeptr[3] = { nullptr, nullptr, nullptr }; char c; uchar uc; short s; signed char sc; ushort us; int i; uint u; long l; ulong ul; bool b; double d; float f; qreal real; qlonglong ll; qulonglong ull; QObject *o; void *ptr; PrivateShared *shared; } data; quintptr packedType : sizeof(QMetaType) * 8 - 2; quintptr is_shared : 1; quintptr is_null : 1; inline QMetaType type() const { return QMetaType(reinterpret_cast(packedType << 2)); } }; public: typedef bool (*f_null)(const Private *); typedef bool (*f_compare)(const Private *, const Private *); typedef bool (*f_convert)(const QVariant::Private *d, int t, void *, bool *); typedef void (*f_debugStream)(QDebug, const QVariant &); struct Handler { f_null isNull; f_compare compare; f_convert convert; f_debugStream debugStream; }; inline bool operator==(const QVariant &v) const { return cmp(v); } inline bool operator!=(const QVariant &v) const { return !cmp(v); } protected: friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &); #ifndef QT_NO_DEBUG_STREAM friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &); #endif // ### Qt6: FIXME: Remove the special Q_CC_MSVC handling, it was introduced to maintain BC for QTBUG-41810 . #if !defined(Q_NO_TEMPLATE_FRIENDS) && !defined(Q_CC_MSVC) template friend inline T qvariant_cast(const QVariant &); template friend struct QtPrivate::QVariantValueHelper; protected: #else public: #endif Private d; void create(int type, const void *copy); bool cmp(const QVariant &other) const; bool convert(const int t, void *ptr) const; // ### Qt6: drop const private: // force compile error, prevent QVariant(bool) to be called inline QVariant(void *) = delete; // QVariant::Type is marked as \obsolete, but we don't want to // provide a constructor from its intended replacement, // QMetaType::Type, instead, because the idea behind these // constructors is flawed in the first place. But we also don't // want QVariant(QMetaType::String) to compile and falsely be an // int variant, so delete this constructor: QVariant(QMetaType::Type) = delete; // These constructors don't create QVariants of the type associcated // with the enum, as expected, but they would create a QVariant of // type int with the value of the enum value. // Use QVariant v = QColor(Qt::red) instead of QVariant v = Qt::red for // example. QVariant(Qt::GlobalColor) = delete; QVariant(Qt::BrushStyle) = delete; QVariant(Qt::PenStyle) = delete; QVariant(Qt::CursorShape) = delete; #ifdef QT_NO_CAST_FROM_ASCII // force compile error when implicit conversion is not wanted inline QVariant(const char *) = delete; #endif public: typedef Private DataPtr; inline DataPtr &data_ptr() { return d; } inline const DataPtr &data_ptr() const { return d; } }; template<> inline QVariant QVariant::fromValue(const QVariant &value) { return value; } #if __has_include() && __cplusplus >= 201703L template<> inline QVariant QVariant::fromValue(const std::monostate &) { return QVariant(); } #endif inline bool QVariant::isValid() const { return d.type().isValid(); } template inline void QVariant::setValue(const T &avalue) { QMetaType metaType = QMetaType::fromType(); // If possible we reuse the current QVariant private. if (isDetached() && d.type() == metaType) { *reinterpret_cast(data()) = avalue; } else { *this = QVariant::fromValue(avalue); } } template<> inline void QVariant::setValue(const QVariant &avalue) { *this = avalue; } #ifndef QT_NO_DATASTREAM Q_CORE_EXPORT QDataStream& operator>> (QDataStream& s, QVariant& p); Q_CORE_EXPORT QDataStream& operator<< (QDataStream& s, const QVariant& p); Q_CORE_EXPORT QDataStream& operator>> (QDataStream& s, QVariant::Type& p); Q_CORE_EXPORT QDataStream& operator<< (QDataStream& s, const QVariant::Type p); #endif inline bool QVariant::isDetached() const { return !d.is_shared || d.data.shared->ref.loadRelaxed() == 1; } #ifdef Q_QDOC inline bool operator==(const QVariant &v1, const QVariant &v2); inline bool operator!=(const QVariant &v1, const QVariant &v2); #else /* Helper class to add one more level of indirection to prevent implicit casts. */ class QVariantComparisonHelper { public: inline QVariantComparisonHelper(const QVariant &var) : v(&var) {} private: friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &); const QVariant *v; }; inline bool operator==(const QVariant &v1, const QVariantComparisonHelper &v2) { return v1.cmp(*v2.v); } inline bool operator!=(const QVariant &v1, const QVariantComparisonHelper &v2) { return !operator==(v1, v2); } #endif Q_DECLARE_SHARED(QVariant) class Q_CORE_EXPORT QSequentialIterable { QtMetaTypePrivate::QSequentialIterableImpl m_impl; public: struct Q_CORE_EXPORT const_iterator { private: QtMetaTypePrivate::QSequentialIterableImpl m_impl; QAtomicInt *ref; friend class QSequentialIterable; explicit const_iterator(const QSequentialIterable &iter, QAtomicInt *ref_); explicit const_iterator(const QtMetaTypePrivate::QSequentialIterableImpl &impl, QAtomicInt *ref_); void begin(); void end(); public: ~const_iterator(); const_iterator(const const_iterator &other); const_iterator& operator=(const const_iterator &other); const QVariant operator*() const; bool operator==(const const_iterator &o) const; bool operator!=(const const_iterator &o) const; const_iterator &operator++(); const_iterator operator++(int); const_iterator &operator--(); const_iterator operator--(int); const_iterator &operator+=(int j); const_iterator &operator-=(int j); const_iterator operator+(int j) const; const_iterator operator-(int j) const; friend inline const_iterator operator+(int j, const_iterator k) { return k + j; } }; friend struct const_iterator; explicit QSequentialIterable(const QtMetaTypePrivate::QSequentialIterableImpl &impl); const_iterator begin() const; const_iterator end() const; QVariant at(int idx) const; int size() const; bool canReverseIterate() const; }; class Q_CORE_EXPORT QAssociativeIterable { QtMetaTypePrivate::QAssociativeIterableImpl m_impl; public: struct Q_CORE_EXPORT const_iterator { private: QtMetaTypePrivate::QAssociativeIterableImpl m_impl; QAtomicInt *ref; friend class QAssociativeIterable; explicit const_iterator(const QAssociativeIterable &iter, QAtomicInt *ref_); explicit const_iterator(const QtMetaTypePrivate::QAssociativeIterableImpl &impl, QAtomicInt *ref_); void begin(); void end(); void find(const QVariant &key); public: ~const_iterator(); const_iterator(const const_iterator &other); const_iterator& operator=(const const_iterator &other); const QVariant key() const; const QVariant value() const; const QVariant operator*() const; bool operator==(const const_iterator &o) const; bool operator!=(const const_iterator &o) const; const_iterator &operator++(); const_iterator operator++(int); const_iterator &operator--(); const_iterator operator--(int); const_iterator &operator+=(int j); const_iterator &operator-=(int j); const_iterator operator+(int j) const; const_iterator operator-(int j) const; friend inline const_iterator operator+(int j, const_iterator k) { return k + j; } }; friend struct const_iterator; explicit QAssociativeIterable(const QtMetaTypePrivate::QAssociativeIterableImpl &impl); const_iterator begin() const; const_iterator end() const; const_iterator find(const QVariant &key) const; QVariant value(const QVariant &key) const; int size() const; }; #ifndef QT_MOC namespace QtPrivate { template struct QVariantValueHelper : TreatAsQObjectBeforeMetaType, T, const QVariant &, T> { static T metaType(const QVariant &v) { const int vid = qMetaTypeId(); if (vid == v.userType()) return *reinterpret_cast(v.constData()); T t; if (v.convert(vid, &t)) return t; return T(); } #ifndef QT_NO_QOBJECT static T object(const QVariant &v) { return qobject_cast(QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject ? v.d.data.o : QVariantValueHelper::metaType(v)); } #endif }; template struct QVariantValueHelperInterface : QVariantValueHelper { }; template<> struct QVariantValueHelperInterface { static QSequentialIterable invoke(const QVariant &v) { const int typeId = v.userType(); if (typeId == qMetaTypeId()) { return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); } if (typeId == qMetaTypeId()) { return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); } #ifndef QT_BOOTSTRAPPED if (typeId == qMetaTypeId()) { return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); } #endif return QSequentialIterable(qvariant_cast(v)); } }; template<> struct QVariantValueHelperInterface { static QAssociativeIterable invoke(const QVariant &v) { const int typeId = v.userType(); if (typeId == qMetaTypeId()) { return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast(v.constData()))); } if (typeId == qMetaTypeId()) { return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast(v.constData()))); } return QAssociativeIterable(qvariant_cast(v)); } }; template<> struct QVariantValueHelperInterface { static QVariantList invoke(const QVariant &v) { const int typeId = v.userType(); if (typeId == qMetaTypeId() || typeId == qMetaTypeId() || (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()))) { QSequentialIterable iter = QVariantValueHelperInterface::invoke(v); QVariantList l; l.reserve(iter.size()); for (QSequentialIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) l << *it; return l; } return QVariantValueHelper::invoke(v); } }; template<> struct QVariantValueHelperInterface { static QVariantHash invoke(const QVariant &v) { const int typeId = v.userType(); if (typeId == qMetaTypeId() || ((QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId())) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()))) { QAssociativeIterable iter = QVariantValueHelperInterface::invoke(v); QVariantHash l; l.reserve(iter.size()); for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) l.insert(it.key().toString(), it.value()); return l; } return QVariantValueHelper::invoke(v); } }; template<> struct QVariantValueHelperInterface { static QVariantMap invoke(const QVariant &v) { const int typeId = v.userType(); if (typeId == qMetaTypeId() || (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()))) { QAssociativeIterable iter = QVariantValueHelperInterface::invoke(v); QVariantMap l; for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) static_cast &>(l).insert(it.key().toString(), it.value()); return l; } return QVariantValueHelper::invoke(v); } }; template<> struct QVariantValueHelperInterface > { static QPair invoke(const QVariant &v) { const int typeId = v.userType(); if (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId()) && !(typeId == qMetaTypeId >())) { QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value(); const QtMetaTypePrivate::VariantData d1 = pi.first(); QVariant v1(d1.metaTypeId, d1.data, d1.flags); if (d1.metaTypeId == qMetaTypeId()) v1 = *reinterpret_cast(d1.data); const QtMetaTypePrivate::VariantData d2 = pi.second(); QVariant v2(d2.metaTypeId, d2.data, d2.flags); if (d2.metaTypeId == qMetaTypeId()) v2 = *reinterpret_cast(d2.data); return QPair(v1, v2); } return QVariantValueHelper >::invoke(v); } }; } template inline T qvariant_cast(const QVariant &v) { return QtPrivate::QVariantValueHelperInterface::invoke(v); } template<> inline QVariant qvariant_cast(const QVariant &v) { if (v.userType() == QMetaType::QVariant) return *reinterpret_cast(v.constData()); return v; } #endif #ifndef QT_NO_DEBUG_STREAM Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &); Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant::Type); #endif QT_END_NAMESPACE #endif // QVARIANT_H