diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2021-02-12 22:35:28 +0100 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-06-12 09:58:58 +0200 |
commit | dcf76042301772b770a088526e5753ed41232d87 (patch) | |
tree | 75f29939947c591f6f3277d64c5a5d177d904ac8 /src/corelib/kernel/qvariant.h | |
parent | b1ee49b46533d39f7fabda68d0bd08a1ab130a27 (diff) |
QVariant::value/qvariant_cast: add rvalue optimization
If we have a rvalue reference to an unshared QVariant, we can avoid
potentially expensive copies, and use move semantics instead.
[ChangeLog][QtCore][QVariant] Added rvalue QVariant overloads of qvariant_cast<T>() and QVariant::value<T>().
[ChangeLog][Potentially Source-Incompatible Changes][QVariant] It is no
longer possible to take the address of a specialization of
qvariant_cast; consider using a lambda function instead.
Change-Id: Ifc74991eadcc31387b755c45484224a3200bb0ba
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/corelib/kernel/qvariant.h')
-rw-r--r-- | src/corelib/kernel/qvariant.h | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index ed4978699f..2c8df591e2 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -508,7 +508,7 @@ public: } template<typename T> - inline T value() const + inline T value() const & { return qvariant_cast<T>(*this); } template<typename T> @@ -519,6 +519,10 @@ public: 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 @@ -654,6 +658,9 @@ private: 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); @@ -753,6 +760,35 @@ 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; +} + template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v) { if (v.metaType().id() == QMetaType::QVariant) |