From 37ac6b5e0e5dfc6fcd69a91f26e3fe34bf262a6b Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 28 Aug 2025 15:00:02 +1000 Subject: [PATCH] Correctly compare long long values --- src/core/qgis.cpp | 88 +++++++++++++++++++++++++++++++++++++ tests/src/core/testqgis.cpp | 51 +++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/src/core/qgis.cpp b/src/core/qgis.cpp index 84e26ae5722..7933bbb110d 100644 --- a/src/core/qgis.cpp +++ b/src/core/qgis.cpp @@ -169,6 +169,14 @@ int qgsVariantCompare( const QVariant &lhs, const QVariant &rhs, bool strictType return lhsInt < rhsInt ? -1 : ( lhsInt == rhsInt ? 0 : 1 ); } + case QMetaType::Type::Long: + case QMetaType::Type::LongLong: + { + const long long lhsInt = lhs.toLongLong(); + const long long rhsInt = rhs.toLongLong(); + return lhsInt < rhsInt ? -1 : ( lhsInt == rhsInt ? 0 : 1 ); + } + case QMetaType::Type::Double: case QMetaType::Type::Float: { @@ -223,6 +231,47 @@ int qgsVariantCompare( const QVariant &lhs, const QVariant &rhs, bool strictType return lhsUInt < rhsUInt ? -1 : ( lhsUInt == rhsUInt ? 0 : 1 ); } + case QMetaType::Type::ULong: + case QMetaType::Type::ULongLong: + { + const qulonglong lhsInt = lhs.toULongLong(); + const qulonglong rhsInt = rhs.toULongLong(); + return lhsInt < rhsInt ? -1 : ( lhsInt == rhsInt ? 0 : 1 ); + } + + case QMetaType::Type::Double: + case QMetaType::Type::Float: + { + const double lhsDouble = static_cast< double >( lhs.toUInt() ); + const double rhsDouble = rhs.toDouble(); + + // consider NaN < any non-NaN + const bool lhsIsNan = std::isnan( lhsDouble ); + const bool rhsIsNan = std::isnan( rhsDouble ); + if ( lhsIsNan ) + { + return rhsIsNan ? 0 : -1; + } + else if ( rhsIsNan ) + { + return 1; + } + + return lhsDouble < rhsDouble ? -1 : ( lhsDouble == rhsDouble ? 0 : 1 ); + } + + case QMetaType::Type::QString: + { + bool ok = false; + const double rhsDouble = rhs.toDouble( &ok ); + if ( ok ) + { + const double lhsDouble = static_cast< double >( lhs.toUInt() ); + return lhsDouble < rhsDouble ? -1 : ( lhsDouble == rhsDouble ? 0 : 1 ); + } + break; + } + default: break; } @@ -234,6 +283,9 @@ int qgsVariantCompare( const QVariant &lhs, const QVariant &rhs, bool strictType { switch ( rhs.userType() ) { + case QMetaType::Type::Int: + case QMetaType::Type::Char: + case QMetaType::Type::Short: case QMetaType::Type::LongLong: case QMetaType::Type::Long: { @@ -242,6 +294,39 @@ int qgsVariantCompare( const QVariant &lhs, const QVariant &rhs, bool strictType return lhsLongLong < rhsLongLong ? -1 : ( lhsLongLong == rhsLongLong ? 0 : 1 ); } + case QMetaType::Type::Double: + case QMetaType::Type::Float: + { + const double lhsDouble = static_cast< double >( lhs.toLongLong() ); + const double rhsDouble = rhs.toDouble(); + + // consider NaN < any non-NaN + const bool lhsIsNan = std::isnan( lhsDouble ); + const bool rhsIsNan = std::isnan( rhsDouble ); + if ( lhsIsNan ) + { + return rhsIsNan ? 0 : -1; + } + else if ( rhsIsNan ) + { + return 1; + } + + return lhsDouble < rhsDouble ? -1 : ( lhsDouble == rhsDouble ? 0 : 1 ); + } + + case QMetaType::Type::QString: + { + bool ok = false; + const double rhsDouble = rhs.toDouble( &ok ); + if ( ok ) + { + const double lhsDouble = static_cast< double >( lhs.toLongLong() ); + return lhsDouble < rhsDouble ? -1 : ( lhsDouble == rhsDouble ? 0 : 1 ); + } + break; + } + default: break; } @@ -253,6 +338,9 @@ int qgsVariantCompare( const QVariant &lhs, const QVariant &rhs, bool strictType { switch ( rhs.userType() ) { + case QMetaType::Type::UInt: + case QMetaType::Type::UChar: + case QMetaType::Type::UShort: case QMetaType::Type::ULongLong: case QMetaType::Type::ULong: { diff --git a/tests/src/core/testqgis.cpp b/tests/src/core/testqgis.cpp index 7d1cd5cbf89..708a0c26ebd 100644 --- a/tests/src/core/testqgis.cpp +++ b/tests/src/core/testqgis.cpp @@ -406,18 +406,49 @@ void TestQgis::qVariantCompare_data() QTest::newRow( "int vs float greater than truncation" ) << QVariant( -2 ) << QVariant( -2.1f ) << false << true << 1; QTest::newRow( "int vs float same" ) << QVariant( 1 ) << QVariant( 1.0f ) << false << false << 0; + QTest::newRow( "long long vs double less than" ) << QVariant( 1LL ) << QVariant( 2.0 ) << true << false << -1; + QTest::newRow( "long long vs double less than truncation" ) << QVariant( 1LL ) << QVariant( 1.1 ) << true << false << -1; + QTest::newRow( "long long vs double greater than" ) << QVariant( 2LL ) << QVariant( 1.0 ) << false << true << 1; + QTest::newRow( "long long vs double greater than truncation" ) << QVariant( -2LL ) << QVariant( -2.1 ) << false << true << 1; + QTest::newRow( "long long vs double same" ) << QVariant( 1LL ) << QVariant( 1.0 ) << false << false << 0; + + QTest::newRow( "long long vs float less than" ) << QVariant( 1LL ) << QVariant( 2.0f ) << true << false << -1; + QTest::newRow( "long long vs float less than truncation" ) << QVariant( 1LL ) << QVariant( 1.1f ) << true << false << -1; + QTest::newRow( "long long vs float greater than" ) << QVariant( 2LL ) << QVariant( 1.0f ) << false << true << 1; + QTest::newRow( "long long vs float greater than truncation" ) << QVariant( -2LL ) << QVariant( -2.1f ) << false << true << 1; + QTest::newRow( "long long vs float same" ) << QVariant( 1LL ) << QVariant( 1.0f ) << false << false << 0; + + QTest::newRow( "long long vs int less than" ) << QVariant( 1LL ) << QVariant( 2 ) << true << false << -1; + QTest::newRow( "long long vs int greater than" ) << QVariant( 2LL ) << QVariant( 1 ) << false << true << 1; + QTest::newRow( "long long vs int same" ) << QVariant( 1LL ) << QVariant( 1 ) << false << false << 0; + QTest::newRow( "int vs long long less than" ) << QVariant( 1 ) << QVariant( 2LL ) << true << false << -1; + QTest::newRow( "int vs long long greater than" ) << QVariant( 2 ) << QVariant( 1LL ) << false << true << 1; + QTest::newRow( "int vs long long same" ) << QVariant( 1 ) << QVariant( 1LL ) << false << false << 0; + QTest::newRow( "double vs int less than" ) << QVariant( 1.0 ) << QVariant( 2 ) << true << false << -1; QTest::newRow( "double vs int less than truncation" ) << QVariant( -2.1 ) << QVariant( -2 ) << true << false << -1; QTest::newRow( "double vs int greater than" ) << QVariant( 2.0 ) << QVariant( 1 ) << false << true << 1; QTest::newRow( "double vs int greater than truncation" ) << QVariant( 1.1 ) << QVariant( 1 ) << false << true << 1; QTest::newRow( "double vs int same" ) << QVariant( 1.0 ) << QVariant( 1 ) << false << false << 0; + QTest::newRow( "double vs long long less than" ) << QVariant( 1.0 ) << QVariant( 2LL ) << true << false << -1; + QTest::newRow( "double vs long long less than truncation" ) << QVariant( -2.1 ) << QVariant( -2LL ) << true << false << -1; + QTest::newRow( "double vs long long greater than" ) << QVariant( 2.0 ) << QVariant( 1LL ) << false << true << 1; + QTest::newRow( "double vs long long greater than truncation" ) << QVariant( 1.1 ) << QVariant( 1LL ) << false << true << 1; + QTest::newRow( "double vs long long same" ) << QVariant( 1.0 ) << QVariant( 1LL ) << false << false << 0; + QTest::newRow( "float vs int less than" ) << QVariant( 1.0f ) << QVariant( 2 ) << true << false << -1; QTest::newRow( "float vs int less than truncation" ) << QVariant( -2.1f ) << QVariant( -2 ) << true << false << -1; QTest::newRow( "float vs int greater than" ) << QVariant( 2.0f ) << QVariant( 1 ) << false << true << 1; QTest::newRow( "float vs int greater than truncation" ) << QVariant( 1.1f ) << QVariant( 1 ) << false << true << 1; QTest::newRow( "float vs int same" ) << QVariant( 1.0f ) << QVariant( 1 ) << false << false << 0; + QTest::newRow( "float vs long long less than" ) << QVariant( 1.0f ) << QVariant( 2LL ) << true << false << -1; + QTest::newRow( "float vs long long less than truncation" ) << QVariant( -2.1f ) << QVariant( -2LL ) << true << false << -1; + QTest::newRow( "float vs long long greater than" ) << QVariant( 2.0f ) << QVariant( 1LL ) << false << true << 1; + QTest::newRow( "float vs long long greater than truncation" ) << QVariant( 1.1f ) << QVariant( 1LL ) << false << true << 1; + QTest::newRow( "float vs long long same" ) << QVariant( 1.0f ) << QVariant( 1LL ) << false << false << 0; + QTest::newRow( "int vs string less than" ) << QVariant( 1 ) << QVariant( "2" ) << true << false << -1; QTest::newRow( "int vs string greater than" ) << QVariant( 2 ) << QVariant( "1" ) << false << true << 1; QTest::newRow( "int vs string same" ) << QVariant( 2 ) << QVariant( "2" ) << false << false << 0; @@ -426,11 +457,24 @@ void TestQgis::qVariantCompare_data() QTest::newRow( "int 0 vs string non numeric" ) << QVariant( 0 ) << QVariant( "aaaa" ) << true << false << -1; QTest::newRow( "non numeric string vs int 0" ) << QVariant( "abc" ) << QVariant( 0 ) << false << true << 1; + QTest::newRow( "long long vs string less than" ) << QVariant( 1LL ) << QVariant( "2" ) << true << false << -1; + QTest::newRow( "long long vs string greater than" ) << QVariant( 2LL ) << QVariant( "1" ) << false << true << 1; + QTest::newRow( "long long vs string same" ) << QVariant( 2LL ) << QVariant( "2" ) << false << false << 0; + QTest::newRow( "long long vs string non numeric" ) << QVariant( 2LL ) << QVariant( "aaaa" ) << true << false << -1; + QTest::newRow( "non numeric string vs long long" ) << QVariant( "abc" ) << QVariant( 2LL ) << false << true << 1; + QTest::newRow( "long long 0 vs string non numeric" ) << QVariant( 0LL ) << QVariant( "aaaa" ) << true << false << -1; + QTest::newRow( "non numeric string vs long long 0" ) << QVariant( "abc" ) << QVariant( 0LL ) << false << true << 1; + QTest::newRow( "int vs double string less than" ) << QVariant( 1 ) << QVariant( "2.0" ) << true << false << -1; QTest::newRow( "int vs double string less than truncation" ) << QVariant( 1 ) << QVariant( "1.1" ) << true << false << -1; QTest::newRow( "int vs double string greater than" ) << QVariant( 2 ) << QVariant( "1.0" ) << false << true << 1; QTest::newRow( "int vs double string greater than truncation" ) << QVariant( -2 ) << QVariant( "-2.1" ) << false << true << 1; QTest::newRow( "int vs double string same" ) << QVariant( 2 ) << QVariant( "2.0" ) << false << false << 0; + QTest::newRow( "long long vs double string less than" ) << QVariant( 1LL ) << QVariant( "2.0" ) << true << false << -1; + QTest::newRow( "long long vs double string less than truncation" ) << QVariant( 1LL ) << QVariant( "1.1" ) << true << false << -1; + QTest::newRow( "long long vs double string greater than" ) << QVariant( 2LL ) << QVariant( "1.0" ) << false << true << 1; + QTest::newRow( "long long vs double string greater than truncation" ) << QVariant( -2LL ) << QVariant( "-2.1" ) << false << true << 1; + QTest::newRow( "long long vs double string same" ) << QVariant( 2LL ) << QVariant( "2.0" ) << false << false << 0; QTest::newRow( "double vs non numeric string" ) << QVariant( 2.1 ) << QVariant( "abc" ) << true << false << -1; QTest::newRow( "double 0 vs non numeric string" ) << QVariant( 0 ) << QVariant( "abc" ) << true << false << -1; QTest::newRow( "non numeric string vs double" ) << QVariant( "abc" ) << QVariant( 2.0 ) << false << true << 1; @@ -445,6 +489,13 @@ void TestQgis::qVariantCompare_data() QTest::newRow( "string vs int same" ) << QVariant( "2" ) << QVariant( 2 ) << false << false << 0; QTest::newRow( "string double vs int same" ) << QVariant( "2.0" ) << QVariant( 2 ) << false << false << 0; + QTest::newRow( "string vs long long less than" ) << QVariant( "1" ) << QVariant( 2LL ) << true << false << -1; + QTest::newRow( "string vs long long less than truncation" ) << QVariant( "-2.1" ) << QVariant( -2LL ) << true << false << -1; + QTest::newRow( "string vs long long greater than" ) << QVariant( "2" ) << QVariant( 1LL ) << false << true << 1; + QTest::newRow( "string vs long long greater than truncation" ) << QVariant( "2.1" ) << QVariant( 2LL ) << false << true << 1; + QTest::newRow( "string vs long long same" ) << QVariant( "2" ) << QVariant( 2LL ) << false << false << 0; + QTest::newRow( "string double vs long long same" ) << QVariant( "2.0" ) << QVariant( 2LL ) << false << false << 0; + QTest::newRow( "string vs double same" ) << QVariant( "2" ) << QVariant( 2.0 ) << false << false << 0; QTest::newRow( "string vs double less than" ) << QVariant( "1" ) << QVariant( 2.0 ) << true << false << -1; QTest::newRow( "string vs double less than truncation" ) << QVariant( "1" ) << QVariant( 1.1 ) << true << false << -1;