diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-09-04 16:36:03 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2017-09-14 06:27:56 +0000 |
commit | b6e99ec056387e8720ef5acff824089fe585e00a (patch) | |
tree | bc6d7536d725e7b47c0e1b024e4ffd88370d62d3 /src | |
parent | 84fcc38955f16e6717f3183dd82eed5ddd76d27f (diff) |
Optimize QVariant::cmp()
Don't always copy the variants that we want to compare. This can
in some cases be a relatively expensive operation.
Change-Id: I2b3fd246ac136b19d8a8d281fbdcfb0417c8fb6c
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 89 |
1 files changed, 49 insertions, 40 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index a0bbcc235e..36fd4567a7 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -3517,29 +3517,36 @@ static int numericCompare(const QVariant::Private *d1, const QVariant::Private * */ bool QVariant::cmp(const QVariant &v) const { + auto cmp_helper = [] (const QVariant::Private &d1, const QVariant::Private &d2) + { + Q_ASSERT(d1.type == d2.type); + if (d1.type >= QMetaType::User) { + int result; + if (QMetaType::equals(QT_PREPEND_NAMESPACE(constData(d1)), QT_PREPEND_NAMESPACE(constData(d2)), d1.type, &result)) + return result == 0; + } + return handlerManager[d1.type]->compare(&d1, &d2); + }; + // try numerics first, with C++ type promotion rules (no conversion) if (qIsNumericType(d.type) && qIsNumericType(v.d.type)) return numericCompare(&d, &v.d) == 0; + if (d.type == v.d.type) + return cmp_helper(d, v.d); + QVariant v1 = *this; QVariant v2 = v; - if (d.type != v2.d.type) { - if (v2.canConvert(v1.d.type)) { - if (!v2.convert(v1.d.type)) - return false; - } else { - // try the opposite conversion, it might work - qSwap(v1, v2); - if (!v2.convert(v1.d.type)) - return false; - } - } - if (v1.d.type >= QMetaType::User) { - int result; - if (QMetaType::equals(QT_PREPEND_NAMESPACE(constData(v1.d)), QT_PREPEND_NAMESPACE(constData(v2.d)), v1.d.type, &result)) - return result == 0; + if (v2.canConvert(v1.d.type)) { + if (!v2.convert(v1.d.type)) + return false; + } else { + // try the opposite conversion, it might work + qSwap(v1, v2); + if (!v2.convert(v1.d.type)) + return false; } - return handlerManager[v1.d.type]->compare(&v1.d, &v2.d); + return cmp_helper(v1.d, v2.d); } /*! @@ -3555,51 +3562,53 @@ int QVariant::compare(const QVariant &v) const if (cmp(v)) return 0; - QVariant v1 = *this; - QVariant v2 = v; + const QVariant *v1 = this; + const QVariant *v2 = &v; + QVariant converted1; + QVariant converted2; - if (v1.d.type != v2.d.type) { + if (d.type != v.d.type) { // if both types differ, try to convert - if (v2.canConvert(v1.d.type)) { - QVariant temp = v2; - if (temp.convert(v1.d.type)) - v2 = temp; + if (v2->canConvert(v1->d.type)) { + converted2 = *v2; + if (converted2.convert(v1->d.type)) + v2 = &converted2; } - if (v1.d.type != v2.d.type && v1.canConvert(v2.d.type)) { - QVariant temp = v1; - if (temp.convert(v2.d.type)) - v1 = temp; + if (v1->d.type != v2->d.type && v1->canConvert(v2->d.type)) { + converted1 = *v1; + if (converted1.convert(v2->d.type)) + v1 = &converted1; } - if (v1.d.type != v2.d.type) { + if (v1->d.type != v2->d.type) { // if conversion fails, default to toString - int r = v1.toString().compare(v2.toString(), Qt::CaseInsensitive); + int r = v1->toString().compare(v2->toString(), Qt::CaseInsensitive); if (r == 0) { // cmp(v) returned false, so we should try to agree with it. - return (v1.d.type < v2.d.type) ? -1 : 1; + return (v1->d.type < v2->d.type) ? -1 : 1; } return r; } // did we end up with two numerics? If so, restart - if (qIsNumericType(v1.d.type) && qIsNumericType(v2.d.type)) - return v1.compare(v2); + if (qIsNumericType(v1->d.type) && qIsNumericType(v2->d.type)) + return v1->compare(*v2); } - if (v1.d.type >= QMetaType::User) { + if (v1->d.type >= QMetaType::User) { int result; - if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(d)), QT_PREPEND_NAMESPACE(constData(v2.d)), d.type, &result)) + if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(d)), QT_PREPEND_NAMESPACE(constData(v2->d)), d.type, &result)) return result; } - switch (v1.d.type) { + switch (v1->d.type) { case QVariant::Date: - return v1.toDate() < v2.toDate() ? -1 : 1; + return v1->toDate() < v2->toDate() ? -1 : 1; case QVariant::Time: - return v1.toTime() < v2.toTime() ? -1 : 1; + return v1->toTime() < v2->toTime() ? -1 : 1; case QVariant::DateTime: - return v1.toDateTime() < v2.toDateTime() ? -1 : 1; + return v1->toDateTime() < v2->toDateTime() ? -1 : 1; case QVariant::StringList: - return v1.toStringList() < v2.toStringList() ? -1 : 1; + return v1->toStringList() < v2->toStringList() ? -1 : 1; } - int r = v1.toString().compare(v2.toString(), Qt::CaseInsensitive); + int r = v1->toString().compare(v2->toString(), Qt::CaseInsensitive); if (r == 0) { // cmp(v) returned false, so we should try to agree with it. return (d.type < v.d.type) ? -1 : 1; |