QArrayDataOps: fix FP equality comparison
We cannot use memcmp() for that, as it incorrectly results in two NaN values being equal. Simply replace the whole self-written algorithm with std::equal(), as it's doing the same thing, but lets the compiler decide when to do the optimizations. Amends db89349bdba2fcc03b2f7e2d23f549a9ec5dc0e3. [ChangeLog][QtCore][QList] Fixed a bug when two QLists holding NaN values were considered to be equal. Fixes: QTBUG-127473 Pick-to: 6.7 6.5 6.2 Change-Id: If7e77549b4cbeb96711893d14344b9e0a40c1a87 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit cb3faeba3d9411ba82c311751bd7de36d0fec939) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
7a31702345
commit
f53074c747
@ -272,23 +272,8 @@ public:
|
|||||||
|
|
||||||
bool compare(const T *begin1, const T *begin2, size_t n) const
|
bool compare(const T *begin1, const T *begin2, size_t n) const
|
||||||
{
|
{
|
||||||
// only use memcmp for fundamental types or pointers.
|
|
||||||
// Other types could have padding in the data structure or custom comparison
|
|
||||||
// operators that would break the comparison using memcmp
|
|
||||||
if constexpr (QArrayDataPointer<T>::pass_parameter_by_value) {
|
|
||||||
return ::memcmp(begin1, begin2, n * sizeof(T)) == 0;
|
|
||||||
} else {
|
|
||||||
const T *end1 = begin1 + n;
|
const T *end1 = begin1 + n;
|
||||||
while (begin1 != end1) {
|
return std::equal(begin1, end1, begin2);
|
||||||
if (*begin1 == *begin2) {
|
|
||||||
++begin1;
|
|
||||||
++begin2;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
|
void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
|
||||||
@ -665,15 +650,7 @@ public:
|
|||||||
bool compare(const T *begin1, const T *begin2, size_t n) const
|
bool compare(const T *begin1, const T *begin2, size_t n) const
|
||||||
{
|
{
|
||||||
const T *end1 = begin1 + n;
|
const T *end1 = begin1 + n;
|
||||||
while (begin1 != end1) {
|
return std::equal(begin1, end1, begin2);
|
||||||
if (*begin1 == *begin2) {
|
|
||||||
++begin1;
|
|
||||||
++begin2;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -429,6 +429,21 @@ private Q_SLOTS:
|
|||||||
void keyValueRange_QMultiMap() { keyValueRange_impl<QMultiMap<int, int>>(); }
|
void keyValueRange_QMultiMap() { keyValueRange_impl<QMultiMap<int, int>>(); }
|
||||||
void keyValueRange_QHash() { keyValueRange_impl<QHash<int, int>>(); }
|
void keyValueRange_QHash() { keyValueRange_impl<QHash<int, int>>(); }
|
||||||
void keyValueRange_QMultiHash() { keyValueRange_impl<QMultiHash<int, int>>(); }
|
void keyValueRange_QMultiHash() { keyValueRange_impl<QMultiHash<int, int>>(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Container>
|
||||||
|
void opEqNaN_impl() const;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void opEqNaN_QList_Float() { opEqNaN_impl<QList<float>>(); }
|
||||||
|
void opEqNaN_QList_Float16() { opEqNaN_impl<QList<qfloat16>>(); }
|
||||||
|
void opEqNaN_QList_Double() { opEqNaN_impl<QList<double>>(); }
|
||||||
|
void opEqNaN_QVarLengthArray_Float() { opEqNaN_impl<QVarLengthArray<float>>(); }
|
||||||
|
void opEqNaN_QVarLengthArray_Float16() { opEqNaN_impl<QVarLengthArray<qfloat16>>(); }
|
||||||
|
void opEqNaN_QVarLengthArray_Double() { opEqNaN_impl<QVarLengthArray<double>>(); }
|
||||||
|
void opEqNaN_QSet_Float() { opEqNaN_impl<QSet<float>>(); }
|
||||||
|
void opEqNaN_QSet_Float16() { opEqNaN_impl<QSet<qfloat16>>(); }
|
||||||
|
void opEqNaN_QSet_Double() { opEqNaN_impl<QSet<double>>(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_ContainerApiSymmetry::init()
|
void tst_ContainerApiSymmetry::init()
|
||||||
@ -1263,5 +1278,16 @@ void tst_ContainerApiSymmetry::keyValueRange_impl() const
|
|||||||
QVERIFY(verify(values, COUNT, 2));
|
QVERIFY(verify(values, COUNT, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
void tst_ContainerApiSymmetry::opEqNaN_impl() const
|
||||||
|
{
|
||||||
|
using V = typename Container::value_type;
|
||||||
|
static_assert(std::is_floating_point_v<V> || std::is_same_v<V, qfloat16>);
|
||||||
|
const Container lhs {std::numeric_limits<V>::quiet_NaN()};
|
||||||
|
const Container rhs {std::numeric_limits<V>::quiet_NaN()};
|
||||||
|
|
||||||
|
QCOMPARE_NE(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_APPLESS_MAIN(tst_ContainerApiSymmetry)
|
QTEST_APPLESS_MAIN(tst_ContainerApiSymmetry)
|
||||||
#include "tst_containerapisymmetry.moc"
|
#include "tst_containerapisymmetry.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user