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.h222
1 files changed, 206 insertions, 16 deletions
diff --git a/src/corelib/global/qcomparehelpers.h b/src/corelib/global/qcomparehelpers.h
index 0e43ac296b..fce751be09 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, \
@@ -450,6 +451,26 @@ constexpr bool IsFloatType_v<QtPrivate::NativeFloat16Type> = true;
} // namespace QtPrivate
+namespace QtOrderingPrivate {
+
+template <typename T, typename U>
+constexpr Qt::strong_ordering
+strongOrderingCompareDefaultImpl(T lhs, U rhs) noexcept
+{
+#ifdef __cpp_lib_three_way_comparison
+ return lhs <=> rhs;
+#else
+ if (lhs == rhs)
+ return Qt::strong_ordering::equivalent;
+ else if (lhs < rhs)
+ return Qt::strong_ordering::less;
+ else
+ return Qt::strong_ordering::greater;
+#endif // __cpp_lib_three_way_comparison
+}
+
+} // namespace QtOrderingPrivate
+
namespace Qt {
template <typename T>
@@ -526,8 +547,11 @@ constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexc
return compareThreeWay(lhs, FloatType(rhs));
}
+#if QT_DEPRECATED_SINCE(6, 8)
+
template <typename LeftType, typename RightType,
if_compatible_pointers<LeftType, RightType> = true>
+QT_DEPRECATED_VERSION_X_6_8("Wrap the pointers into Qt::totally_ordered_wrapper and use the respective overload instead.")
constexpr Qt::strong_ordering compareThreeWay(const LeftType *lhs, const RightType *rhs) noexcept
{
#ifdef __cpp_lib_three_way_comparison
@@ -543,25 +567,191 @@ constexpr Qt::strong_ordering compareThreeWay(const LeftType *lhs, const RightTy
}
template <typename T>
+QT_DEPRECATED_VERSION_X_6_8("Wrap the pointer into Qt::totally_ordered_wrapper and use the respective overload instead.")
constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept
{
return compareThreeWay(lhs, static_cast<const T *>(rhs));
}
template <typename T>
+QT_DEPRECATED_VERSION_X_6_8("Wrap the pointer into Qt::totally_ordered_wrapper and use the respective overload instead.")
constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept
{
return compareThreeWay(static_cast<const T *>(lhs), rhs);
}
+#endif // QT_DEPRECATED_SINCE(6, 8)
+
template <class Enum, if_enum<Enum> = true>
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 void reset(P p) noexcept { ptr = p; }
+ constexpr P operator->() const noexcept { return get(); }
+ constexpr T& operator*() const noexcept { return *get(); }
+
+ explicit constexpr operator bool() const noexcept { return get(); }
+
+private:
+ // TODO: Replace the constraints with std::common_type_t<P, U> when
+ // a bug in VxWorks is fixed!
+ template <typename T, typename U>
+ using if_compatible_types =
+ std::enable_if_t<std::conjunction_v<std::is_pointer<T>,
+ std::is_pointer<U>,
+ std::disjunction<std::is_convertible<T, U>,
+ std::is_convertible<U, T>>>,
+ bool>;
+
+#define MAKE_RELOP(Ret, op, Op) \
+ template <typename U = P, if_compatible_types<P, U> = true> \
+ friend constexpr Ret operator op (const totally_ordered_wrapper<P> &lhs, const totally_ordered_wrapper<U> &rhs) noexcept \
+ { return std:: Op {}(lhs.ptr, rhs.get()); } \
+ template <typename U = P, if_compatible_types<P, U> = true> \
+ friend constexpr Ret operator op (const totally_ordered_wrapper<P> &lhs, const U &rhs) noexcept \
+ { return std:: Op {}(lhs.ptr, rhs ); } \
+ template <typename U = P, if_compatible_types<P, U> = true> \
+ friend constexpr Ret operator op (const U &lhs, const totally_ordered_wrapper<P> &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, P(nullptr)); } \
+ friend constexpr Ret operator op (std::nullptr_t, const totally_ordered_wrapper &rhs) noexcept \
+ { return std:: Op {}(P(nullptr), rhs.ptr); } \
+ /* end */
+ MAKE_RELOP(bool, ==, equal_to<>)
+ MAKE_RELOP(bool, !=, not_equal_to<>)
+ MAKE_RELOP(bool, < , less<>)
+ MAKE_RELOP(bool, <=, less_equal<>)
+ MAKE_RELOP(bool, > , greater<>)
+ MAKE_RELOP(bool, >=, greater_equal<>)
+#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); }
+};
+
+template <typename T, typename U, if_compatible_pointers<T, U> = true>
+constexpr Qt::strong_ordering
+compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, Qt::totally_ordered_wrapper<U*> rhs) noexcept
+{
+ return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
+}
+
+template <typename T, typename U, if_compatible_pointers<T, U> = true>
+constexpr Qt::strong_ordering
+compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, U *rhs) noexcept
+{
+ return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
+}
+
+template <typename T, typename U, if_compatible_pointers<T, U> = true>
+constexpr Qt::strong_ordering
+compareThreeWay(U *lhs, Qt::totally_ordered_wrapper<T*> rhs) noexcept
+{
+ return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
+}
+
+template <typename T>
+constexpr Qt::strong_ordering
+compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, std::nullptr_t rhs) noexcept
+{
+ return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
+}
+
+template <typename T>
+constexpr Qt::strong_ordering
+compareThreeWay(std::nullptr_t lhs, Qt::totally_ordered_wrapper<T*> rhs) noexcept
+{
+ return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
+}
+
+} //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