Compare QUniqueHandles using comparesEqual and compareThreeWay

This fixes an issue where comparing pointers to object is only defined
if both pointers point into the same array.

Task-number: QTBUG-132507
Pick-to: 6.8
Change-Id: Ib7ccb30001add38ad25b62c848a01cd53566d8bf
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 5dcdeeebbc08be8845cdb5a0e586b7a864b7f16f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Jøger Hansegård 2025-01-02 15:31:43 +01:00 committed by Qt Cherry-pick Bot
parent 3fa33cf1f1
commit 99d401220c
2 changed files with 53 additions and 23 deletions

View File

@ -17,6 +17,7 @@
#include <QtCore/qtconfigmacros.h>
#include <QtCore/qassert.h>
#include <QtCore/qcompare.h>
#include <QtCore/qswap.h>
#include <QtCore/qtclasshelpermacros.h>
@ -198,37 +199,24 @@ public:
m_handle = HandleTraits::invalidValue();
}
[[nodiscard]] friend bool operator==(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
private:
friend bool comparesEqual(const QUniqueHandle& lhs, const QUniqueHandle& rhs) noexcept
{
return lhs.get() == rhs.get();
}
[[nodiscard]] friend bool operator!=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
friend Qt::strong_ordering compareThreeWay(const QUniqueHandle& lhs,
const QUniqueHandle& rhs) noexcept
{
return lhs.get() != rhs.get();
if constexpr (std::is_pointer_v<Type>)
return qCompareThreeWay(Qt::totally_ordered_wrapper{ lhs.get() },
Qt::totally_ordered_wrapper{ rhs.get() });
else
return qCompareThreeWay(lhs.get(), rhs.get());
}
[[nodiscard]] friend bool operator<(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
{
return lhs.get() < rhs.get();
}
Q_DECLARE_STRONGLY_ORDERED(QUniqueHandle)
[[nodiscard]] friend bool operator<=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
{
return lhs.get() <= rhs.get();
}
[[nodiscard]] friend bool operator>(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
{
return lhs.get() > rhs.get();
}
[[nodiscard]] friend bool operator>=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
{
return lhs.get() >= rhs.get();
}
private:
Type m_handle{ HandleTraits::invalidValue() };
};

View File

@ -348,6 +348,48 @@ private slots:
QCOMPARE_EQ(Handle{ }, Handle{ });
}
void comparison_behavesAsPointer_whenHandleTypeIsPointer_data() const
{
QTest::addColumn<int*>("lhs");
QTest::addColumn<int*>("rhs");
QTest::addRow("lhs == rhs") << reinterpret_cast<int*>(2) << reinterpret_cast<int*>(2);
QTest::addRow("lhs < rhs") << reinterpret_cast<int*>(1) << reinterpret_cast<int*>(2);
QTest::addRow("lhs > rhs") << reinterpret_cast<int*>(2) << reinterpret_cast<int*>(1);
}
void comparison_behavesAsPointer_whenHandleTypeIsPointer() const
{
struct IntPtrTraits
{
using Type = int*;
static bool close(Type)
{
return true;
}
static Type invalidValue() noexcept
{
return nullptr;
}
};
using Handle = QUniqueHandle<IntPtrTraits>;
QFETCH(int*, lhs);
QFETCH(int*, rhs);
QCOMPARE_EQ(Handle{ lhs } == Handle{ rhs }, lhs == rhs);
QCOMPARE_EQ(Handle{ lhs } != Handle{ rhs }, lhs != rhs);
QCOMPARE_EQ(Handle{ lhs } < Handle{ rhs }, lhs < rhs);
QCOMPARE_EQ(Handle{ lhs } <= Handle{ rhs }, lhs <= rhs);
QCOMPARE_EQ(Handle{ lhs } > Handle{ rhs }, lhs > rhs);
QCOMPARE_EQ(Handle{ lhs } >= Handle{ rhs }, lhs >= rhs);
QCOMPARE_EQ(Handle{ }, Handle{ });
}
void sort_sortsHandles() const
{
const auto resource0 = GlobalResource::open();