diff options
Diffstat (limited to 'src/corelib/kernel/qvariant.h')
-rw-r--r-- | src/corelib/kernel/qvariant.h | 620 |
1 files changed, 388 insertions, 232 deletions
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 9ebdbc4a18..d567bcbb7c 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -1,104 +1,144 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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_NO_DEBUG_STREAM #include <QtCore/qdebug.h> #endif -#ifndef QT_BOOTSTRAPPED -#include <QtCore/qbytearraylist.h> -#endif -#include <memory> -#include <type_traits> -#if __has_include(<variant>) && __cplusplus >= 201703L +#include <memory> +#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 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; template<typename T> inline T qvariant_cast(const QVariant &); +namespace QtPrivate { +template<> constexpr inline bool qIsRelocatable<QVariant> = true; +} class Q_CORE_EXPORT QVariant { - public: + 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; } + }; + + struct Private + { + 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) + { + Q_ASSERT(type); + return QMetaType::TypeFlags(type->flags) & QMetaType::RelocatableType && + size_t(type->size) <= MaxInternalSize && size_t(type->alignment) <= alignof(double); + } + + 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 reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(packedType << 2); + } + + inline QMetaType type() const + { + return QMetaType(typeInterface()); + } + }; + #if QT_DEPRECATED_SINCE(6, 0) enum QT_DEPRECATED_VERSION_X_6_0("Use QMetaType::Type instead.") Type { @@ -180,32 +220,104 @@ class Q_CORE_EXPORT QVariant explicit QVariant(QMetaType type, const void *copy = nullptr); QVariant(const QVariant &other); - QVariant(int i); - QVariant(uint ui); - QVariant(qlonglong ll); - QVariant(qulonglong ull); - QVariant(bool b); - QVariant(double d); - QVariant(float f); +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 + + // 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); @@ -214,25 +326,7 @@ 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); @@ -240,7 +334,7 @@ class Q_CORE_EXPORT QVariant { other.d = Private(); } 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(); } @@ -281,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; @@ -336,7 +432,7 @@ class Q_CORE_EXPORT QVariant QT_DEPRECATED_VERSION_X_6_0("Use typeId() or metaType().") Type type() const { - int type = d.typeId(); + int type = d.type().id(); return type >= QMetaType::User ? UserType : static_cast<Type>(type); } QT_DEPRECATED_VERSION_6_0 @@ -356,6 +452,43 @@ class Q_CORE_EXPORT QVariant { 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,7 +513,7 @@ class Q_CORE_EXPORT QVariant } template<typename T> - inline T value() const + inline T value() const & { return qvariant_cast<T>(*this); } template<typename T> @@ -392,25 +525,73 @@ class Q_CORE_EXPORT QVariant } template<typename T> -#ifndef Q_CLANG_QDOC - static inline auto fromValue(const T &value) -> - std::enable_if_t<std::is_copy_constructible_v<T>, QVariant> + 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); + } + + template<typename... Types> + static QVariant fromStdVariant(std::variant<Types...> &&value) + { + return fromStdVariantImpl(std::move(value)); } -#endif + + static QVariant fromMetaType(QMetaType type, const void *copy = nullptr); template<typename T> bool canConvert() const @@ -420,113 +601,24 @@ class Q_CORE_EXPORT QVariant bool canView() const { return canView(QMetaType::fromType<T>()); } -public: - struct PrivateShared - { - private: - inline PrivateShared() : ref(1) { } - public: - static PrivateShared *create(const QtPrivate::QMetaTypeInterface *type) - { - Q_ASSERT(type); - size_t size = type->size; - size_t align = type->alignment; - - size += sizeof(PrivateShared); - if (align > sizeof(PrivateShared)) { - // The alignment is larger than the alignment we can guarantee for the pointer - // directly following PrivateShared, so we need to allocate some additional - // memory to be able to fit the object into the available memory with suitable - // alignment. - size += align - sizeof(PrivateShared); - } - void *data = operator new(size); - auto *ps = new (data) QVariant::PrivateShared(); - ps->offset = int(((quintptr(ps) + sizeof(PrivateShared) + align - 1) & ~(align - 1)) - quintptr(ps)); - return ps; - } - static void free(PrivateShared *p) - { - p->~PrivateShared(); - operator delete(p); - } - - alignas(8) QAtomicInt ref; - int offset; - - const void *data() const - { return reinterpret_cast<const unsigned char *>(this) + offset; } - void *data() - { return reinterpret_cast<unsigned char *>(this) + offset; } - }; - struct Private - { - static constexpr size_t MaxInternalSize = 3*sizeof(void *); - template<typename T> - static constexpr bool CanUseInternalSpace = (QTypeInfo<T>::isRelocatable && sizeof(T) <= MaxInternalSize && alignof(T) <= alignof(double)); - static constexpr bool canUseInternalSpace(QtPrivate::QMetaTypeInterface *type) - { - Q_ASSERT(type); - return QMetaType::TypeFlags(type->flags) & QMetaType::RelocatableType && - size_t(type->size) <= MaxInternalSize && size_t(type->alignment) <= alignof(double); - } - - 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; - - Private() noexcept : is_shared(false), is_null(true), packedType(0) {} - explicit Private(QMetaType type) noexcept : is_shared(false), is_null(false) - { - quintptr mt = quintptr(type.d_ptr); - Q_ASSERT((mt & 0x3) == 0); - packedType = mt >> 2; - } - explicit Private(int type) noexcept : Private(QMetaType(type)) {} - - const void *storage() const - { return is_shared ? data.shared->data() : &data.data; } - - const void *internalStorage() const - { Q_ASSERT(is_shared); return &data.data; } - - // determine internal storage at compile time - template<typename T> - const T &get() const - { return *static_cast<const T *>(storage()); } - template<typename T> - void set(const T &t) - { *static_cast<T *>(CanUseInternalSpace<T> ? &data.data : data.shared->data()) = t; } - - inline QMetaType type() const - { - return QMetaType(reinterpret_cast<QtPrivate::QMetaTypeInterface *>(packedType << 2)); - } - - inline QtPrivate::QMetaTypeInterface * typeInterface() const - { - return reinterpret_cast<QtPrivate::QMetaTypeInterface *>(packedType << 2); - } - - inline int typeId() const - { - return type().id(); - } - }; - public: static QPartialOrdering compare(const QVariant &lhs, const QVariant &rhs); private: - friend inline bool operator==(const QVariant &a, const QVariant &b) + 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)); + } + + friend bool comparesEqual(const QVariant &a, const QVariant &b) { return a.equals(b); } - friend inline bool operator!=(const QVariant &a, const QVariant &b) - { return !a.equals(b); } + Q_DECLARE_EQUALITY_COMPARABLE(QVariant) + #ifndef QT_NO_DEBUG_STREAM template <typename T> friend auto operator<<(const QDebug &debug, const T &variant) -> std::enable_if_t<std::is_same_v<T, QVariant>, QDebug> { @@ -534,8 +626,48 @@ private: } QDebug qdebugHelper(QDebug) const; #endif + + 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 inline T qvariant_cast(QVariant &&); + protected: Private d; void create(int type, const void *copy); @@ -555,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 @@ -574,20 +711,6 @@ public: inline const DataPtr &data_ptr() const { return d; } }; -template<> -inline QVariant QVariant::fromValue(const QVariant &value) -{ - return value; -} - -#if __has_include(<variant>) && __cplusplus >= 201703L -template<> -inline QVariant QVariant::fromValue(const std::monostate &) -{ - return QVariant(); -} -#endif - inline bool QVariant::isValid() const { return d.type().isValid(); @@ -622,7 +745,8 @@ QT_WARNING_POP inline bool QVariant::isDetached() const { return !d.is_shared || d.data.shared->ref.loadRelaxed() == 1; } -Q_DECLARE_SHARED(QVariant) +inline void swap(QVariant &value1, QVariant &value2) noexcept +{ value1.swap(value2); } #ifndef QT_MOC @@ -643,14 +767,45 @@ template<typename T> inline T qvariant_cast(const QVariant &v) return t; } +template<typename T> inline T qvariant_cast(QVariant &&v) +{ + 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; +} + +# ifndef QT_NO_VARIANT template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v) { if (v.metaType().id() == QMetaType::QVariant) return *reinterpret_cast<const QVariant *>(v.constData()); return v; } +# endif -#endif +#endif // QT_MOC #ifndef QT_NO_DEBUG_STREAM #if QT_DEPRECATED_SINCE(6, 0) @@ -666,6 +821,7 @@ namespace QtPrivate { class Q_CORE_EXPORT QVariantTypeCoercer { public: + // ### 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); |