summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qvariant.h
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2022-09-18 15:27:38 +0200
committerMarc Mutz <marc.mutz@qt.io>2023-06-02 22:31:36 +0200
commit79ae79d05c65019233cf9ae9e77ef59d90e75ac2 (patch)
tree417e8dcfed1af2c78a9de0daaa8e059afce2590c /src/corelib/kernel/qvariant.h
parent581c4bcb62a9d3cbb4c33df3f0f7a0a965225e74 (diff)
QVariant::fromValue: Add rvalue optimization
When passing an rvalue-reference to QVariant, there is no reason to make a copy if the type is moveable. Moreover, we know that the pointer which we construct from the object passed to fromValue non-null. We make use of both facts by parametrizing custom_construct on non-nullness and availability of a move-ctor, and then dispatching to the suitable template. We need to keep the const T& overload, as otherwise code which explicitly specializes fromValue and passes a const lvalue to it would stop to compile. [ChangeLog][QtCore][QVariant] Added fromValue() overload taking rvalues. Change-Id: I44fb757d516ef364fe7967bc103b3f98278b4919 Reviewed-by: Marc Mutz <marc.mutz@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib/kernel/qvariant.h')
-rw-r--r--src/corelib/kernel/qvariant.h39
1 files changed, 39 insertions, 0 deletions
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index b1865e442b..582f135fab 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -71,6 +71,9 @@ class Q_CORE_EXPORT QVariant
>,
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
@@ -516,6 +519,39 @@ public:
return t;
}
+ 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(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)
@@ -594,6 +630,9 @@ private:
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 &);
protected: