QVariant::setValue(): enable move semantics

Given we optimize for the case where the new value is of the
same type of the one already stored in the variant, enable move
assignment for that case.

As a drive-by, avoid a path to detach() for data() if we know
we're detached.

Change-Id: I9abbdc10637ce77ebb747b49d83e1ef914d997bb
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Giuseppe D'Angelo 2020-06-06 00:27:44 +02:00
parent 23444d4b26
commit 43fa292ff6
5 changed files with 41 additions and 27 deletions

View File

@ -4019,7 +4019,7 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
#endif
/*! \fn template<typename T> void QVariant::setValue(const T &value)
/*! \fn template<typename T> void QVariant::setValue(T &&value)
Stores a copy of \a value. If \c{T} is a type that QVariant
doesn't support, QMetaType is used to store the value. A compile
@ -4032,6 +4032,18 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
\sa value(), fromValue(), canConvert()
*/
/*! \fn template<typename T> void QVariant::setValue(const QVariant &value)
Copies \a value over this QVariant. It is equivalent to simply
assigning \a value to this QVariant.
*/
/*! \fn template<typename T> void QVariant::setValue(QVariant &&value)
Moves \a value over this QVariant. It is equivalent to simply
move assigning \a value to this QVariant.
*/
/*! \fn template<typename T> T QVariant::value() const
Returns the stored value converted to the template type \c{T}.

View File

@ -356,8 +356,28 @@ class Q_CORE_EXPORT QVariant
const void *constData() const;
inline const void *data() const { return constData(); }
template<typename T>
inline void setValue(const T &value);
template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>>
void setValue(T &&avalue)
{
using VT = std::decay_t<T>;
QMetaType metaType = QMetaType::fromType<VT>();
// If possible we reuse the current QVariant private.
if (isDetached() && d.type() == metaType) {
*reinterpret_cast<VT *>(const_cast<void *>(constData())) = std::forward<T>(avalue);
} else {
*this = QVariant::fromValue<VT>(std::forward<T>(avalue));
}
}
void setValue(const QVariant &avalue)
{
*this = avalue;
}
void setValue(QVariant &&avalue)
{
*this = std::move(avalue);
}
template<typename T>
inline T value() const
@ -533,24 +553,6 @@ inline bool QVariant::isValid() const
return d.type().isValid();
}
template<typename T>
inline void QVariant::setValue(const T &avalue)
{
QMetaType metaType = QMetaType::fromType<T>();
// If possible we reuse the current QVariant private.
if (isDetached() && d.type() == metaType) {
*reinterpret_cast<T *>(data()) = avalue;
} else {
*this = QVariant::fromValue<T>(avalue);
}
}
template<>
inline void QVariant::setValue(const QVariant &avalue)
{
*this = avalue;
}
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream& operator>> (QDataStream& s, QVariant& p);
Q_CORE_EXPORT QDataStream& operator<< (QDataStream& s, const QVariant& p);

View File

@ -2122,7 +2122,7 @@ void QTextBlockFormat::setTabPositions(const QList<QTextOption::Tab> &tabs)
QList<QTextOption::Tab>::ConstIterator iter = tabs.constBegin();
while (iter != tabs.constEnd()) {
QVariant v;
v.setValue<QTextOption::Tab>(*iter);
v.setValue(*iter);
list.append(v);
++iter;
}

View File

@ -327,7 +327,7 @@ void tst_QVariant::constructor()
QVERIFY(var7.isValid());
QVERIFY(!var7.isNull());
QVariant var8;
var8.setValue<int>(5);
var8.setValue(5);
QVERIFY(var8.isValid());
QVERIFY(!var8.isNull());
}

View File

@ -4499,7 +4499,7 @@ protected:
break;
case QGraphicsItem::ItemTransformChange: {
QVariant variant;
variant.setValue<QTransform>(transform());
variant.setValue(transform());
oldValues << variant;
}
break;
@ -4616,7 +4616,7 @@ void tst_QGraphicsItem::itemChange()
}
{
// ItemTransformChange / ItemTransformHasChanged
tester.itemChangeReturnValue.setValue<QTransform>(QTransform().rotate(90));
tester.itemChangeReturnValue.setValue(QTransform().rotate(90));
tester.setTransform(QTransform::fromTranslate(50, 0), true);
++changeCount; // notification sent too
++changeCount;
@ -4628,7 +4628,7 @@ void tst_QGraphicsItem::itemChange()
QCOMPARE(qvariant_cast<QTransform>(tester.values.at(tester.values.size() - 1)),
QTransform().rotate(90));
QVariant variant;
variant.setValue<QTransform>(QTransform());
variant.setValue(QTransform());
QCOMPARE(tester.oldValues.constLast(), variant);
QCOMPARE(tester.transform(), QTransform().rotate(90));
}
@ -4763,7 +4763,7 @@ void tst_QGraphicsItem::itemChange()
}
{
// ItemParentChange
tester.itemChangeReturnValue.setValue<QGraphicsItem *>(nullptr);
tester.itemChangeReturnValue.setValue(static_cast<QGraphicsItem *>(nullptr));
tester.setParentItem(&testerHelper);
QCOMPARE(tester.changes.size(), ++changeCount);
QCOMPARE(tester.changes.constLast(), QGraphicsItem::ItemParentChange);