diff options
Diffstat (limited to 'src/corelib/global/qcomparehelpers.h')
-rw-r--r-- | src/corelib/global/qcomparehelpers.h | 148 |
1 files changed, 132 insertions, 16 deletions
diff --git a/src/corelib/global/qcomparehelpers.h b/src/corelib/global/qcomparehelpers.h index 0e43ac296b..9a0f0f83a4 100644 --- a/src/corelib/global/qcomparehelpers.h +++ b/src/corelib/global/qcomparehelpers.h @@ -16,6 +16,7 @@ #include <QtCore/qoverload.h> #include <QtCore/qttypetraits.h> +#include <QtCore/qtypeinfo.h> #include <QtCore/qtypes.h> #ifdef __cpp_lib_three_way_comparison @@ -23,7 +24,7 @@ #endif #include <QtCore/q20type_traits.h> -#include <functional> // std::less +#include <functional> // std::less, std::hash QT_BEGIN_NAMESPACE @@ -145,8 +146,8 @@ template <typename In> constexpr auto to_Qt(In in) noexcept noexcept(noexcept(compareThreeWay(rhs, lhs))) \ { \ const auto r = compareThreeWay(rhs, lhs); \ - if (r > 0) return std::strong_ordering::less; \ - if (r < 0) return std::strong_ordering::greater; \ + if (is_gt(r)) return std::strong_ordering::less; \ + if (is_lt(r)) return std::strong_ordering::greater; \ return r; \ } @@ -157,8 +158,8 @@ template <typename In> constexpr auto to_Qt(In in) noexcept noexcept(noexcept(compareThreeWay(rhs, lhs))) \ { \ const auto r = compareThreeWay(rhs, lhs); \ - if (r > 0) return std::weak_ordering::less; \ - if (r < 0) return std::weak_ordering::greater; \ + if (is_gt(r)) return std::weak_ordering::less; \ + if (is_lt(r)) return std::weak_ordering::greater; \ return r; \ } @@ -169,8 +170,8 @@ template <typename In> constexpr auto to_Qt(In in) noexcept noexcept(noexcept(compareThreeWay(rhs, lhs))) \ { \ const auto r = compareThreeWay(rhs, lhs); \ - if (r > 0) return std::partial_ordering::less; \ - if (r < 0) return std::partial_ordering::greater; \ + if (is_gt(r)) return std::partial_ordering::less; \ + if (is_lt(r)) return std::partial_ordering::greater; \ return r; \ } @@ -218,19 +219,19 @@ template <typename In> constexpr auto to_Qt(In in) noexcept Attributes \ friend Constexpr bool operator<(LeftType const &lhs, RightType const &rhs) \ noexcept(noexcept(compareThreeWay(lhs, rhs))) \ - { return compareThreeWay(lhs, rhs) < 0; } \ + { return is_lt(compareThreeWay(lhs, rhs)); } \ Attributes \ friend Constexpr bool operator>(LeftType const &lhs, RightType const &rhs) \ noexcept(noexcept(compareThreeWay(lhs, rhs))) \ - { return compareThreeWay(lhs, rhs) > 0; } \ + { return is_gt(compareThreeWay(lhs, rhs)); } \ Attributes \ friend Constexpr bool operator<=(LeftType const &lhs, RightType const &rhs) \ noexcept(noexcept(compareThreeWay(lhs, rhs))) \ - { return compareThreeWay(lhs, rhs) <= 0; } \ + { return is_lteq(compareThreeWay(lhs, rhs)); } \ Attributes \ friend Constexpr bool operator>=(LeftType const &lhs, RightType const &rhs) \ noexcept(noexcept(compareThreeWay(lhs, rhs))) \ - { return compareThreeWay(lhs, rhs) >= 0; } + { return is_gteq(compareThreeWay(lhs, rhs)); } #define QT_DECLARE_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \ QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr, \ @@ -255,19 +256,19 @@ template <typename In> constexpr auto to_Qt(In in) noexcept Attributes \ friend Constexpr bool operator<(RightType const &lhs, LeftType const &rhs) \ noexcept(noexcept(compareThreeWay(rhs, lhs))) \ - { return compareThreeWay(rhs, lhs) > 0; } \ + { return is_gt(compareThreeWay(rhs, lhs)); } \ Attributes \ friend Constexpr bool operator>(RightType const &lhs, LeftType const &rhs) \ noexcept(noexcept(compareThreeWay(rhs, lhs))) \ - { return compareThreeWay(rhs, lhs) < 0; } \ + { return is_lt(compareThreeWay(rhs, lhs)); } \ Attributes \ friend Constexpr bool operator<=(RightType const &lhs, LeftType const &rhs) \ noexcept(noexcept(compareThreeWay(rhs, lhs))) \ - { return compareThreeWay(rhs, lhs) >= 0; } \ + { return is_gteq(compareThreeWay(rhs, lhs)); } \ Attributes \ friend Constexpr bool operator>=(RightType const &lhs, LeftType const &rhs) \ noexcept(noexcept(compareThreeWay(rhs, lhs))) \ - { return compareThreeWay(rhs, lhs) <= 0; } + { return is_lteq(compareThreeWay(rhs, lhs)); } #define QT_DECLARE_REVERSED_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \ QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, \ @@ -559,9 +560,124 @@ constexpr Qt::strong_ordering compareThreeWay(Enum lhs, Enum rhs) noexcept { return compareThreeWay(qToUnderlying(lhs), qToUnderlying(rhs)); } - } // namespace Qt +namespace QtOrderingPrivate { + +template <typename Head, typename...Tail, std::size_t...Is> +constexpr std::tuple<Tail...> qt_tuple_pop_front_impl(const std::tuple<Head, Tail...> &t, + std::index_sequence<Is...>) noexcept +{ + return std::tuple<Tail...>(std::get<Is + 1>(t)...); +} + +template <typename Head, typename...Tail> +constexpr std::tuple<Tail...> qt_tuple_pop_front(const std::tuple<Head, Tail...> &t) noexcept +{ + return qt_tuple_pop_front_impl(t, std::index_sequence_for<Tail...>{}); +} + +template <typename LhsHead, typename...LhsTail, typename RhsHead, typename...RhsTail> +constexpr auto compareThreeWayMulti(const std::tuple<LhsHead, LhsTail...> &lhs, // ie. not empty + const std::tuple<RhsHead, RhsTail...> &rhs) noexcept +{ + static_assert(sizeof...(LhsTail) == sizeof...(RhsTail), + // expanded together below, but provide a nicer error message: + "The tuple arguments have to have the same size."); + + using Qt::compareThreeWay; + using R = std::common_type_t< + decltype(compareThreeWay(std::declval<LhsHead>(), std::declval<RhsHead>())), + decltype(compareThreeWay(std::declval<LhsTail>(), std::declval<RhsTail>()))... + >; + + const auto &l = std::get<0>(lhs); + const auto &r = std::get<0>(rhs); + static_assert(noexcept(compareThreeWay(l, r)), + "This function requires all relational operators to be noexcept."); + const auto res = compareThreeWay(l, r); + if constexpr (sizeof...(LhsTail) > 0) { + if (is_eq(res)) + return R{compareThreeWayMulti(qt_tuple_pop_front(lhs), qt_tuple_pop_front(rhs))}; + } + return R{res}; +} + +} //QtOrderingPrivate + +namespace Qt { +// A wrapper class that adapts the wrappee to use the strongly-ordered +// <functional> function objects for implementing the relational operators. +// Mostly useful to avoid UB on pointers (which it currently mandates P to be), +// because all the comparison helpers (incl. std::compare_three_way on +// std::tuple<T*>!) will use the language-level operators. +// +template <typename P> +class totally_ordered_wrapper +{ + static_assert(std::is_pointer_v<P>); + using T = std::remove_pointer_t<P>; + + P ptr; +public: + totally_ordered_wrapper() noexcept = default; + explicit constexpr totally_ordered_wrapper(P p) noexcept : ptr(p) {} + + constexpr P get() const noexcept { return ptr; } + constexpr P operator->() const noexcept { return get(); } + constexpr T& operator*() const noexcept { return *get(); } + + explicit constexpr operator bool() const noexcept { return get(); } + +private: + friend constexpr auto compareThreeWay(const totally_ordered_wrapper &lhs, const totally_ordered_wrapper &rhs) noexcept + { return Qt::compareThreeWay(lhs.ptr, rhs.ptr); } +#define MAKE_RELOP(Ret, op, Op) \ + friend constexpr Ret operator op (const totally_ordered_wrapper &lhs, const totally_ordered_wrapper &rhs) noexcept \ + { return std:: Op {}(lhs.ptr, rhs.ptr); } \ + friend constexpr Ret operator op (const totally_ordered_wrapper &lhs, const P &rhs) noexcept \ + { return std:: Op {}(lhs.ptr, rhs ); } \ + friend constexpr Ret operator op (const P &lhs, const totally_ordered_wrapper &rhs) noexcept \ + { return std:: Op {}(lhs, rhs.ptr); } \ + friend constexpr Ret operator op (const totally_ordered_wrapper &lhs, std::nullptr_t) noexcept \ + { return std:: Op {}(lhs.ptr, nullptr); } \ + friend constexpr Ret operator op (std::nullptr_t, const totally_ordered_wrapper &rhs) noexcept \ + { return std:: Op {}(nullptr, rhs.ptr); } \ + /* end */ + MAKE_RELOP(bool, ==, equal_to<P>) + MAKE_RELOP(bool, !=, not_equal_to<P>) + MAKE_RELOP(bool, < , less<P>) + MAKE_RELOP(bool, <=, less_equal<P>) + MAKE_RELOP(bool, > , greater<P>) + MAKE_RELOP(bool, >=, greater_equal<P>) +#ifdef __cpp_lib_three_way_comparison + MAKE_RELOP(auto, <=>, compare_three_way) +#endif +#undef MAKE_RELOP + friend void qt_ptr_swap(totally_ordered_wrapper &lhs, totally_ordered_wrapper &rhs) noexcept + { qt_ptr_swap(lhs.ptr, rhs.ptr); } + friend void swap(totally_ordered_wrapper &lhs, totally_ordered_wrapper &rhs) noexcept + { qt_ptr_swap(lhs, rhs); } + friend size_t qHash(totally_ordered_wrapper key, size_t seed = 0) noexcept + { return qHash(key.ptr, seed); } +}; + +} //Qt + +template <typename P> +class QTypeInfo<Qt::totally_ordered_wrapper<P>> : public QTypeInfo<P> {}; + QT_END_NAMESPACE +namespace std { + template <typename P> + struct hash<QT_PREPEND_NAMESPACE(Qt::totally_ordered_wrapper)<P>> + { + using argument_type = QT_PREPEND_NAMESPACE(Qt::totally_ordered_wrapper)<P>; + using result_type = size_t; + constexpr result_type operator()(argument_type w) const noexcept + { return std::hash<P>{}(w.get()); } + }; +} + #endif // QCOMPAREHELPERS_H |