diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2022-09-18 15:27:38 +0200 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2023-06-02 22:31:36 +0200 |
commit | 79ae79d05c65019233cf9ae9e77ef59d90e75ac2 (patch) | |
tree | 417e8dcfed1af2c78a9de0daaa8e059afce2590c /src/corelib/kernel/qvariant.h | |
parent | 581c4bcb62a9d3cbb4c33df3f0f7a0a965225e74 (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.h | 39 |
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: |