diff options
Diffstat (limited to 'src/corelib/kernel/qvariant.h')
-rw-r--r-- | src/corelib/kernel/qvariant.h | 1066 |
1 files changed, 543 insertions, 523 deletions
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 87fb16485f..d567bcbb7c 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -1,137 +1,147 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QVARIANT_H #define QVARIANT_H #include <QtCore/qatomic.h> -#include <QtCore/qbytearray.h> -#include <QtCore/qlist.h> +#include <QtCore/qcompare.h> +#include <QtCore/qcontainerfwd.h> #include <QtCore/qmetatype.h> -#include <QtCore/qmap.h> -#include <QtCore/qhash.h> -#include <QtCore/qstring.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qobject.h> -#ifndef QT_BOOTSTRAPPED -#include <QtCore/qbytearraylist.h> +#ifndef QT_NO_DEBUG_STREAM +#include <QtCore/qdebug.h> #endif #include <memory> - -#if __has_include(<variant>) && __cplusplus >= 201703L +#include <QtCore/q20type_traits.h> +#include <QtCore/q23utility.h> #include <variant> -#elif defined(Q_CLANG_QDOC) -namespace std { template<typename...> struct variant; } + +#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1 +# include <QtCore/qlist.h> +# include <QtCore/qstringlist.h> +# include <QtCore/qbytearraylist.h> +# include <QtCore/qhash.h> +# include <QtCore/qmap.h> +# include <QtCore/qobject.h> #endif QT_BEGIN_NAMESPACE +QT_ENABLE_P0846_SEMANTICS_FOR(get_if) +QT_ENABLE_P0846_SEMANTICS_FOR(get) 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 QModelIndex; +class QPersistentModelIndex; class QPoint; class QPointF; -class QSize; -class QSizeF; class QRect; class QRectF; -#if QT_CONFIG(regularexpression) class QRegularExpression; -#endif // QT_CONFIG(regularexpression) +class QSize; +class QSizeF; class QTextFormat; class QTextLength; +class QTime; +class QTransform; class QUrl; class QVariant; -class QVariantComparisonHelper; template<typename T> inline T qvariant_cast(const QVariant &); namespace QtPrivate { +template<> constexpr inline bool qIsRelocatable<QVariant> = true; +} +class Q_CORE_EXPORT QVariant +{ + template <typename T, typename... Args> + using if_constructible = std::enable_if_t< + std::conjunction_v< + std::is_copy_constructible<q20::remove_cvref_t<T>>, + std::is_destructible<q20::remove_cvref_t<T>>, + std::is_constructible<q20::remove_cvref_t<T>, Args...> + >, + bool>; + + template <typename T> + using if_rvalue = std::enable_if_t<!std::is_reference_v<T>, bool>; + + struct CborValueStandIn { qint64 n; void *c; int t; }; +public: + struct PrivateShared + { + private: + inline PrivateShared() : ref(1) { } + public: + static int computeOffset(PrivateShared *ps, size_t align); + static size_t computeAllocationSize(size_t size, size_t align); + static PrivateShared *create(size_t size, size_t align); + static void free(PrivateShared *p); + + alignas(8) QAtomicInt ref; + int offset; + + const void *data() const { return reinterpret_cast<const uchar *>(this) + offset; } + void *data() { return reinterpret_cast<uchar *>(this) + offset; } + }; - template <typename Derived, typename Argument, typename ReturnType> - struct ObjectInvoker + struct Private { - static ReturnType invoke(Argument a) + static constexpr size_t MaxInternalSize = 3 * sizeof(void *); + template <size_t S> static constexpr bool FitsInInternalSize = S <= MaxInternalSize; + template<typename T> static constexpr bool CanUseInternalSpace = + (QTypeInfo<T>::isRelocatable && FitsInInternalSize<sizeof(T)> && alignof(T) <= alignof(double)); + static constexpr bool canUseInternalSpace(const QtPrivate::QMetaTypeInterface *type) { - return Derived::object(a); + Q_ASSERT(type); + return QMetaType::TypeFlags(type->flags) & QMetaType::RelocatableType && + size_t(type->size) <= MaxInternalSize && size_t(type->alignment) <= alignof(double); } - }; - template <typename Derived, typename Argument, typename ReturnType> - struct MetaTypeInvoker - { - static ReturnType invoke(Argument a) + union + { + uchar data[MaxInternalSize] = {}; + PrivateShared *shared; + double _forAlignment; // we want an 8byte alignment on 32bit systems as well + } data; + quintptr is_shared : 1; + quintptr is_null : 1; + quintptr packedType : sizeof(QMetaType) * 8 - 2; + + constexpr Private() noexcept : is_shared(false), is_null(true), packedType(0) {} + explicit Private(const QtPrivate::QMetaTypeInterface *iface) noexcept; + template <typename T> explicit Private(std::piecewise_construct_t, const T &t); + + const void *storage() const + { return is_shared ? data.shared->data() : &data.data; } + + // determine internal storage at compile time + template<typename T> const T &get() const + { return *static_cast<const T *>(CanUseInternalSpace<T> ? &data.data : data.shared->data()); } + + inline const QtPrivate::QMetaTypeInterface *typeInterface() const { - return Derived::metaType(a); + return reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(packedType << 2); } - }; - template <typename Derived, typename T, typename Argument, typename ReturnType, bool = IsPointerToTypeDerivedFromQObject<T>::Value> - struct TreatAsQObjectBeforeMetaType : ObjectInvoker<Derived, Argument, ReturnType> - { + inline QMetaType type() const + { + return QMetaType(typeInterface()); + } }; - template <typename Derived, typename T, typename Argument, typename ReturnType> - struct TreatAsQObjectBeforeMetaType<Derived, T, Argument, ReturnType, false> : MetaTypeInvoker<Derived, Argument, ReturnType> +#if QT_DEPRECATED_SINCE(6, 0) + enum QT_DEPRECATED_VERSION_X_6_0("Use QMetaType::Type instead.") Type { - }; - - template<typename T> struct QVariantValueHelper; -} - -class Q_CORE_EXPORT QVariant -{ - public: - enum Type { Invalid = QMetaType::UnknownType, Bool = QMetaType::Bool, Int = QMetaType::Int, @@ -204,44 +214,110 @@ class Q_CORE_EXPORT QVariant UserType = QMetaType::User, LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type }; - +#endif 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); + explicit QVariant(QMetaType type, const void *copy = nullptr); QVariant(const QVariant &other); -#ifndef QT_NO_DATASTREAM - QVariant(QDataStream &s); +private: + template <typename T, typename ...Args> + using is_noexcept_constructible = std::conjunction< + std::bool_constant<Private::CanUseInternalSpace<T>>, + std::is_nothrow_constructible<T, Args...> + >; + +public: + template <typename T, typename... Args, + if_constructible<T, Args...> = true> + explicit QVariant(std::in_place_type_t<T>, Args&&... args) + noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, Args...>::value) + : QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<T>>() ) + { + void *data = const_cast<void *>(constData()); + new (data) T(std::forward<Args>(args)...); + } + + template <typename T, typename U, typename... Args, + if_constructible<T, std::initializer_list<U> &, Args...> = true> + explicit QVariant(std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args) + noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, + std::initializer_list<U> &, + Args... + >::value) + : QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<T>>()) + { + char *data = static_cast<char *>(const_cast<void *>(constData())); + new (data) T(il, std::forward<Args>(args)...); + } + + // primitives + QVariant(int i) noexcept; + QVariant(uint ui) noexcept; + QVariant(qlonglong ll) noexcept; + QVariant(qulonglong ull) noexcept; + QVariant(bool b) noexcept; + QVariant(double d) noexcept; + QVariant(float f) noexcept; + + // trivial, trivially-copyable or COW + QVariant(QChar qchar) noexcept; + QVariant(QDate date) noexcept; + QVariant(QTime time) noexcept; +#ifndef QT_BOOTSTRAPPED + QVariant(const QBitArray &bitarray) noexcept; +#endif + QVariant(const QByteArray &bytearray) noexcept; + QVariant(const QDateTime &datetime) noexcept; + QVariant(const QHash<QString, QVariant> &hash) noexcept; + QVariant(const QJsonArray &jsonArray) noexcept; + QVariant(const QJsonObject &jsonObject) noexcept; + QVariant(const QList<QVariant> &list) noexcept; + QVariant(const QLocale &locale) noexcept; + QVariant(const QMap<QString, QVariant> &map) noexcept; + QVariant(const QRegularExpression &re) noexcept; + QVariant(const QString &string) noexcept; + QVariant(const QStringList &stringlist) noexcept; + QVariant(const QUrl &url) noexcept; + + // conditionally noexcept trivial or trivially-copyable + // (most of these are noexcept on 64-bit) + QVariant(const QJsonValue &jsonValue) noexcept(Private::FitsInInternalSize<sizeof(CborValueStandIn)>); + QVariant(const QModelIndex &modelIndex) noexcept(Private::FitsInInternalSize<8 + 2 * sizeof(quintptr)>); + QVariant(QUuid uuid) noexcept(Private::FitsInInternalSize<16>); +#ifndef QT_NO_GEOM_VARIANT + QVariant(QSize size) noexcept; + QVariant(QSizeF size) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 2>); + QVariant(QPoint pt) noexcept; + QVariant(QPointF pt) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 2>); + QVariant(QLine line) noexcept(Private::FitsInInternalSize<sizeof(int) * 4>); + QVariant(QLineF line) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 4>); + QVariant(QRect rect) noexcept(Private::FitsInInternalSize<sizeof(int) * 4>); + QVariant(QRectF rect) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 4>); #endif - QVariant(int i); - QVariant(uint ui); - QVariant(qlonglong ll); - QVariant(qulonglong ull); - QVariant(bool b); - QVariant(double d); - QVariant(float f); + // not noexcept + QVariant(const QEasingCurve &easing) noexcept(false); + QVariant(const QJsonDocument &jsonDocument) noexcept(false); + QVariant(const QPersistentModelIndex &modelIndex) noexcept(false); + #ifndef QT_NO_CAST_FROM_ASCII - QT_ASCII_CAST_WARN QVariant(const char *str) + QT_ASCII_CAST_WARN QVariant(const char *str) noexcept(false) : QVariant(QString::fromUtf8(str)) {} #endif + QVariant(QLatin1StringView string) noexcept(false); // converts to QString - 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<QVariant> &list); - QVariant(const QMap<QString,QVariant> &map); - QVariant(const QHash<QString,QVariant> &hash); -#ifndef QT_NO_GEOM_VARIANT +#if !defined(Q_CC_GHS) + // GHS has an ICE with this code; use the simplified version below + template <typename T, + std::enable_if_t<std::disjunction_v<std::is_pointer<T>, std::is_member_pointer<T>>, bool> = false> + QVariant(T) = delete; +#else + QVariant(const volatile void *) = delete; +#endif + +#if QT_CORE_REMOVED_SINCE(6, 5) QVariant(const QSize &size); QVariant(const QSizeF &size); QVariant(const QPoint &pt); @@ -250,42 +326,37 @@ class Q_CORE_EXPORT QVariant 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; } + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QVariant) - inline void swap(QVariant &other) noexcept { qSwap(d, other.d); } + inline void swap(QVariant &other) noexcept { std::swap(d, other.d); } + + int userType() const { return typeId(); } + int typeId() const { return metaType().id(); } - Type type() const; - int userType() const; const char *typeName() const; QMetaType metaType() const; - bool canConvert(int targetTypeId) const; - bool convert(int targetTypeId); + bool canConvert(QMetaType targetType) const + { return QMetaType::canConvert(d.type(), targetType); } + bool convert(QMetaType type); + + bool canView(QMetaType targetType) const + { return QMetaType::canView(d.type(), targetType); } + +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_6_0 + bool canConvert(int targetTypeId) const + { return QMetaType::canConvert(d.type(), QMetaType(targetTypeId)); } + QT_DEPRECATED_VERSION_6_0 + bool convert(int targetTypeId) + { return convert(QMetaType(targetTypeId)); } +#endif inline bool isValid() const; bool isNull() const; @@ -304,7 +375,9 @@ class Q_CORE_EXPORT QVariant float toFloat(bool *ok = nullptr) const; qreal toReal(bool *ok = nullptr) const; QByteArray toByteArray() const; +#ifndef QT_BOOTSTRAPPED QBitArray toBitArray() const; +#endif QString toString() const; QStringList toStringList() const; QChar toChar() const; @@ -349,13 +422,73 @@ class Q_CORE_EXPORT QVariant void load(QDataStream &ds); void save(QDataStream &ds) const; #endif - static const char *typeToName(int typeId); - static Type nameToType(const char *name); +#if QT_DEPRECATED_SINCE(6, 0) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + QT_DEPRECATED_VERSION_X_6_0("Use the constructor taking a QMetaType instead.") + explicit QVariant(Type type) + : QVariant(QMetaType(int(type))) + {} + QT_DEPRECATED_VERSION_X_6_0("Use typeId() or metaType().") + Type type() const + { + int type = d.type().id(); + return type >= QMetaType::User ? UserType : static_cast<Type>(type); + } + QT_DEPRECATED_VERSION_6_0 + static const char *typeToName(int typeId) + { return QMetaType(typeId).name(); } + QT_DEPRECATED_VERSION_6_0 + static Type nameToType(const char *name) + { + int metaType = QMetaType::fromName(name).id(); + return metaType <= int(UserType) ? QVariant::Type(metaType) : UserType; + } + QT_WARNING_POP +#endif void *data(); - const void *constData() const; + const void *constData() const + { return d.storage(); } inline const void *data() const { return constData(); } +private: + template <typename T> + void verifySuitableForEmplace() + { + static_assert(!std::is_reference_v<T>, + "QVariant does not support reference types"); + static_assert(!std::is_const_v<T>, + "QVariant does not support const types"); + static_assert(std::is_copy_constructible_v<T>, + "QVariant requires that the type is copyable"); + static_assert(std::is_destructible_v<T>, + "QVariant requires that the type is destructible"); + } + + template <typename T, typename... Args> + T &emplaceImpl(Args&&... args) + { + verifySuitableForEmplace<T>(); + auto data = static_cast<T *>(prepareForEmplace(QMetaType::fromType<T>())); + return *q20::construct_at(data, std::forward<Args>(args)...); + } + +public: + template <typename T, typename... Args, + if_constructible<T, Args...> = true> + T &emplace(Args&&... args) + { + return emplaceImpl<T>(std::forward<Args>(args)...); + } + + template <typename T, typename U, typename... Args, + if_constructible<T, std::initializer_list<U> &, Args...> = true> + T &emplace(std::initializer_list<U> list, Args&&... args) + { + return emplaceImpl<T>(list, std::forward<Args>(args)...); + } + template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>> void setValue(T &&avalue) { @@ -380,129 +513,168 @@ class Q_CORE_EXPORT QVariant } template<typename T> - inline T value() const + inline T value() const & { return qvariant_cast<T>(*this); } template<typename T> + inline T view() + { + T t{}; + QMetaType::view(metaType(), data(), QMetaType::fromType<T>(), &t); + return t; + } + + template<typename T> + inline T value() && + { return qvariant_cast<T>(std::move(*this)); } + + template<typename T, if_rvalue<T> = true> +#ifndef Q_QDOC + /* needs is_copy_constructible for variants semantics, is_move_constructible so that moveConstruct works + (but copy_constructible implies move_constructble, so don't bother checking) + */ + static inline auto fromValue(T &&value) + noexcept(std::is_nothrow_copy_constructible_v<T> && Private::CanUseInternalSpace<T>) + -> std::enable_if_t<std::conjunction_v<std::is_copy_constructible<T>, + std::is_destructible<T>>, QVariant> +#else + static inline QVariant fromValue(T &&value) +#endif + { + // handle special cases + using Type = std::remove_cv_t<T>; + if constexpr (std::is_null_pointer_v<Type>) + return QVariant::fromMetaType(QMetaType::fromType<std::nullptr_t>()); + else if constexpr (std::is_same_v<Type, QVariant>) + return std::forward<T>(value); + else if constexpr (std::is_same_v<Type, std::monostate>) + return QVariant(); + QMetaType mt = QMetaType::fromType<Type>(); + mt.registerType(); // we want the type stored in QVariant to always be registered + // T is a forwarding reference, so if T satifies the enable-ifery, + // we get this overload even if T is an lvalue reference and thus must check here + // Moreover, we only try to move if the type is actually moveable and not if T is const + // as in const int i; QVariant::fromValue(std::move(i)); + if constexpr (std::conjunction_v<std::is_move_constructible<Type>, std::negation<std::is_const<T>>>) + return moveConstruct(QMetaType::fromType<Type>(), std::addressof(value)); + else + return copyConstruct(mt, std::addressof(value)); + } + + template<typename T> +#ifndef Q_QDOC + static inline auto fromValue(const T &value) + noexcept(std::is_nothrow_copy_constructible_v<T> && Private::CanUseInternalSpace<T>) + -> std::enable_if_t<std::is_copy_constructible_v<T> && std::is_destructible_v<T>, QVariant> +#else static inline QVariant fromValue(const T &value) +#endif { + if constexpr (std::is_null_pointer_v<T>) + return QVariant(QMetaType::fromType<std::nullptr_t>()); + else if constexpr (std::is_same_v<T, QVariant>) + return value; + else if constexpr (std::is_same_v<T, std::monostate>) + return QVariant(); return QVariant(QMetaType::fromType<T>(), std::addressof(value)); } -#if (__has_include(<variant>) && __cplusplus >= 201703L) || defined(Q_CLANG_QDOC) template<typename... Types> static inline QVariant fromStdVariant(const std::variant<Types...> &value) { - if (value.valueless_by_exception()) - return QVariant(); - return std::visit([](const auto &arg) { return fromValue(arg); }, value); + return fromStdVariantImpl(value); } -#endif + + template<typename... Types> + static QVariant fromStdVariant(std::variant<Types...> &&value) + { + return fromStdVariantImpl(std::move(value)); + } + + static QVariant fromMetaType(QMetaType type, const void *copy = nullptr); template<typename T> bool canConvert() const - { return canConvert(qMetaTypeId<T>()); } + { return canConvert(QMetaType::fromType<T>()); } - 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(); + template<typename T> + bool canView() const + { return canView(QMetaType::fromType<T>()); } - 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<QtPrivate::QMetaTypeInterface *>(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; - }; + static QPartialOrdering compare(const QVariant &lhs, const QVariant &rhs); + +private: + template <typename StdVariant> + static QVariant fromStdVariantImpl(StdVariant &&v) + { + if (Q_UNLIKELY(v.valueless_by_exception())) + return QVariant(); + auto visitor = [](auto &&arg) { + return QVariant::fromValue(q23::forward_like<StdVariant>(arg)); + }; + return std::visit(visitor, std::forward<StdVariant>(v)); + } - inline bool operator==(const QVariant &v) const - { return cmp(v); } - inline bool operator!=(const QVariant &v) const - { return !cmp(v); } + friend bool comparesEqual(const QVariant &a, const QVariant &b) + { return a.equals(b); } + Q_DECLARE_EQUALITY_COMPARABLE(QVariant) -protected: - friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &); #ifndef QT_NO_DEBUG_STREAM - friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &); + template <typename T> + friend auto operator<<(const QDebug &debug, const T &variant) -> std::enable_if_t<std::is_same_v<T, QVariant>, QDebug> { + return variant.qdebugHelper(debug); + } + QDebug qdebugHelper(QDebug) const; #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 <typename T> + friend T *get_if(QVariant *v) noexcept + { + // data() will detach from is_null, returning non-nullptr + if (!v || v->d.type() != QMetaType::fromType<T>()) + return nullptr; + return static_cast<T*>(v->data()); + } + template <typename T> + friend const T *get_if(const QVariant *v) noexcept + { + // (const) data() will not detach from is_null, return nullptr + if (!v || v->d.is_null || v->d.type() != QMetaType::fromType<T>()) + return nullptr; + return static_cast<const T*>(v->data()); + } + +#define Q_MK_GET(cvref) \ + template <typename T> \ + friend T cvref get(QVariant cvref v) \ + { \ + if constexpr (std::is_const_v<T cvref>) \ + Q_ASSERT(!v.d.is_null); \ + Q_ASSERT(v.d.type() == QMetaType::fromType<q20::remove_cvref_t<T>>()); \ + return static_cast<T cvref>(*get_if<T>(&v)); \ + } \ + /* end */ + Q_MK_GET(&) + Q_MK_GET(const &) + Q_MK_GET(&&) + Q_MK_GET(const &&) +#undef Q_MK_GET + + static QVariant moveConstruct(QMetaType type, void *data); + static QVariant copyConstruct(QMetaType type, const void *data); + template<typename T> friend inline T qvariant_cast(const QVariant &); - template<typename T> friend struct QtPrivate::QVariantValueHelper; + template<typename T> + friend inline T qvariant_cast(QVariant &&); + 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 + void create(QMetaType type, const void *copy); + bool equals(const QVariant &other) const; + bool convert(int type, void *ptr) const; + bool view(int type, void *ptr); private: // force compile error, prevent QVariant(bool) to be called @@ -515,7 +687,12 @@ private: // int variant, so delete this constructor: QVariant(QMetaType::Type) = delete; - // These constructors don't create QVariants of the type associcated + // used to setup the QVariant internals for the "real" inplace ctor + QVariant(std::in_place_t, QMetaType type); + // helper for emplace + void *prepareForEmplace(QMetaType type); + + // These constructors don't create QVariants of the type associated // 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 @@ -534,330 +711,173 @@ public: inline const DataPtr &data_ptr() const { return d; } }; -template<> -inline QVariant QVariant::fromValue(const QVariant &value) +inline bool QVariant::isValid() const { - return value; + return d.type().isValid(); } -#if __has_include(<variant>) && __cplusplus >= 201703L -template<> -inline QVariant QVariant::fromValue(const std::monostate &) +#ifndef QT_NO_DATASTREAM +Q_CORE_EXPORT QDataStream &operator>>(QDataStream &s, QVariant &p); +Q_CORE_EXPORT QDataStream &operator<<(QDataStream &s, const QVariant &p); + +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +QT_DEPRECATED_VERSION_6_0 +inline QDataStream &operator>>(QDataStream &s, QVariant::Type &p) { - return QVariant(); + quint32 u; + s >> u; + p = static_cast<QVariant::Type>(u); + return s; } -#endif - -inline bool QVariant::isValid() const +QT_DEPRECATED_VERSION_6_0 +inline QDataStream &operator<<(QDataStream &s, const QVariant::Type p) { - return d.type().isValid(); + s << static_cast<quint32>(p); + return s; } +QT_WARNING_POP +#endif -#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; } +inline void swap(QVariant &value1, QVariant &value2) noexcept +{ value1.swap(value2); } -#ifdef Q_QDOC - inline bool operator==(const QVariant &v1, const QVariant &v2); - inline bool operator!=(const QVariant &v1, const QVariant &v2); -#else +#ifndef QT_MOC -/* Helper class to add one more level of indirection to prevent - implicit casts. -*/ -class QVariantComparisonHelper +template<typename T> inline T qvariant_cast(const QVariant &v) { -public: - inline QVariantComparisonHelper(const QVariant &var) - : v(&var) {} -private: - friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &); - const QVariant *v; -}; + QMetaType targetType = QMetaType::fromType<T>(); + if (v.d.type() == targetType) + return v.d.get<T>(); + if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) { + using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *; + QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>(); + if (v.d.type() == nonConstTargetType) + return v.d.get<nonConstT>(); + } -inline bool operator==(const QVariant &v1, const QVariantComparisonHelper &v2) -{ - return v1.cmp(*v2.v); + T t{}; + QMetaType::convert(v.metaType(), v.constData(), targetType, &t); + return t; } -inline bool operator!=(const QVariant &v1, const QVariantComparisonHelper &v2) +template<typename T> inline T qvariant_cast(QVariant &&v) { - return !operator==(v1, v2); + QMetaType targetType = QMetaType::fromType<T>(); + if (v.d.type() == targetType) { + if constexpr (QVariant::Private::CanUseInternalSpace<T>) { + return std::move(*reinterpret_cast<T *>(v.d.data.data)); + } else { + if (v.d.data.shared->ref.loadRelaxed() == 1) + return std::move(*reinterpret_cast<T *>(v.d.data.shared->data())); + else + return v.d.get<T>(); + } + } + if constexpr (std::is_same_v<T, QVariant>) { + // if the metatype doesn't match, but we want a QVariant, just return the current variant + return v; + } if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) { + // moving a pointer is pointless, just do the same as the const & overload + using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *; + QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>(); + if (v.d.type() == nonConstTargetType) + return v.d.get<nonConstT>(); + } + + T t{}; + QMetaType::convert(v.metaType(), v.constData(), targetType, &t); + return t; } -#endif -Q_DECLARE_SHARED(QVariant) -class Q_CORE_EXPORT QSequentialIterable +# ifndef QT_NO_VARIANT +template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v) { - 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 const_iterator &k) { return k + j; } - }; - - friend struct const_iterator; - - explicit QSequentialIterable(const QtMetaTypePrivate::QSequentialIterableImpl &impl); - - const_iterator begin() const; - const_iterator end() const; + if (v.metaType().id() == QMetaType::QVariant) + return *reinterpret_cast<const QVariant *>(v.constData()); + return v; +} +# endif - QVariant at(int idx) const; - int size() const; +#endif // QT_MOC - bool canReverseIterate() const; -}; +#ifndef QT_NO_DEBUG_STREAM +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +QT_DEPRECATED_VERSION_6_0 +Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant::Type); +QT_WARNING_POP +#endif +#endif -class Q_CORE_EXPORT QAssociativeIterable +namespace QtPrivate { +class Q_CORE_EXPORT QVariantTypeCoercer { - 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_); + // ### Qt7: Pass QMetaType as value rather than const ref. + const void *convert(const QVariant &value, const QMetaType &type); + const void *coerce(const QVariant &value, const QMetaType &type); - 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 const_iterator &k) { return k + j; } - }; - - friend struct const_iterator; - - explicit QAssociativeIterable(const QtMetaTypePrivate::QAssociativeIterableImpl &impl); +private: + QVariant converted; +}; +} - const_iterator begin() const; - const_iterator end() const; - const_iterator find(const QVariant &key) const; +template<typename Pointer> +class QVariantRef +{ +private: + const Pointer *m_pointer = nullptr; - QVariant value(const QVariant &key) const; +public: + explicit QVariantRef(const Pointer *reference) : m_pointer(reference) {} + QVariantRef(const QVariantRef &) = default; + QVariantRef(QVariantRef &&) = default; + ~QVariantRef() = default; - int size() const; -}; + operator QVariant() const; + QVariantRef &operator=(const QVariant &value); + QVariantRef &operator=(const QVariantRef &value) { return operator=(QVariant(value)); } + QVariantRef &operator=(QVariantRef &&value) { return operator=(QVariant(value)); } -#ifndef QT_MOC -namespace QtPrivate { - template<typename T> - struct QVariantValueHelper : TreatAsQObjectBeforeMetaType<QVariantValueHelper<T>, T, const QVariant &, T> + friend void swap(QVariantRef a, QVariantRef b) { - static T metaType(const QVariant &v) - { - const int vid = qMetaTypeId<T>(); - if (vid == v.userType()) - return *reinterpret_cast<const T *>(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<T>(QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject - ? v.d.data.o - : QVariantValueHelper::metaType(v)); - } -#endif - }; + QVariant tmp = a; + a = b; + b = std::move(tmp); + } +}; - template<typename T> - struct QVariantValueHelperInterface : QVariantValueHelper<T> - { - }; +class Q_CORE_EXPORT QVariantConstPointer +{ +private: + QVariant m_variant; - template<> - struct QVariantValueHelperInterface<QSequentialIterable> - { - static QSequentialIterable invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId<QVariantList>()) { - return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QVariantList*>(v.constData()))); - } - if (typeId == qMetaTypeId<QStringList>()) { - return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QStringList*>(v.constData()))); - } -#ifndef QT_BOOTSTRAPPED - if (typeId == qMetaTypeId<QByteArrayList>()) { - return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QByteArrayList*>(v.constData()))); - } -#endif - return QSequentialIterable(qvariant_cast<QtMetaTypePrivate::QSequentialIterableImpl>(v)); - } - }; - template<> - struct QVariantValueHelperInterface<QAssociativeIterable> - { - static QAssociativeIterable invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId<QVariantMap>()) { - return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast<const QVariantMap*>(v.constData()))); - } - if (typeId == qMetaTypeId<QVariantHash>()) { - return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast<const QVariantHash*>(v.constData()))); - } - return QAssociativeIterable(qvariant_cast<QtMetaTypePrivate::QAssociativeIterableImpl>(v)); - } - }; - template<> - struct QVariantValueHelperInterface<QVariantList> - { - static QVariantList invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId<QStringList>() || typeId == qMetaTypeId<QByteArrayList>() || - (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>()) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QVariantList>()))) { - QSequentialIterable iter = QVariantValueHelperInterface<QSequentialIterable>::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<QVariantList>::invoke(v); - } - }; - template<> - struct QVariantValueHelperInterface<QVariantHash> - { - static QVariantHash invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId<QVariantMap>() || ((QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QVariantHash>()))) { - QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::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<QVariantHash>::invoke(v); - } - }; - template<> - struct QVariantValueHelperInterface<QVariantMap> - { - static QVariantMap invoke(const QVariant &v) - { - const int typeId = v.userType(); - if (typeId == qMetaTypeId<QVariantHash>() || (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>()) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QVariantMap>()))) { - QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v); - QVariantMap l; - for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) - static_cast<QMultiMap<QString, QVariant> &>(l).insert(it.key().toString(), it.value()); - return l; - } - return QVariantValueHelper<QVariantMap>::invoke(v); - } - }; - template<> - struct QVariantValueHelperInterface<QPair<QVariant, QVariant> > - { - static QPair<QVariant, QVariant> invoke(const QVariant &v) - { - const int typeId = v.userType(); - - if (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>()) && !(typeId == qMetaTypeId<QPair<QVariant, QVariant> >())) { - QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value<QtMetaTypePrivate::QPairVariantInterfaceImpl>(); - const QtMetaTypePrivate::VariantData d1 = pi.first(); - QVariant v1(d1.metaTypeId, d1.data, d1.flags); - if (d1.metaTypeId == qMetaTypeId<QVariant>()) - v1 = *reinterpret_cast<const QVariant*>(d1.data); - - const QtMetaTypePrivate::VariantData d2 = pi.second(); - QVariant v2(d2.metaTypeId, d2.data, d2.flags); - if (d2.metaTypeId == qMetaTypeId<QVariant>()) - v2 = *reinterpret_cast<const QVariant*>(d2.data); - - return QPair<QVariant, QVariant>(v1, v2); - } - return QVariantValueHelper<QPair<QVariant, QVariant> >::invoke(v); - } - }; -} +public: + explicit QVariantConstPointer(QVariant variant); -template<typename T> inline T qvariant_cast(const QVariant &v) -{ - return QtPrivate::QVariantValueHelperInterface<T>::invoke(v); -} + QVariant operator*() const; + const QVariant *operator->() const; +}; -template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v) +template<typename Pointer> +class QVariantPointer { - if (v.userType() == QMetaType::QVariant) - return *reinterpret_cast<const QVariant *>(v.constData()); - return v; -} - -#endif +private: + const Pointer *m_pointer = nullptr; -#ifndef QT_NO_DEBUG_STREAM -Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &); -Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant::Type); -#endif +public: + explicit QVariantPointer(const Pointer *pointer) : m_pointer(pointer) {} + QVariantRef<Pointer> operator*() const { return QVariantRef<Pointer>(m_pointer); } + Pointer operator->() const { return *m_pointer; } +}; QT_END_NAMESPACE |