summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qfloat16.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/global/qfloat16.h')
-rw-r--r--src/corelib/global/qfloat16.h164
1 files changed, 105 insertions, 59 deletions
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
index 76ea990c33..30dd9a60af 100644
--- a/src/corelib/global/qfloat16.h
+++ b/src/corelib/global/qfloat16.h
@@ -5,16 +5,17 @@
#ifndef QFLOAT16_H
#define QFLOAT16_H
+#include <QtCore/qcompare.h>
#include <QtCore/qglobal.h>
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qmath.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtypes.h>
+
#include <limits>
#include <string.h>
-
-#if defined(__STDCPP_FLOAT16_T__) && __has_include(<stdfloat>)
-// P1467 implementation - https://wg21.link/p1467
-# include <stdfloat>
-#endif
+#include <type_traits>
#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__AVX2__) && !defined(__F16C__)
// All processors that support AVX2 do support F16C too, so we could enable the
@@ -52,25 +53,22 @@ class qfloat16
constexpr inline explicit Wrap(int value) : b16(quint16(value)) {}
};
-public:
-#if defined(__STDCPP_FLOAT16_T__)
-# define QFLOAT16_IS_NATIVE 1
- using NativeType = std::float16_t;
-#elif defined(Q_CC_CLANG) && defined(__FLT16_MAX__) && 0
- // disabled due to https://github.com/llvm/llvm-project/issues/56963
-# define QFLOAT16_IS_NATIVE 1
- using NativeType = decltype(__FLT16_MAX__);
-#elif defined(Q_CC_GNU_ONLY) && defined(__FLT16_MAX__)
-# define QFLOAT16_IS_NATIVE 1
-# ifdef __ARM_FP16_FORMAT_IEEE
- using NativeType = __fp16;
-# else
- using NativeType = _Float16;
-# endif
+#ifdef QT_SUPPORTS_INT128
+ template <typename T>
+ using IsIntegral = std::disjunction<std::is_integral<T>,
+ std::is_same<std::remove_const_t<T>, qint128>,
+ std::is_same<std::remove_const_t<T>, quint128>>;
#else
-# define QFLOAT16_IS_NATIVE 0
- using NativeType = void;
+ template <typename T>
+ using IsIntegral = std::is_integral<T>;
#endif
+ template <typename T>
+ using if_type_is_integral = std::enable_if_t<IsIntegral<std::remove_reference_t<T>>::value,
+ bool>;
+
+public:
+ using NativeType = QtPrivate::NativeFloat16Type;
+
static constexpr bool IsNative = QFLOAT16_IS_NATIVE;
using NearestFloat = std::conditional_t<IsNative, NativeType, float>;
@@ -96,6 +94,22 @@ public:
qfloat16 copySign(qfloat16 sign) const noexcept
{ return qfloat16(Wrap((sign.b16 & 0x8000) | (b16 & 0x7fff))); }
// Support for std::numeric_limits<qfloat16>
+
+#ifdef __STDCPP_FLOAT16_T__
+private:
+ using Bounds = std::numeric_limits<NativeType>;
+public:
+ static constexpr qfloat16 _limit_epsilon() noexcept { return Bounds::epsilon(); }
+ static constexpr qfloat16 _limit_min() noexcept { return Bounds::min(); }
+ static constexpr qfloat16 _limit_denorm_min() noexcept { return Bounds::denorm_min(); }
+ static constexpr qfloat16 _limit_max() noexcept { return Bounds::max(); }
+ static constexpr qfloat16 _limit_lowest() noexcept { return Bounds::lowest(); }
+ static constexpr qfloat16 _limit_infinity() noexcept { return Bounds::infinity(); }
+ static constexpr qfloat16 _limit_quiet_NaN() noexcept { return Bounds::quiet_NaN(); }
+#if QT_CONFIG(signaling_nan)
+ static constexpr qfloat16 _limit_signaling_NaN() noexcept { return Bounds::signaling_NaN(); }
+#endif
+#else
static constexpr qfloat16 _limit_epsilon() noexcept { return qfloat16(Wrap(0x1400)); }
static constexpr qfloat16 _limit_min() noexcept { return qfloat16(Wrap(0x400)); }
static constexpr qfloat16 _limit_denorm_min() noexcept { return qfloat16(Wrap(1)); }
@@ -106,6 +120,7 @@ public:
#if QT_CONFIG(signaling_nan)
static constexpr qfloat16 _limit_signaling_NaN() noexcept { return qfloat16(Wrap(0x7d00)); }
#endif
+#endif
inline constexpr bool isNormal() const noexcept
{ return (b16 & 0x7c00) && (b16 & 0x7c00) != 0x7c00; }
private:
@@ -121,7 +136,13 @@ private:
NativeType nf;
#endif
};
- constexpr inline explicit qfloat16(Wrap nibble) noexcept : b16(nibble.b16) {}
+ constexpr inline explicit qfloat16(Wrap nibble) noexcept :
+#if QFLOAT16_IS_NATIVE && defined(__cpp_lib_bit_cast)
+ nf(std::bit_cast<NativeType>(nibble.b16))
+#else
+ b16(nibble.b16)
+#endif
+ {}
Q_CORE_EXPORT static const quint32 mantissatable[];
Q_CORE_EXPORT static const quint32 exponenttable[];
@@ -144,6 +165,12 @@ private:
friend inline qfloat16 operator*(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) * static_cast<NearestFloat>(b)); }
friend inline qfloat16 operator/(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) / static_cast<NearestFloat>(b)); }
+ friend size_t qHash(qfloat16 key, size_t seed = 0) noexcept
+ { return qHash(float(key), seed); } // 6.4 algorithm, so keep using it; ### Qt 7: fix QTBUG-116077
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wfloat-conversion")
+
#define QF16_MAKE_ARITH_OP_FP(FP, OP) \
friend inline FP operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \
friend inline FP operator OP(FP lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<FP>(rhs); }
@@ -179,44 +206,63 @@ private:
QF16_MAKE_ARITH_OP_INT(/)
#undef QF16_MAKE_ARITH_OP_INT
-QT_WARNING_PUSH
QT_WARNING_DISABLE_FLOAT_COMPARE
- friend inline bool operator>(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) > static_cast<NearestFloat>(b); }
- friend inline bool operator<(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) < static_cast<NearestFloat>(b); }
- friend inline bool operator>=(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) >= static_cast<NearestFloat>(b); }
- friend inline bool operator<=(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) <= static_cast<NearestFloat>(b); }
- friend inline bool operator==(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) == static_cast<NearestFloat>(b); }
- friend inline bool operator!=(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) != static_cast<NearestFloat>(b); }
-
-#define QF16_MAKE_BOOL_OP_FP(FP, OP) \
- friend inline bool operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \
- friend inline bool operator OP(FP lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<FP>(rhs); }
-#define QF16_MAKE_BOOL_OP(FP) \
- QF16_MAKE_BOOL_OP_FP(FP, <) \
- QF16_MAKE_BOOL_OP_FP(FP, >) \
- QF16_MAKE_BOOL_OP_FP(FP, >=) \
- QF16_MAKE_BOOL_OP_FP(FP, <=) \
- QF16_MAKE_BOOL_OP_FP(FP, ==) \
- QF16_MAKE_BOOL_OP_FP(FP, !=)
-
- QF16_MAKE_BOOL_OP(long double)
- QF16_MAKE_BOOL_OP(double)
- QF16_MAKE_BOOL_OP(float)
-#undef QF16_MAKE_BOOL_OP
-#undef QF16_MAKE_BOOL_OP_FP
-
-#define QF16_MAKE_BOOL_OP_INT(OP) \
- friend inline bool operator OP(qfloat16 a, int b) noexcept { return static_cast<NearestFloat>(a) OP static_cast<NearestFloat>(b); } \
- friend inline bool operator OP(int a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) OP static_cast<NearestFloat>(b); }
-
- QF16_MAKE_BOOL_OP_INT(>)
- QF16_MAKE_BOOL_OP_INT(<)
- QF16_MAKE_BOOL_OP_INT(>=)
- QF16_MAKE_BOOL_OP_INT(<=)
- QF16_MAKE_BOOL_OP_INT(==)
- QF16_MAKE_BOOL_OP_INT(!=)
-#undef QF16_MAKE_BOOL_OP_INT
+#if QFLOAT16_IS_NATIVE
+# define QF16_CONSTEXPR constexpr
+# define QF16_PARTIALLY_ORDERED Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE
+#else
+# define QF16_CONSTEXPR
+# define QF16_PARTIALLY_ORDERED Q_DECLARE_PARTIALLY_ORDERED
+#endif
+
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, const qfloat16 &rhs) noexcept
+ { return static_cast<NearestFloat>(lhs) == static_cast<NearestFloat>(rhs); }
+ friend QF16_CONSTEXPR
+ Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, const qfloat16 &rhs) noexcept
+ { return Qt::compareThreeWay(static_cast<NearestFloat>(lhs), static_cast<NearestFloat>(rhs)); }
+ QF16_PARTIALLY_ORDERED(qfloat16)
+
+#define QF16_MAKE_ORDER_OP_FP(FP) \
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, FP rhs) noexcept \
+ { return static_cast<FP>(lhs) == rhs; } \
+ friend QF16_CONSTEXPR \
+ Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, FP rhs) noexcept \
+ { return Qt::compareThreeWay(static_cast<FP>(lhs), rhs); } \
+ QF16_PARTIALLY_ORDERED(qfloat16, FP)
+
+ QF16_MAKE_ORDER_OP_FP(long double)
+ QF16_MAKE_ORDER_OP_FP(double)
+ QF16_MAKE_ORDER_OP_FP(float)
+#if QFLOAT16_IS_NATIVE
+ QF16_MAKE_ORDER_OP_FP(qfloat16::NativeType)
+#endif
+#undef QF16_MAKE_ORDER_OP_FP
+
+ template <typename T, if_type_is_integral<T> = true>
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, T rhs) noexcept
+ { return static_cast<NearestFloat>(lhs) == static_cast<NearestFloat>(rhs); }
+ template <typename T, if_type_is_integral<T> = true>
+ friend QF16_CONSTEXPR Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, T rhs) noexcept
+ { return Qt::compareThreeWay(static_cast<NearestFloat>(lhs), static_cast<NearestFloat>(rhs)); }
+
+ QF16_PARTIALLY_ORDERED(qfloat16, qint8)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint8)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint16)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint16)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint32)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint32)
+ QF16_PARTIALLY_ORDERED(qfloat16, long)
+ QF16_PARTIALLY_ORDERED(qfloat16, unsigned long)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint64)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint64)
+#ifdef QT_SUPPORTS_INT128
+ QF16_PARTIALLY_ORDERED(qfloat16, qint128)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint128)
+#endif
+
+#undef QF16_PARTIALLY_ORDERED
+#undef QF16_CONSTEXPR
QT_WARNING_POP