summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qvariant.h
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2021-02-12 22:35:28 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2023-06-12 09:58:58 +0200
commitdcf76042301772b770a088526e5753ed41232d87 (patch)
tree75f29939947c591f6f3277d64c5a5d177d904ac8 /src/corelib/kernel/qvariant.h
parentb1ee49b46533d39f7fabda68d0bd08a1ab130a27 (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.h38
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)