diff options
Diffstat (limited to 'src/corelib/global/qcompare.h')
-rw-r--r-- | src/corelib/global/qcompare.h | 866 |
1 files changed, 831 insertions, 35 deletions
diff --git a/src/corelib/global/qcompare.h b/src/corelib/global/qcompare.h index aa0e5eefa8..fb5a40f052 100644 --- a/src/corelib/global/qcompare.h +++ b/src/corelib/global/qcompare.h @@ -1,4 +1,5 @@ // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QCOMPARE_H @@ -11,6 +12,13 @@ #include <QtCore/qglobal.h> #include <QtCore/qcompare_impl.h> +#ifdef __cpp_lib_bit_cast +#include <bit> +#endif +#ifdef __cpp_lib_three_way_comparison +#include <compare> +#endif + QT_BEGIN_NAMESPACE namespace QtPrivate { @@ -27,11 +35,648 @@ enum class Ordering : CompareUnderlyingType enum class Uncomparable : CompareUnderlyingType { - Unordered = -127 + Unordered = + #if defined(_LIBCPP_VERSION) // libc++ + -127 + #elif defined(__GLIBCXX__) // libstdc++ + 2 + #else // assume MSSTL + -128 + #endif +}; + +} // namespace QtPrivate + +namespace QtOrderingPrivate { + +template <typename O> +constexpr O reversed(O o) noexcept +{ + // https://eel.is/c++draft/cmp.partialord#5 + return is_lt(o) ? O::greater : + is_gt(o) ? O::less : + /*else*/ o ; +} + +} // namespace QtOrderingPrivate + +namespace Qt { + +class weak_ordering; +class strong_ordering; + +class partial_ordering +{ +public: + static const partial_ordering less; + static const partial_ordering equivalent; + static const partial_ordering greater; + static const partial_ordering unordered; + + friend constexpr bool operator==(partial_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order == 0; } + + friend constexpr bool operator!=(partial_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order != 0; } + + friend constexpr bool operator< (partial_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order < 0; } + + friend constexpr bool operator<=(partial_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order <= 0; } + + friend constexpr bool operator> (partial_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order > 0; } + + friend constexpr bool operator>=(partial_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order >= 0; } + + + friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero, + partial_ordering rhs) noexcept + { return rhs.isOrdered() && 0 == rhs.m_order; } + + friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero, + partial_ordering rhs) noexcept + { return rhs.isOrdered() && 0 != rhs.m_order; } + + friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero, + partial_ordering rhs) noexcept + { return rhs.isOrdered() && 0 < rhs.m_order; } + + friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero, + partial_ordering rhs) noexcept + { return rhs.isOrdered() && 0 <= rhs.m_order; } + + friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero, + partial_ordering rhs) noexcept + { return rhs.isOrdered() && 0 > rhs.m_order; } + + friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero, + partial_ordering rhs) noexcept + { return rhs.isOrdered() && 0 >= rhs.m_order; } + + +#ifdef __cpp_lib_three_way_comparison + friend constexpr std::partial_ordering + operator<=>(partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs; } // https://eel.is/c++draft/cmp.partialord#4 + + friend constexpr std::partial_ordering + operator<=>(QtPrivate::CompareAgainstLiteralZero, partial_ordering rhs) noexcept + { return QtOrderingPrivate::reversed(rhs); } +#endif // __cpp_lib_three_way_comparison + + + friend constexpr bool operator==(partial_ordering lhs, partial_ordering rhs) noexcept + { return lhs.m_order == rhs.m_order; } + + friend constexpr bool operator!=(partial_ordering lhs, partial_ordering rhs) noexcept + { return lhs.m_order != rhs.m_order; } + +#ifdef __cpp_lib_three_way_comparison + constexpr Q_IMPLICIT partial_ordering(std::partial_ordering stdorder) noexcept + { + if (stdorder == std::partial_ordering::less) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less); + else if (stdorder == std::partial_ordering::equivalent) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent); + else if (stdorder == std::partial_ordering::greater) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater); + else if (stdorder == std::partial_ordering::unordered) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); + } + + constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept + { + static_assert(sizeof(*this) == sizeof(std::partial_ordering)); +#ifdef __cpp_lib_bit_cast + return std::bit_cast<std::partial_ordering>(*this); +#else + using O = QtPrivate::Ordering; + using U = QtPrivate::Uncomparable; + using R = std::partial_ordering; + switch (m_order) { + case qToUnderlying(O::Less): return R::less; + case qToUnderlying(O::Greater): return R::greater; + case qToUnderlying(O::Equivalent): return R::equivalent; + case qToUnderlying(U::Unordered): return R::unordered; + } + Q_UNREACHABLE_RETURN(R::unordered); +#endif // __cpp_lib_bit_cast + } + + friend constexpr bool operator==(partial_ordering lhs, std::partial_ordering rhs) noexcept + { return static_cast<std::partial_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(partial_ordering lhs, std::partial_ordering rhs) noexcept + { return static_cast<std::partial_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(std::partial_ordering lhs, partial_ordering rhs) noexcept + { return lhs == static_cast<std::partial_ordering>(rhs); } + + friend constexpr bool operator!=(std::partial_ordering lhs, partial_ordering rhs) noexcept + { return lhs != static_cast<std::partial_ordering>(rhs); } +#endif // __cpp_lib_three_way_comparison + +private: + friend class weak_ordering; + friend class strong_ordering; + + constexpr explicit partial_ordering(QtPrivate::Ordering order) noexcept + : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) + {} + constexpr explicit partial_ordering(QtPrivate::Uncomparable order) noexcept + : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) + {} + + QT_WARNING_PUSH + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903 + QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant") + friend constexpr bool is_eq (partial_ordering o) noexcept { return o == 0; } + friend constexpr bool is_neq (partial_ordering o) noexcept { return o != 0; } + friend constexpr bool is_lt (partial_ordering o) noexcept { return o < 0; } + friend constexpr bool is_lteq(partial_ordering o) noexcept { return o <= 0; } + friend constexpr bool is_gt (partial_ordering o) noexcept { return o > 0; } + friend constexpr bool is_gteq(partial_ordering o) noexcept { return o >= 0; } + QT_WARNING_POP + + // instead of the exposition only is_ordered member in [cmp.partialord], + // use a private function + constexpr bool isOrdered() const noexcept + { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); } + + QtPrivate::CompareUnderlyingType m_order; +}; + +inline constexpr partial_ordering partial_ordering::less(QtPrivate::Ordering::Less); +inline constexpr partial_ordering partial_ordering::equivalent(QtPrivate::Ordering::Equivalent); +inline constexpr partial_ordering partial_ordering::greater(QtPrivate::Ordering::Greater); +inline constexpr partial_ordering partial_ordering::unordered(QtPrivate::Uncomparable::Unordered); + +class weak_ordering +{ +public: + static const weak_ordering less; + static const weak_ordering equivalent; + static const weak_ordering greater; + + constexpr Q_IMPLICIT operator partial_ordering() const noexcept + { return partial_ordering(static_cast<QtPrivate::Ordering>(m_order)); } + + friend constexpr bool operator==(weak_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order == 0; } + + friend constexpr bool operator!=(weak_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order != 0; } + + friend constexpr bool operator< (weak_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order < 0; } + + friend constexpr bool operator<=(weak_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order <= 0; } + + friend constexpr bool operator> (weak_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order > 0; } + + friend constexpr bool operator>=(weak_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order >= 0; } + + + friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero, + weak_ordering rhs) noexcept + { return 0 == rhs.m_order; } + + friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero, + weak_ordering rhs) noexcept + { return 0 != rhs.m_order; } + + friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero, + weak_ordering rhs) noexcept + { return 0 < rhs.m_order; } + + friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero, + weak_ordering rhs) noexcept + { return 0 <= rhs.m_order; } + + friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero, + weak_ordering rhs) noexcept + { return 0 > rhs.m_order; } + + friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero, + weak_ordering rhs) noexcept + { return 0 >= rhs.m_order; } + + +#ifdef __cpp_lib_three_way_comparison + friend constexpr std::weak_ordering + operator<=>(weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs; } // https://eel.is/c++draft/cmp.weakord#5 + + friend constexpr std::weak_ordering + operator<=>(QtPrivate::CompareAgainstLiteralZero, weak_ordering rhs) noexcept + { return QtOrderingPrivate::reversed(rhs); } +#endif // __cpp_lib_three_way_comparison + + + friend constexpr bool operator==(weak_ordering lhs, weak_ordering rhs) noexcept + { return lhs.m_order == rhs.m_order; } + + friend constexpr bool operator!=(weak_ordering lhs, weak_ordering rhs) noexcept + { return lhs.m_order != rhs.m_order; } + + friend constexpr bool operator==(weak_ordering lhs, partial_ordering rhs) noexcept + { return static_cast<partial_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(weak_ordering lhs, partial_ordering rhs) noexcept + { return static_cast<partial_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(partial_ordering lhs, weak_ordering rhs) noexcept + { return lhs == static_cast<partial_ordering>(rhs); } + + friend constexpr bool operator!=(partial_ordering lhs, weak_ordering rhs) noexcept + { return lhs != static_cast<partial_ordering>(rhs); } + +#ifdef __cpp_lib_three_way_comparison + constexpr Q_IMPLICIT weak_ordering(std::weak_ordering stdorder) noexcept + { + if (stdorder == std::weak_ordering::less) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less); + else if (stdorder == std::weak_ordering::equivalent) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent); + else if (stdorder == std::weak_ordering::greater) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater); + } + + constexpr Q_IMPLICIT operator std::weak_ordering() const noexcept + { + static_assert(sizeof(*this) == sizeof(std::weak_ordering)); +#ifdef __cpp_lib_bit_cast + return std::bit_cast<std::weak_ordering>(*this); +#else + using O = QtPrivate::Ordering; + using R = std::weak_ordering; + switch (m_order) { + case qToUnderlying(O::Less): return R::less; + case qToUnderlying(O::Greater): return R::greater; + case qToUnderlying(O::Equivalent): return R::equivalent; + } + Q_UNREACHABLE_RETURN(R::equivalent); +#endif // __cpp_lib_bit_cast + } + + friend constexpr bool operator==(weak_ordering lhs, std::weak_ordering rhs) noexcept + { return static_cast<std::weak_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(weak_ordering lhs, std::weak_ordering rhs) noexcept + { return static_cast<std::weak_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(weak_ordering lhs, std::partial_ordering rhs) noexcept + { return static_cast<std::weak_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(weak_ordering lhs, std::partial_ordering rhs) noexcept + { return static_cast<std::weak_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(weak_ordering lhs, std::strong_ordering rhs) noexcept + { return static_cast<std::weak_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(weak_ordering lhs, std::strong_ordering rhs) noexcept + { return static_cast<std::weak_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(std::weak_ordering lhs, weak_ordering rhs) noexcept + { return lhs == static_cast<std::weak_ordering>(rhs); } + + friend constexpr bool operator!=(std::weak_ordering lhs, weak_ordering rhs) noexcept + { return lhs != static_cast<std::weak_ordering>(rhs); } + + friend constexpr bool operator==(std::partial_ordering lhs, weak_ordering rhs) noexcept + { return lhs == static_cast<std::weak_ordering>(rhs); } + + friend constexpr bool operator!=(std::partial_ordering lhs, weak_ordering rhs) noexcept + { return lhs != static_cast<std::weak_ordering>(rhs); } + + friend constexpr bool operator==(std::strong_ordering lhs, weak_ordering rhs) noexcept + { return lhs == static_cast<std::weak_ordering>(rhs); } + + friend constexpr bool operator!=(std::strong_ordering lhs, weak_ordering rhs) noexcept + { return lhs != static_cast<std::weak_ordering>(rhs); } +#endif // __cpp_lib_three_way_comparison + +private: + friend class strong_ordering; + + constexpr explicit weak_ordering(QtPrivate::Ordering order) noexcept + : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) + {} + + QT_WARNING_PUSH + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903 + QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant") + friend constexpr bool is_eq (weak_ordering o) noexcept { return o == 0; } + friend constexpr bool is_neq (weak_ordering o) noexcept { return o != 0; } + friend constexpr bool is_lt (weak_ordering o) noexcept { return o < 0; } + friend constexpr bool is_lteq(weak_ordering o) noexcept { return o <= 0; } + friend constexpr bool is_gt (weak_ordering o) noexcept { return o > 0; } + friend constexpr bool is_gteq(weak_ordering o) noexcept { return o >= 0; } + QT_WARNING_POP + + QtPrivate::CompareUnderlyingType m_order; +}; + +inline constexpr weak_ordering weak_ordering::less(QtPrivate::Ordering::Less); +inline constexpr weak_ordering weak_ordering::equivalent(QtPrivate::Ordering::Equivalent); +inline constexpr weak_ordering weak_ordering::greater(QtPrivate::Ordering::Greater); + +class strong_ordering +{ +public: + static const strong_ordering less; + static const strong_ordering equivalent; + static const strong_ordering equal; + static const strong_ordering greater; + + constexpr Q_IMPLICIT operator partial_ordering() const noexcept + { return partial_ordering(static_cast<QtPrivate::Ordering>(m_order)); } + + constexpr Q_IMPLICIT operator weak_ordering() const noexcept + { return weak_ordering(static_cast<QtPrivate::Ordering>(m_order)); } + + friend constexpr bool operator==(strong_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order == 0; } + + friend constexpr bool operator!=(strong_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order != 0; } + + friend constexpr bool operator< (strong_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order < 0; } + + friend constexpr bool operator<=(strong_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order <= 0; } + + friend constexpr bool operator> (strong_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order > 0; } + + friend constexpr bool operator>=(strong_ordering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.m_order >= 0; } + + + friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero, + strong_ordering rhs) noexcept + { return 0 == rhs.m_order; } + + friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero, + strong_ordering rhs) noexcept + { return 0 != rhs.m_order; } + + friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero, + strong_ordering rhs) noexcept + { return 0 < rhs.m_order; } + + friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero, + strong_ordering rhs) noexcept + { return 0 <= rhs.m_order; } + + friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero, + strong_ordering rhs) noexcept + { return 0 > rhs.m_order; } + + friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero, + strong_ordering rhs) noexcept + { return 0 >= rhs.m_order; } + + +#ifdef __cpp_lib_three_way_comparison + friend constexpr std::strong_ordering + operator<=>(strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs; } // https://eel.is/c++draft/cmp.strongord#6 + + friend constexpr std::strong_ordering + operator<=>(QtPrivate::CompareAgainstLiteralZero, strong_ordering rhs) noexcept + { return QtOrderingPrivate::reversed(rhs); } +#endif // __cpp_lib_three_way_comparison + + + friend constexpr bool operator==(strong_ordering lhs, strong_ordering rhs) noexcept + { return lhs.m_order == rhs.m_order; } + + friend constexpr bool operator!=(strong_ordering lhs, strong_ordering rhs) noexcept + { return lhs.m_order != rhs.m_order; } + + friend constexpr bool operator==(strong_ordering lhs, partial_ordering rhs) noexcept + { return static_cast<partial_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(strong_ordering lhs, partial_ordering rhs) noexcept + { return static_cast<partial_ordering>(lhs) == rhs; } + + friend constexpr bool operator==(partial_ordering lhs, strong_ordering rhs) noexcept + { return lhs == static_cast<partial_ordering>(rhs); } + + friend constexpr bool operator!=(partial_ordering lhs, strong_ordering rhs) noexcept + { return lhs != static_cast<partial_ordering>(rhs); } + + friend constexpr bool operator==(strong_ordering lhs, weak_ordering rhs) noexcept + { return static_cast<weak_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(strong_ordering lhs, weak_ordering rhs) noexcept + { return static_cast<weak_ordering>(lhs) == rhs; } + + friend constexpr bool operator==(weak_ordering lhs, strong_ordering rhs) noexcept + { return lhs == static_cast<weak_ordering>(rhs); } + + friend constexpr bool operator!=(weak_ordering lhs, strong_ordering rhs) noexcept + { return lhs != static_cast<weak_ordering>(rhs); } + +#ifdef __cpp_lib_three_way_comparison + constexpr Q_IMPLICIT strong_ordering(std::strong_ordering stdorder) noexcept + { + if (stdorder == std::strong_ordering::less) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less); + else if (stdorder == std::strong_ordering::equivalent) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent); + else if (stdorder == std::strong_ordering::equal) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equal); + else if (stdorder == std::strong_ordering::greater) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater); + } + + constexpr Q_IMPLICIT operator std::strong_ordering() const noexcept + { + static_assert(sizeof(*this) == sizeof(std::strong_ordering)); +#ifdef __cpp_lib_bit_cast + return std::bit_cast<std::strong_ordering>(*this); +#else + using O = QtPrivate::Ordering; + using R = std::strong_ordering; + switch (m_order) { + case qToUnderlying(O::Less): return R::less; + case qToUnderlying(O::Greater): return R::greater; + case qToUnderlying(O::Equal): return R::equal; + } + Q_UNREACHABLE_RETURN(R::equal); +#endif // __cpp_lib_bit_cast + } + + friend constexpr bool operator==(strong_ordering lhs, std::strong_ordering rhs) noexcept + { return static_cast<std::strong_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(strong_ordering lhs, std::strong_ordering rhs) noexcept + { return static_cast<std::strong_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(strong_ordering lhs, std::partial_ordering rhs) noexcept + { return static_cast<std::strong_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(strong_ordering lhs, std::partial_ordering rhs) noexcept + { return static_cast<std::strong_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(strong_ordering lhs, std::weak_ordering rhs) noexcept + { return static_cast<std::strong_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(strong_ordering lhs, std::weak_ordering rhs) noexcept + { return static_cast<std::strong_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(std::strong_ordering lhs, strong_ordering rhs) noexcept + { return lhs == static_cast<std::strong_ordering>(rhs); } + + friend constexpr bool operator!=(std::strong_ordering lhs, strong_ordering rhs) noexcept + { return lhs != static_cast<std::strong_ordering>(rhs); } + + friend constexpr bool operator==(std::partial_ordering lhs, strong_ordering rhs) noexcept + { return lhs == static_cast<std::strong_ordering>(rhs); } + + friend constexpr bool operator!=(std::partial_ordering lhs, strong_ordering rhs) noexcept + { return lhs != static_cast<std::strong_ordering>(rhs); } + + friend constexpr bool operator==(std::weak_ordering lhs, strong_ordering rhs) noexcept + { return lhs == static_cast<std::strong_ordering>(rhs); } + + friend constexpr bool operator!=(std::weak_ordering lhs, strong_ordering rhs) noexcept + { return lhs != static_cast<std::strong_ordering>(rhs); } +#endif // __cpp_lib_three_way_comparison + + private: + constexpr explicit strong_ordering(QtPrivate::Ordering order) noexcept + : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) + {} + + QT_WARNING_PUSH + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903 + QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant") + friend constexpr bool is_eq (strong_ordering o) noexcept { return o == 0; } + friend constexpr bool is_neq (strong_ordering o) noexcept { return o != 0; } + friend constexpr bool is_lt (strong_ordering o) noexcept { return o < 0; } + friend constexpr bool is_lteq(strong_ordering o) noexcept { return o <= 0; } + friend constexpr bool is_gt (strong_ordering o) noexcept { return o > 0; } + friend constexpr bool is_gteq(strong_ordering o) noexcept { return o >= 0; } + QT_WARNING_POP + + QtPrivate::CompareUnderlyingType m_order; }; +inline constexpr strong_ordering strong_ordering::less(QtPrivate::Ordering::Less); +inline constexpr strong_ordering strong_ordering::equivalent(QtPrivate::Ordering::Equivalent); +inline constexpr strong_ordering strong_ordering::equal(QtPrivate::Ordering::Equal); +inline constexpr strong_ordering strong_ordering::greater(QtPrivate::Ordering::Greater); + +} // namespace Qt + +QT_BEGIN_INCLUDE_NAMESPACE + +// This is intentionally included after Qt::*_ordering types and before +// qCompareThreeWay. Do not change! +#include <QtCore/qcomparehelpers.h> + +QT_END_INCLUDE_NAMESPACE + +namespace QtPrivate { + +namespace CompareThreeWayTester { + + using Qt::compareThreeWay; + + // Check if compareThreeWay is implemented for the (LT, RT) argument + // pair. + template <typename LT, typename RT, typename = void> + constexpr bool hasCompareThreeWay = false; + + template <typename LT, typename RT> + constexpr bool hasCompareThreeWay< + LT, RT, std::void_t<decltype(compareThreeWay(std::declval<LT>(), std::declval<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 + // context. + + template <typename LT, typename RT, + std::enable_if_t<hasCompareThreeWay<LT, RT>, bool> = true> + constexpr bool compareThreeWayNoexcept() noexcept + { return noexcept(compareThreeWay(std::declval<LT>(), std::declval<RT>())); } + + template <typename LT, typename RT, + std::enable_if_t<!hasCompareThreeWay<LT, RT> && hasCompareThreeWay<RT, LT>, + bool> = true> + constexpr bool compareThreeWayNoexcept() noexcept + { return noexcept(compareThreeWay(std::declval<RT>(), std::declval<LT>())); } + +} // namespace CompareThreeWayTester + } // namespace QtPrivate +#if defined(Q_QDOC) + +template <typename LeftType, typename RightType> +auto qCompareThreeWay(const LeftType &lhs, const RightType &rhs); + +#else + +template <typename LT, typename RT, + std::enable_if_t<QtPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT> + || QtPrivate::CompareThreeWayTester::hasCompareThreeWay<RT, LT>, + bool> = true> +auto qCompareThreeWay(const LT &lhs, const RT &rhs) + noexcept(QtPrivate::CompareThreeWayTester::compareThreeWayNoexcept<LT, RT>()) +{ + using Qt::compareThreeWay; + if constexpr (QtPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT>) { + return compareThreeWay(lhs, rhs); + } else { + const auto retval = compareThreeWay(rhs, lhs); + return QtOrderingPrivate::reversed(retval); + } +} + +#endif // defined(Q_QDOC) + +// +// Legacy QPartialOrdering +// + +namespace QtPrivate { +enum class LegacyUncomparable : CompareUnderlyingType +{ + Unordered = -127 +}; +} + // [cmp.partialord] class QPartialOrdering { @@ -41,49 +686,195 @@ public: static const QPartialOrdering Greater; static const QPartialOrdering Unordered; - friend constexpr bool operator==(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept - { return p.isOrdered() && p.m_order == 0; } - friend constexpr bool operator!=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept - { return p.isOrdered() && p.m_order != 0; } - friend constexpr bool operator< (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept - { return p.isOrdered() && p.m_order < 0; } - friend constexpr bool operator<=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept - { return p.isOrdered() && p.m_order <= 0; } - friend constexpr bool operator> (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept - { return p.isOrdered() && p.m_order > 0; } - friend constexpr bool operator>=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept - { return p.isOrdered() && p.m_order >= 0; } - - friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept - { return p.isOrdered() && 0 == p.m_order; } - friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept - { return p.isOrdered() && 0 != p.m_order; } - friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept - { return p.isOrdered() && 0 < p.m_order; } - friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept - { return p.isOrdered() && 0 <= p.m_order; } - friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept - { return p.isOrdered() && 0 > p.m_order; } - friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept - { return p.isOrdered() && 0 >= p.m_order; } - - friend constexpr bool operator==(QPartialOrdering p1, QPartialOrdering p2) noexcept - { return p1.m_order == p2.m_order; } - friend constexpr bool operator!=(QPartialOrdering p1, QPartialOrdering p2) noexcept - { return p1.m_order != p2.m_order; } + static const QPartialOrdering less; + static const QPartialOrdering equivalent; + static const QPartialOrdering greater; + static const QPartialOrdering unordered; + + friend constexpr bool operator==(QPartialOrdering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order == 0; } + + friend constexpr bool operator!=(QPartialOrdering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order != 0; } + + friend constexpr bool operator< (QPartialOrdering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order < 0; } + + friend constexpr bool operator<=(QPartialOrdering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order <= 0; } + + friend constexpr bool operator> (QPartialOrdering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order > 0; } + + friend constexpr bool operator>=(QPartialOrdering lhs, + QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs.isOrdered() && lhs.m_order >= 0; } + + + friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero, + QPartialOrdering rhs) noexcept + { return rhs.isOrdered() && 0 == rhs.m_order; } + + friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero, + QPartialOrdering rhs) noexcept + { return rhs.isOrdered() && 0 != rhs.m_order; } + + friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero, + QPartialOrdering rhs) noexcept + { return rhs.isOrdered() && 0 < rhs.m_order; } + + friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero, + QPartialOrdering rhs) noexcept + { return rhs.isOrdered() && 0 <= rhs.m_order; } + + friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero, + QPartialOrdering rhs) noexcept + { return rhs.isOrdered() && 0 > rhs.m_order; } + + friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero, + QPartialOrdering rhs) noexcept + { return rhs.isOrdered() && 0 >= rhs.m_order; } + + +#ifdef __cpp_lib_three_way_comparison + friend constexpr std::partial_ordering + operator<=>(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept + { return lhs; } // https://eel.is/c++draft/cmp.partialord#4 + + friend constexpr std::partial_ordering + operator<=>(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs) noexcept + { return QtOrderingPrivate::reversed(rhs); } +#endif // __cpp_lib_three_way_comparison + + + friend constexpr bool operator==(QPartialOrdering lhs, QPartialOrdering rhs) noexcept + { return lhs.m_order == rhs.m_order; } + + friend constexpr bool operator!=(QPartialOrdering lhs, QPartialOrdering rhs) noexcept + { return lhs.m_order != rhs.m_order; } + + constexpr Q_IMPLICIT QPartialOrdering(Qt::partial_ordering order) noexcept + : m_order{} // == equivalent + { + if (order == Qt::partial_ordering::less) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less); + else if (order == Qt::partial_ordering::greater) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater); + else if (order == Qt::partial_ordering::unordered) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered); + } + + constexpr Q_IMPLICIT QPartialOrdering(Qt::weak_ordering stdorder) noexcept + : QPartialOrdering(Qt::partial_ordering{stdorder}) {} + + constexpr Q_IMPLICIT QPartialOrdering(Qt::strong_ordering stdorder) noexcept + : QPartialOrdering(Qt::partial_ordering{stdorder}) {} + + constexpr Q_IMPLICIT operator Qt::partial_ordering() const noexcept + { + using O = QtPrivate::Ordering; + using U = QtPrivate::LegacyUncomparable; + using R = Qt::partial_ordering; + switch (m_order) { + case qToUnderlying(O::Less): return R::less; + case qToUnderlying(O::Greater): return R::greater; + case qToUnderlying(O::Equivalent): return R::equivalent; + case qToUnderlying(U::Unordered): return R::unordered; + } + // GCC 8.x does not treat __builtin_unreachable() as constexpr +#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900) + // NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8 + Q_UNREACHABLE(); +#endif + return R::unordered; + } + + friend constexpr bool operator==(QPartialOrdering lhs, Qt::partial_ordering rhs) noexcept + { Qt::partial_ordering qt = lhs; return qt == rhs; } + + friend constexpr bool operator!=(QPartialOrdering lhs, Qt::partial_ordering rhs) noexcept + { Qt::partial_ordering qt = lhs; return qt != rhs; } + + friend constexpr bool operator==(Qt::partial_ordering lhs, QPartialOrdering rhs) noexcept + { Qt::partial_ordering qt = rhs; return lhs == qt; } + + friend constexpr bool operator!=(Qt::partial_ordering lhs, QPartialOrdering rhs) noexcept + { Qt::partial_ordering qt = rhs; return lhs != qt; } + +#ifdef __cpp_lib_three_way_comparison + constexpr Q_IMPLICIT QPartialOrdering(std::partial_ordering stdorder) noexcept + { + if (stdorder == std::partial_ordering::less) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less); + else if (stdorder == std::partial_ordering::equivalent) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent); + else if (stdorder == std::partial_ordering::greater) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater); + else if (stdorder == std::partial_ordering::unordered) + m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered); + } + + constexpr Q_IMPLICIT QPartialOrdering(std::weak_ordering stdorder) noexcept + : QPartialOrdering(std::partial_ordering(stdorder)) {} + + constexpr Q_IMPLICIT QPartialOrdering(std::strong_ordering stdorder) noexcept + : QPartialOrdering(std::partial_ordering(stdorder)) {} + + constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept + { + using O = QtPrivate::Ordering; + using U = QtPrivate::LegacyUncomparable; + using R = std::partial_ordering; + switch (m_order) { + case qToUnderlying(O::Less): return R::less; + case qToUnderlying(O::Greater): return R::greater; + case qToUnderlying(O::Equivalent): return R::equivalent; + case qToUnderlying(U::Unordered): return R::unordered; + } + Q_UNREACHABLE_RETURN(R::unordered); + } + + friend constexpr bool operator==(QPartialOrdering lhs, std::partial_ordering rhs) noexcept + { return static_cast<std::partial_ordering>(lhs) == rhs; } + + friend constexpr bool operator!=(QPartialOrdering lhs, std::partial_ordering rhs) noexcept + { return static_cast<std::partial_ordering>(lhs) != rhs; } + + friend constexpr bool operator==(std::partial_ordering lhs, QPartialOrdering rhs) noexcept + { return lhs == static_cast<std::partial_ordering>(rhs); } + + friend constexpr bool operator!=(std::partial_ordering lhs, QPartialOrdering rhs) noexcept + { return lhs != static_cast<std::partial_ordering>(rhs); } +#endif // __cpp_lib_three_way_comparison private: constexpr explicit QPartialOrdering(QtPrivate::Ordering order) noexcept : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) {} - constexpr explicit QPartialOrdering(QtPrivate::Uncomparable order) noexcept + constexpr explicit QPartialOrdering(QtPrivate::LegacyUncomparable order) noexcept : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) {} + QT_WARNING_PUSH + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903 + QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant") + friend constexpr bool is_eq (QPartialOrdering o) noexcept { return o == 0; } + friend constexpr bool is_neq (QPartialOrdering o) noexcept { return o != 0; } + friend constexpr bool is_lt (QPartialOrdering o) noexcept { return o < 0; } + friend constexpr bool is_lteq(QPartialOrdering o) noexcept { return o <= 0; } + friend constexpr bool is_gt (QPartialOrdering o) noexcept { return o > 0; } + friend constexpr bool is_gteq(QPartialOrdering o) noexcept { return o >= 0; } + QT_WARNING_POP + // instead of the exposition only is_ordered member in [cmp.partialord], // use a private function - constexpr bool isOrdered() noexcept - { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); } + constexpr bool isOrdered() const noexcept + { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered); } QtPrivate::CompareUnderlyingType m_order; }; @@ -91,7 +882,12 @@ private: inline constexpr QPartialOrdering QPartialOrdering::Less(QtPrivate::Ordering::Less); inline constexpr QPartialOrdering QPartialOrdering::Equivalent(QtPrivate::Ordering::Equivalent); inline constexpr QPartialOrdering QPartialOrdering::Greater(QtPrivate::Ordering::Greater); -inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::Uncomparable::Unordered); +inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::LegacyUncomparable::Unordered); + +inline constexpr QPartialOrdering QPartialOrdering::less(QtPrivate::Ordering::Less); +inline constexpr QPartialOrdering QPartialOrdering::equivalent(QtPrivate::Ordering::Equivalent); +inline constexpr QPartialOrdering QPartialOrdering::greater(QtPrivate::Ordering::Greater); +inline constexpr QPartialOrdering QPartialOrdering::unordered(QtPrivate::LegacyUncomparable::Unordered); QT_END_NAMESPACE |