Add QtOrderingPrivate::lexicographicalCompareThreeWay
This function should behave similarly to std::lexicographical_compare_three_way, but be available in C++17. It is required at least to properly implement the compareThreeWay() helper function for Qt container types. The function requires that the contained types of the compared ranges provide a compareThreeWay() helper function. Similarly to std implementation, this patch also adds an overload that takes a custom comparator object. For now the functions are added in a private namespace, because they are only required to implement relational operators on Qt containers. We might want to expose them as public API later, if needed. Task-number: QTBUG-127095 Task-number: QTBUG-120305 Change-Id: I5b29129905b2e801ae7e470c96a7ef71e7b210d6 Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
parent
fc947593ef
commit
2f8f274cae
@ -1563,6 +1563,42 @@ CHECK(strong, equivalent);
|
||||
\sa Qt::partial_ordering, Qt::weak_ordering, Qt::strong_ordering
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename InputIt1, typename InputIt2> QtOrderingPrivate::lexicographicalCompareThreeWay(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
|
||||
\internal
|
||||
\relates <QtCompare>
|
||||
|
||||
\brief Three-way lexicographic comparison of ranges.
|
||||
|
||||
Checks how the range [ \a first1, \a last1 ) compares to the second range
|
||||
[ \a first2, \a last2 ) and produces a result of the strongest applicable
|
||||
category type.
|
||||
|
||||
This function can only be used if \c InputIt1::value_type and
|
||||
\c InputIt2::value_type types provide a \c {compareThreeWay()} helper method
|
||||
that returns one of the Qt ordering types.
|
||||
|
||||
\sa {Comparison types overview}
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename InputIt1, typename InputIt2, typename Comparator> QtOrderingPrivate::lexicographicalCompareThreeWay(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Comparator cmp)
|
||||
\internal
|
||||
\relates <QtCompare>
|
||||
\overload
|
||||
|
||||
This overload takes a custom \c Comparator that is used to do the comparison.
|
||||
The comparator should have the following signature:
|
||||
|
||||
\badcode
|
||||
OrderingType cmp(const InputIt1::value_type &lhs, const InputIt2::value_type &rhs);
|
||||
\endcode
|
||||
|
||||
where \c OrderingType is one of the Qt ordering types.
|
||||
|
||||
\sa {Comparison types overview}
|
||||
*/
|
||||
|
||||
/*!
|
||||
\class Qt::totally_ordered_wrapper
|
||||
\inmodule QtCore
|
||||
|
@ -1195,6 +1195,9 @@ namespace CompareThreeWayTester {
|
||||
|
||||
using Qt::compareThreeWay;
|
||||
|
||||
template <typename T>
|
||||
using WrappedType = std::conditional_t<std::is_pointer_v<T>, Qt::totally_ordered_wrapper<T>, T>;
|
||||
|
||||
// Check if compareThreeWay is implemented for the (LT, RT) argument
|
||||
// pair.
|
||||
template <typename LT, typename RT, typename = void>
|
||||
@ -1205,6 +1208,13 @@ constexpr inline bool hasCompareThreeWay<
|
||||
LT, RT, std::void_t<decltype(compareThreeWay(std::declval<LT>(), std::declval<RT>()))>
|
||||
> = true;
|
||||
|
||||
template <typename LT, typename RT>
|
||||
constexpr inline bool hasCompareThreeWay<
|
||||
LT*, RT*,
|
||||
std::void_t<decltype(compareThreeWay(std::declval<WrappedType<LT>>(),
|
||||
std::declval<WrappedType<RT>>()))>
|
||||
> = true;
|
||||
|
||||
// Check if the operation is noexcept. We have two different overloads,
|
||||
// depending on the available compareThreeWay() implementation.
|
||||
// Both are declared, but not implemented. To be used only in unevaluated
|
||||
@ -1223,8 +1233,86 @@ constexpr bool compareThreeWayNoexcept() noexcept
|
||||
|
||||
} // namespace CompareThreeWayTester
|
||||
|
||||
// These checks do not use Qt::compareThreeWay(), so only work for user-defined
|
||||
// compareThreeWay() helper functions.
|
||||
// We cannot use the same condition as in CompareThreeWayTester::hasCompareThreeWay,
|
||||
// because GCC seems to cache and re-use the result.
|
||||
// Created https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117174
|
||||
// For now, modify the condition a bit without changing its meaning.
|
||||
template <typename LT, typename RT = LT, typename = void>
|
||||
struct HasCustomCompareThreeWay : std::false_type {};
|
||||
|
||||
template <typename LT, typename RT>
|
||||
struct HasCustomCompareThreeWay<
|
||||
LT, RT,
|
||||
std::void_t<decltype(is_eq(compareThreeWay(std::declval<LT>(), std::declval<RT>())))>
|
||||
> : std::true_type {};
|
||||
|
||||
template <typename InputIt1, typename InputIt2, typename Compare>
|
||||
auto lexicographicalCompareThreeWay(InputIt1 first1, InputIt1 last1,
|
||||
InputIt2 first2, InputIt2 last2,
|
||||
Compare cmp)
|
||||
{
|
||||
using R = decltype(cmp(*first1, *first2));
|
||||
|
||||
while (first1 != last1) {
|
||||
if (first2 == last2)
|
||||
return R::greater;
|
||||
const auto r = cmp(*first1, *first2);
|
||||
if (is_neq(r))
|
||||
return r;
|
||||
++first1;
|
||||
++first2;
|
||||
}
|
||||
return first2 == last2 ? R::equivalent : R::less;
|
||||
}
|
||||
|
||||
template <typename InputIt1, typename InputIt2>
|
||||
auto lexicographicalCompareThreeWay(InputIt1 first1, InputIt1 last1,
|
||||
InputIt2 first2, InputIt2 last2)
|
||||
{
|
||||
using LT = typename std::iterator_traits<InputIt1>::value_type;
|
||||
using RT = typename std::iterator_traits<InputIt2>::value_type;
|
||||
|
||||
// if LT && RT are pointers, and there is no user-defined compareThreeWay()
|
||||
// operation for the pointers, we need to wrap them into
|
||||
// Qt::totally_ordered_wrapper.
|
||||
constexpr bool UseWrapper =
|
||||
std::conjunction_v<std::is_pointer<LT>, std::is_pointer<RT>,
|
||||
std::negation<HasCustomCompareThreeWay<LT, RT>>,
|
||||
std::negation<HasCustomCompareThreeWay<RT, LT>>>;
|
||||
using WrapLT = std::conditional_t<UseWrapper,
|
||||
Qt::totally_ordered_wrapper<LT>,
|
||||
const LT &>;
|
||||
using WrapRT = std::conditional_t<UseWrapper,
|
||||
Qt::totally_ordered_wrapper<RT>,
|
||||
const RT &>;
|
||||
|
||||
auto cmp = [](LT const &lhs, RT const &rhs) {
|
||||
using Qt::compareThreeWay;
|
||||
namespace Test = QtOrderingPrivate::CompareThreeWayTester;
|
||||
// Need this because the user might provide only
|
||||
// compareThreeWay(LT, RT), but not the reversed version.
|
||||
if constexpr (Test::hasCompareThreeWay<WrapLT, WrapRT>)
|
||||
return compareThreeWay(WrapLT(lhs), WrapRT(rhs));
|
||||
else
|
||||
return QtOrderingPrivate::reversed(compareThreeWay(WrapRT(rhs), WrapLT(lhs)));
|
||||
};
|
||||
return lexicographicalCompareThreeWay(first1, last1, first2, last2, cmp);
|
||||
}
|
||||
|
||||
} // namespace QtOrderingPrivate
|
||||
|
||||
namespace Qt {
|
||||
|
||||
template <typename T, typename U>
|
||||
using if_has_qt_compare_three_way =
|
||||
std::enable_if_t<QtOrderingPrivate::CompareThreeWayTester::hasCompareThreeWay<T, U>
|
||||
|| QtOrderingPrivate::CompareThreeWayTester::hasCompareThreeWay<U, T>,
|
||||
bool>;
|
||||
|
||||
} // namespace Qt
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace std {
|
||||
|
@ -66,6 +66,42 @@ private Q_SLOTS:
|
||||
void totallyOrderedWrapperBasics();
|
||||
|
||||
void compareAutoReturnType();
|
||||
|
||||
private:
|
||||
template <typename LeftType, typename RightType, typename OrderingType>
|
||||
void lexicographicalCompareThreeWayDataImpl();
|
||||
|
||||
template <typename LeftType, typename RightType, typename OrderingType>
|
||||
void lexicographicalCompareThreeWayImpl();
|
||||
|
||||
template <typename LeftType, typename RightType, typename OrderingType>
|
||||
void lexicographicalCompareThreeWayComparatorImpl();
|
||||
|
||||
private slots:
|
||||
void lexicographicalCompareThreeWay_ThreeWayCmp_Int_data();
|
||||
void lexicographicalCompareThreeWay_ThreeWayCmp_Int();
|
||||
void lexicographicalCompareThreeWay_ThreeWayCmp_Float_data();
|
||||
void lexicographicalCompareThreeWay_ThreeWayCmp_Float();
|
||||
void lexicographicalCompareThreeWay_ThreeWayCmp_Weak_data();
|
||||
void lexicographicalCompareThreeWay_ThreeWayCmp_Weak();
|
||||
|
||||
void lexicographicalCompareThreeWay_Mixed_Int_data();
|
||||
void lexicographicalCompareThreeWay_Mixed_Int();
|
||||
void lexicographicalCompareThreeWay_Mixed_Float_data();
|
||||
void lexicographicalCompareThreeWay_Mixed_Float();
|
||||
void lexicographicalCompareThreeWay_Mixed_Weak_data();
|
||||
void lexicographicalCompareThreeWay_Mixed_Weak();
|
||||
|
||||
void lexicographicalCompareThreeWay_Comparator_Int_data();
|
||||
void lexicographicalCompareThreeWay_Comparator_Int();
|
||||
void lexicographicalCompareThreeWay_Comparator_Float_data();
|
||||
void lexicographicalCompareThreeWay_Comparator_Float();
|
||||
void lexicographicalCompareThreeWay_Comparator_Weak_data();
|
||||
void lexicographicalCompareThreeWay_Comparator_Weak();
|
||||
|
||||
void lexicographicalCompareThreeWay_Pointers();
|
||||
void lexicographicalCompareThreeWay_NonCopyMove();
|
||||
void lexicographicalCompareThreeWay_CustomPointerHelper();
|
||||
};
|
||||
|
||||
#endif // TST_QCOMPAREHELPERS_H
|
||||
|
@ -198,3 +198,409 @@ void tst_QCompareHelpers::compareAutoReturnType()
|
||||
QTestPrivate::testAllComparisonOperatorsCompile<WeakT>();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class LessOnly
|
||||
{
|
||||
public:
|
||||
using Type = T;
|
||||
|
||||
LessOnly(T v) : val(v) {}
|
||||
T value() const { return val; }
|
||||
private:
|
||||
friend bool operator<(LessOnly lhs, LessOnly rhs)
|
||||
{ return lhs.val < rhs.val; }
|
||||
|
||||
T val;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ThreeWayCmp
|
||||
{
|
||||
public:
|
||||
using Type = T;
|
||||
|
||||
ThreeWayCmp(T v) : val(v) {}
|
||||
private:
|
||||
template <typename U = T>
|
||||
friend bool operator==(ThreeWayCmp lhs, ThreeWayCmp rhs)
|
||||
{ return lhs.val == rhs.val; }
|
||||
template <typename U = T>
|
||||
friend bool operator==(ThreeWayCmp lhs, LessOnly<U> rhs)
|
||||
{ return lhs.val == rhs.value(); }
|
||||
template <typename U = T>
|
||||
friend auto compareThreeWay(ThreeWayCmp lhs, ThreeWayCmp rhs)
|
||||
{
|
||||
using Qt::compareThreeWay;
|
||||
return compareThreeWay(lhs.val, rhs.val);
|
||||
}
|
||||
template <typename U = T>
|
||||
friend auto compareThreeWay(ThreeWayCmp lhs, LessOnly<U> rhs)
|
||||
{
|
||||
using Qt::compareThreeWay;
|
||||
return compareThreeWay(lhs.val, rhs.value());
|
||||
}
|
||||
|
||||
T val;
|
||||
};
|
||||
|
||||
// A dummy int-based class to implement weak ordering
|
||||
struct Weak
|
||||
{
|
||||
int val;
|
||||
private:
|
||||
friend constexpr bool comparesEqual(Weak lhs, Weak rhs) noexcept
|
||||
{ return lhs.val == rhs.val; }
|
||||
friend constexpr Qt::weak_ordering compareThreeWay(Weak lhs, Weak rhs) noexcept
|
||||
{
|
||||
const auto r = Qt::compareThreeWay(lhs.val, rhs.val);
|
||||
return Qt::weak_ordering{r};
|
||||
}
|
||||
Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(Weak)
|
||||
};
|
||||
|
||||
template <typename LeftType, typename RightType, typename OrderingType>
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWayDataImpl()
|
||||
{
|
||||
QTest::addColumn<QList<LeftType>>("lhs");
|
||||
QTest::addColumn<QList<RightType>>("rhs");
|
||||
QTest::addColumn<OrderingType>("expectedResult");
|
||||
|
||||
using LT = typename LeftType::Type;
|
||||
using RT = typename RightType::Type;
|
||||
|
||||
constexpr bool HasOnlyOpLess = std::is_same_v<LeftType, LessOnly<LT>>
|
||||
&& std::is_same_v<RightType, LessOnly<RT>>;
|
||||
|
||||
if constexpr (!HasOnlyOpLess)
|
||||
static_assert(std::is_same_v<Qt::if_has_qt_compare_three_way<LeftType, RightType>, bool>);
|
||||
|
||||
QTest::addRow("empty")
|
||||
<< QList<LeftType>{}
|
||||
<< QList<RightType>{}
|
||||
<< OrderingType::equivalent;
|
||||
QTest::addRow("same_length_equal")
|
||||
<< QList<LeftType>{LT{1}, LT{2}, LT{3}}
|
||||
<< QList<RightType>{RT{1}, RT{2}, RT{3}}
|
||||
<< OrderingType::equivalent;
|
||||
QTest::addRow("greater_val")
|
||||
<< QList<LeftType>{LT{1}, LT{3}, LT{2}}
|
||||
<< QList<RightType>{RT{1}, RT{2}, RT{3}, RT{4}}
|
||||
<< OrderingType::greater;
|
||||
QTest::addRow("less_val")
|
||||
<< QList<LeftType>{LT{1}, LT{2}, LT{3}, LT{4}}
|
||||
<< QList<RightType>{RT{1}, RT{3}, RT{2}}
|
||||
<< OrderingType::less;
|
||||
QTest::addRow("greater_length")
|
||||
<< QList<LeftType>{LT{1}, LT{2}, LT{3}}
|
||||
<< QList<RightType>{RT{1}, RT{2}}
|
||||
<< OrderingType::greater;
|
||||
QTest::addRow("less_length")
|
||||
<< QList<LeftType>{LT{1}, LT{2}, LT{3}}
|
||||
<< QList<RightType>{RT{1}, RT{2}, RT{3}, RT{4}}
|
||||
<< OrderingType::less;
|
||||
|
||||
if constexpr (!HasOnlyOpLess && std::is_same_v<OrderingType, Qt::partial_ordering>) {
|
||||
const float nan = std::numeric_limits<float>::quiet_NaN();
|
||||
QTest::addRow("unordered")
|
||||
<< QList<LeftType>{LT{nan}, LT{2}, LT{3}}
|
||||
<< QList<RightType>{RT{1}, RT{2}, RT{3}}
|
||||
<< OrderingType::unordered;
|
||||
QTest::addRow("unordered_start_with_nan")
|
||||
<< QList<LeftType>{LT{nan}, LT{2}, LT{3}}
|
||||
<< QList<RightType>{RT{nan}, RT{3}, RT{2}}
|
||||
<< OrderingType::unordered;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LeftType, typename RightType, typename OrderingType>
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWayImpl()
|
||||
{
|
||||
QFETCH(const QList<LeftType>, lhs);
|
||||
QFETCH(const QList<RightType>, rhs);
|
||||
QFETCH(const OrderingType, expectedResult);
|
||||
|
||||
const auto res =
|
||||
QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end());
|
||||
QCOMPARE_EQ(res, expectedResult);
|
||||
|
||||
// check the C-style arrays as well
|
||||
const auto rawRes =
|
||||
QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.data(), lhs.data() + lhs.size(),
|
||||
rhs.data(), rhs.data() + rhs.size());
|
||||
QCOMPARE_EQ(rawRes, expectedResult);
|
||||
}
|
||||
|
||||
template <typename LT, typename RT = LT>
|
||||
Qt::strong_ordering lessOnlyCmp(LT const &lhs, RT const &rhs)
|
||||
{
|
||||
if (std::less<>{}(lhs, rhs))
|
||||
return Qt::strong_ordering::less;
|
||||
if (std::less<>{}(rhs, lhs))
|
||||
return Qt::strong_ordering::greater;
|
||||
return Qt::strong_ordering::equivalent;
|
||||
}
|
||||
|
||||
template <typename LeftType, typename RightType, typename OrderingType>
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWayComparatorImpl()
|
||||
{
|
||||
QFETCH(const QList<LeftType>, lhs);
|
||||
QFETCH(const QList<RightType>, rhs);
|
||||
QFETCH(const OrderingType, expectedResult);
|
||||
|
||||
// free function
|
||||
{
|
||||
const auto res =
|
||||
QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end(),
|
||||
lessOnlyCmp<LeftType, RightType>);
|
||||
QCOMPARE_EQ(res, expectedResult);
|
||||
|
||||
// check the C-style arrays as well
|
||||
const auto rawRes =
|
||||
QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.data(), lhs.data() + lhs.size(),
|
||||
rhs.data(), rhs.data() + rhs.size(),
|
||||
lessOnlyCmp<LeftType, RightType>);
|
||||
QCOMPARE_EQ(rawRes, expectedResult);
|
||||
}
|
||||
// lambda
|
||||
{
|
||||
auto cmp = [](LeftType const &lhs, RightType const &rhs) {
|
||||
return lessOnlyCmp(lhs, rhs);
|
||||
};
|
||||
const auto res =
|
||||
QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end(),
|
||||
cmp);
|
||||
QCOMPARE_EQ(res, expectedResult);
|
||||
|
||||
// check the C-style arrays as well
|
||||
const auto rawRes =
|
||||
QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.data(), lhs.data() + lhs.size(),
|
||||
rhs.data(), rhs.data() + rhs.size(),
|
||||
std::move(cmp));
|
||||
QCOMPARE_EQ(rawRes, expectedResult);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_ThreeWayCmp_Int_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<ThreeWayCmp<int>, ThreeWayCmp<int>,
|
||||
Qt::strong_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_ThreeWayCmp_Int()
|
||||
{
|
||||
lexicographicalCompareThreeWayImpl<ThreeWayCmp<int>, ThreeWayCmp<int>,
|
||||
Qt::strong_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_ThreeWayCmp_Float_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<ThreeWayCmp<float>, ThreeWayCmp<float>,
|
||||
Qt::partial_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_ThreeWayCmp_Float()
|
||||
{
|
||||
lexicographicalCompareThreeWayImpl<ThreeWayCmp<float>, ThreeWayCmp<float>,
|
||||
Qt::partial_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_ThreeWayCmp_Weak_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<ThreeWayCmp<Weak>, ThreeWayCmp<Weak>,
|
||||
Qt::weak_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_ThreeWayCmp_Weak()
|
||||
{
|
||||
lexicographicalCompareThreeWayImpl<ThreeWayCmp<Weak>, ThreeWayCmp<Weak>,
|
||||
Qt::weak_ordering>();
|
||||
}
|
||||
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Mixed_Int_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<LessOnly<int>, ThreeWayCmp<int>,
|
||||
Qt::strong_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Mixed_Int()
|
||||
{
|
||||
lexicographicalCompareThreeWayImpl<LessOnly<int>, ThreeWayCmp<int>,
|
||||
Qt::strong_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Mixed_Float_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<LessOnly<float>, ThreeWayCmp<float>,
|
||||
Qt::partial_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Mixed_Float()
|
||||
{
|
||||
lexicographicalCompareThreeWayImpl<LessOnly<float>, ThreeWayCmp<float>,
|
||||
Qt::partial_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Mixed_Weak_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<LessOnly<Weak>, ThreeWayCmp<Weak>,
|
||||
Qt::weak_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Mixed_Weak()
|
||||
{
|
||||
lexicographicalCompareThreeWayImpl<LessOnly<Weak>, ThreeWayCmp<Weak>,
|
||||
Qt::weak_ordering>();
|
||||
}
|
||||
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Comparator_Int_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<LessOnly<int>, LessOnly<int>, Qt::strong_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Comparator_Int()
|
||||
{
|
||||
lexicographicalCompareThreeWayComparatorImpl<LessOnly<int>, LessOnly<int>,
|
||||
Qt::strong_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Comparator_Float_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<LessOnly<float>, LessOnly<float>,
|
||||
Qt::partial_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Comparator_Float()
|
||||
{
|
||||
lexicographicalCompareThreeWayComparatorImpl<LessOnly<float>, LessOnly<float>,
|
||||
Qt::partial_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Comparator_Weak_data()
|
||||
{
|
||||
lexicographicalCompareThreeWayDataImpl<LessOnly<Weak>, LessOnly<Weak>, Qt::weak_ordering>();
|
||||
}
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Comparator_Weak()
|
||||
{
|
||||
lexicographicalCompareThreeWayComparatorImpl<LessOnly<Weak>, LessOnly<Weak>,
|
||||
Qt::weak_ordering>();
|
||||
}
|
||||
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_Pointers()
|
||||
{
|
||||
constexpr std::array<int, 3> a = {42, 0, 17}; // the actual values do not matter
|
||||
|
||||
{
|
||||
const QList<const int*> lhs{&a[0], &a[1], &a[2]};
|
||||
const QList<const int*> rhs{&a[0], &a[1], &a[2]};
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end());
|
||||
QCOMPARE_EQ(res, Qt::strong_ordering::equivalent);
|
||||
}
|
||||
{
|
||||
const QList<const int*> lhs{&a[0], &a[1], &a[2]};
|
||||
const QList<const int*> rhs{&a[0], &a[2]};
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end());
|
||||
QCOMPARE_EQ(res, Qt::strong_ordering::less);
|
||||
}
|
||||
{
|
||||
const QList<const int*> lhs{&a[0], &a[2], &a[1]};
|
||||
const QList<const int*> rhs{&a[0], &a[1], &a[2]};
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end());
|
||||
QCOMPARE_EQ(res, Qt::strong_ordering::greater);
|
||||
}
|
||||
{
|
||||
const QList<const int*> lhs{&a[0], &a[1], &a[2], &a[0]};
|
||||
const QList<const int*> rhs{&a[0], &a[1], &a[2]};
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end());
|
||||
QCOMPARE_EQ(res, Qt::strong_ordering::greater);
|
||||
}
|
||||
}
|
||||
|
||||
struct NonCopyMove
|
||||
{
|
||||
float val;
|
||||
|
||||
constexpr NonCopyMove(float f) : val(f) {}
|
||||
Q_DISABLE_COPY_MOVE(NonCopyMove)
|
||||
|
||||
private:
|
||||
friend auto compareThreeWay(const NonCopyMove &lhs, const NonCopyMove &rhs)
|
||||
{
|
||||
return Qt::compareThreeWay(lhs.val, rhs.val);
|
||||
}
|
||||
};
|
||||
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_NonCopyMove()
|
||||
{
|
||||
constexpr std::array a1 = {NonCopyMove{1.f}, NonCopyMove{2.f}, NonCopyMove{3.f}};
|
||||
constexpr std::array a2 = {NonCopyMove{1.f}, NonCopyMove{3.f}, NonCopyMove{2.f}};
|
||||
constexpr std::array a3 = {NonCopyMove{std::numeric_limits<float>::quiet_NaN()},
|
||||
NonCopyMove{2.f}, NonCopyMove{3.f}};
|
||||
|
||||
{
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(a1.begin(), a1.end(),
|
||||
a1.begin(), a1.end());
|
||||
QCOMPARE_EQ(res, Qt::partial_ordering::equivalent);
|
||||
}
|
||||
{
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(a1.begin(), a1.end(),
|
||||
a2.begin(), a2.end());
|
||||
QCOMPARE_EQ(res, Qt::partial_ordering::less);
|
||||
}
|
||||
{
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(a2.begin(), a2.end(),
|
||||
a1.begin(), a1.end());
|
||||
QCOMPARE_EQ(res, Qt::partial_ordering::greater);
|
||||
}
|
||||
{
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(a1.begin(), a1.end(),
|
||||
a3.begin(), a3.end());
|
||||
QCOMPARE_EQ(res, Qt::partial_ordering::unordered);
|
||||
}
|
||||
}
|
||||
|
||||
struct WithCustomPointerCompareThreeWayHelper
|
||||
{
|
||||
float val;
|
||||
|
||||
private:
|
||||
friend auto compareThreeWay(const WithCustomPointerCompareThreeWayHelper *lhs,
|
||||
const WithCustomPointerCompareThreeWayHelper *rhs)
|
||||
{
|
||||
if (lhs && rhs)
|
||||
return Qt::compareThreeWay(lhs->val, rhs->val);
|
||||
else if (lhs)
|
||||
return Qt::partial_ordering::greater;
|
||||
else
|
||||
return Qt::partial_ordering::less;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(QtOrderingPrivate::HasCustomCompareThreeWay<WithCustomPointerCompareThreeWayHelper*>::value);
|
||||
static_assert(!QtOrderingPrivate::HasCustomCompareThreeWay<int*>::value);
|
||||
|
||||
void tst_QCompareHelpers::lexicographicalCompareThreeWay_CustomPointerHelper()
|
||||
{
|
||||
const WithCustomPointerCompareThreeWayHelper val1{1.f};
|
||||
const WithCustomPointerCompareThreeWayHelper val2{2.f};
|
||||
const WithCustomPointerCompareThreeWayHelper val3{3.f};
|
||||
const WithCustomPointerCompareThreeWayHelper nan{std::numeric_limits<float>::quiet_NaN()};
|
||||
|
||||
const std::array a1 = {&val1, &val2, &val3};
|
||||
const std::array a2 = {&val1, &val3, &val2};
|
||||
const std::array a3 = {&nan, &val2, &val3};
|
||||
|
||||
{
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(a1.begin(), a1.end(),
|
||||
a1.begin(), a1.end());
|
||||
QCOMPARE_EQ(res, Qt::partial_ordering::equivalent);
|
||||
}
|
||||
{
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(a1.begin(), a1.end(),
|
||||
a2.begin(), a2.end());
|
||||
QCOMPARE_EQ(res, Qt::partial_ordering::less);
|
||||
}
|
||||
{
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(a2.begin(), a2.end(),
|
||||
a1.begin(), a1.end());
|
||||
QCOMPARE_EQ(res, Qt::partial_ordering::greater);
|
||||
}
|
||||
{
|
||||
const auto res = QtOrderingPrivate::lexicographicalCompareThreeWay(a1.begin(), a1.end(),
|
||||
a3.begin(), a3.end());
|
||||
QCOMPARE_EQ(res, Qt::partial_ordering::unordered);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user