summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qcomparehelpers.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/global/qcomparehelpers.h')
-rw-r--r--src/corelib/global/qcomparehelpers.h148
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