// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo // 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 #define QCOMPARE_H #if 0 #pragma qt_class(QtCompare) #endif #include #include #ifdef __cpp_lib_bit_cast #include #endif #ifdef __cpp_lib_three_way_comparison #include #endif QT_BEGIN_NAMESPACE namespace QtPrivate { using CompareUnderlyingType = qint8; // [cmp.categories.pre] / 1 enum class Ordering : CompareUnderlyingType { Equal = 0, Equivalent = Equal, Less = -1, Greater = 1 }; enum class Uncomparable : CompareUnderlyingType { Unordered = #if defined(_LIBCPP_VERSION) // libc++ -127 #elif defined(__GLIBCXX__) // libstdc++ 2 #else // assume MSSTL -128 #endif }; } // namespace QtPrivate namespace QtOrderingPrivate { template 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 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::Ordering::Less); else if (stdorder == std::partial_ordering::equivalent) m_order = static_cast(QtPrivate::Ordering::Equivalent); else if (stdorder == std::partial_ordering::greater) m_order = static_cast(QtPrivate::Ordering::Greater); else if (stdorder == std::partial_ordering::unordered) m_order = static_cast(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(*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(lhs) == rhs; } friend constexpr bool operator!=(partial_ordering lhs, std::partial_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(std::partial_ordering lhs, partial_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(std::partial_ordering lhs, partial_ordering rhs) noexcept { return lhs != static_cast(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(order)) {} constexpr explicit partial_ordering(QtPrivate::Uncomparable order) noexcept : m_order(static_cast(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::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(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(lhs) == rhs; } friend constexpr bool operator!=(weak_ordering lhs, partial_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(partial_ordering lhs, weak_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(partial_ordering lhs, weak_ordering rhs) noexcept { return lhs != static_cast(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::Ordering::Less); else if (stdorder == std::weak_ordering::equivalent) m_order = static_cast(QtPrivate::Ordering::Equivalent); else if (stdorder == std::weak_ordering::greater) m_order = static_cast(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(*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(lhs) == rhs; } friend constexpr bool operator!=(weak_ordering lhs, std::weak_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(weak_ordering lhs, std::partial_ordering rhs) noexcept { return static_cast(lhs) == rhs; } friend constexpr bool operator!=(weak_ordering lhs, std::partial_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(weak_ordering lhs, std::strong_ordering rhs) noexcept { return static_cast(lhs) == rhs; } friend constexpr bool operator!=(weak_ordering lhs, std::strong_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(std::weak_ordering lhs, weak_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(std::weak_ordering lhs, weak_ordering rhs) noexcept { return lhs != static_cast(rhs); } friend constexpr bool operator==(std::partial_ordering lhs, weak_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(std::partial_ordering lhs, weak_ordering rhs) noexcept { return lhs != static_cast(rhs); } friend constexpr bool operator==(std::strong_ordering lhs, weak_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(std::strong_ordering lhs, weak_ordering rhs) noexcept { return lhs != static_cast(rhs); } #endif // __cpp_lib_three_way_comparison private: friend class strong_ordering; constexpr explicit weak_ordering(QtPrivate::Ordering order) noexcept : m_order(static_cast(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(m_order)); } constexpr Q_IMPLICIT operator weak_ordering() const noexcept { return weak_ordering(static_cast(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(lhs) == rhs; } friend constexpr bool operator!=(strong_ordering lhs, partial_ordering rhs) noexcept { return static_cast(lhs) == rhs; } friend constexpr bool operator==(partial_ordering lhs, strong_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(partial_ordering lhs, strong_ordering rhs) noexcept { return lhs != static_cast(rhs); } friend constexpr bool operator==(strong_ordering lhs, weak_ordering rhs) noexcept { return static_cast(lhs) == rhs; } friend constexpr bool operator!=(strong_ordering lhs, weak_ordering rhs) noexcept { return static_cast(lhs) == rhs; } friend constexpr bool operator==(weak_ordering lhs, strong_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(weak_ordering lhs, strong_ordering rhs) noexcept { return lhs != static_cast(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::Ordering::Less); else if (stdorder == std::strong_ordering::equivalent) m_order = static_cast(QtPrivate::Ordering::Equivalent); else if (stdorder == std::strong_ordering::equal) m_order = static_cast(QtPrivate::Ordering::Equal); else if (stdorder == std::strong_ordering::greater) m_order = static_cast(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(*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(lhs) == rhs; } friend constexpr bool operator!=(strong_ordering lhs, std::strong_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(strong_ordering lhs, std::partial_ordering rhs) noexcept { return static_cast(lhs) == rhs; } friend constexpr bool operator!=(strong_ordering lhs, std::partial_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(strong_ordering lhs, std::weak_ordering rhs) noexcept { return static_cast(lhs) == rhs; } friend constexpr bool operator!=(strong_ordering lhs, std::weak_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(std::strong_ordering lhs, strong_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(std::strong_ordering lhs, strong_ordering rhs) noexcept { return lhs != static_cast(rhs); } friend constexpr bool operator==(std::partial_ordering lhs, strong_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(std::partial_ordering lhs, strong_ordering rhs) noexcept { return lhs != static_cast(rhs); } friend constexpr bool operator==(std::weak_ordering lhs, strong_ordering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(std::weak_ordering lhs, strong_ordering rhs) noexcept { return lhs != static_cast(rhs); } #endif // __cpp_lib_three_way_comparison private: constexpr explicit strong_ordering(QtPrivate::Ordering order) noexcept : m_order(static_cast(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 QT_END_INCLUDE_NAMESPACE namespace QtPrivate { namespace CompareThreeWayTester { using Qt::compareThreeWay; // Check if compareThreeWay is implemented for the (LT, RT) argument // pair. template constexpr bool hasCompareThreeWay = false; template constexpr bool hasCompareThreeWay< LT, RT, std::void_t(), std::declval()))> > = 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 , bool> = true> constexpr bool compareThreeWayNoexcept() noexcept { return noexcept(compareThreeWay(std::declval(), std::declval())); } template && hasCompareThreeWay, bool> = true> constexpr bool compareThreeWayNoexcept() noexcept { return noexcept(compareThreeWay(std::declval(), std::declval())); } } // namespace CompareThreeWayTester } // namespace QtPrivate #if defined(Q_QDOC) template auto qCompareThreeWay(const LeftType &lhs, const RightType &rhs); #else template || QtPrivate::CompareThreeWayTester::hasCompareThreeWay, bool> = true> auto qCompareThreeWay(const LT &lhs, const RT &rhs) noexcept(QtPrivate::CompareThreeWayTester::compareThreeWayNoexcept()) { using Qt::compareThreeWay; if constexpr (QtPrivate::CompareThreeWayTester::hasCompareThreeWay) { 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 { public: static const QPartialOrdering Less; static const QPartialOrdering Equivalent; static const QPartialOrdering Greater; static const QPartialOrdering Unordered; 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::Ordering::Less); else if (order == Qt::partial_ordering::greater) m_order = static_cast(QtPrivate::Ordering::Greater); else if (order == Qt::partial_ordering::unordered) m_order = static_cast(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::Ordering::Less); else if (stdorder == std::partial_ordering::equivalent) m_order = static_cast(QtPrivate::Ordering::Equivalent); else if (stdorder == std::partial_ordering::greater) m_order = static_cast(QtPrivate::Ordering::Greater); else if (stdorder == std::partial_ordering::unordered) m_order = static_cast(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(lhs) == rhs; } friend constexpr bool operator!=(QPartialOrdering lhs, std::partial_ordering rhs) noexcept { return static_cast(lhs) != rhs; } friend constexpr bool operator==(std::partial_ordering lhs, QPartialOrdering rhs) noexcept { return lhs == static_cast(rhs); } friend constexpr bool operator!=(std::partial_ordering lhs, QPartialOrdering rhs) noexcept { return lhs != static_cast(rhs); } #endif // __cpp_lib_three_way_comparison private: constexpr explicit QPartialOrdering(QtPrivate::Ordering order) noexcept : m_order(static_cast(order)) {} constexpr explicit QPartialOrdering(QtPrivate::LegacyUncomparable order) noexcept : m_order(static_cast(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() const noexcept { return m_order != static_cast(QtPrivate::LegacyUncomparable::Unordered); } QtPrivate::CompareUnderlyingType m_order; }; 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); 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 #endif // QCOMPARE_H