diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2024-02-29 08:27:26 -0800 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2024-03-04 11:31:48 -0800 |
commit | a14bba6803f674edede596eaeb5a46feed0f889e (patch) | |
tree | 808755cce4a0a777c4843de1bf996d6ce16c5464 | |
parent | 26f307ddb16563777bbd57ba1f29d656760c7ff3 (diff) |
Move QLocaleData::convertDoubleToFloat to qnumeric_p.h
So others can use it too.
Change-Id: I01ec3c774d9943adb903fffd17b86236d06a948c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r-- | src/corelib/global/qnumeric_p.h | 45 | ||||
-rw-r--r-- | src/corelib/text/qlocale_p.h | 23 |
2 files changed, 48 insertions, 20 deletions
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 40c459991c..bdace21000 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -51,6 +51,8 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE +class qfloat16; + namespace qnumeric_std_wrapper { #if defined(QT_MATH_H_DEFINES_MACROS) # undef QT_MATH_H_DEFINES_MACROS @@ -145,15 +147,16 @@ namespace { it's out of range. If the conversion is successful, the converted value is stored in \a value; if it was not successful, \a value will contain the minimum or maximum of T, depending on the sign of \a d. If \c T is - unsigned, then \a value contains the absolute value of \a v. + unsigned, then \a value contains the absolute value of \a v. If \c T is \c + float, an underflow is also signalled by returning false and setting \a + value to zero. This function works for v containing infinities, but not NaN. It's the caller's responsibility to exclude that possibility before calling it. */ -template<typename T> -static inline bool convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true) +template <typename T> static inline std::enable_if_t<std::is_integral_v<T>, bool> +convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true) { - static_assert(std::numeric_limits<T>::is_integer); static_assert(std::is_integral_v<T>); constexpr bool TypeIsLarger = std::numeric_limits<T>::digits > std::numeric_limits<double>::digits; @@ -278,6 +281,40 @@ QT_WARNING_DISABLE_FLOAT_COMPARE QT_WARNING_POP } +template <typename T> static inline +std::enable_if_t<std::is_floating_point_v<T> || std::is_same_v<T, qfloat16>, bool> +convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true) +{ + Q_UNUSED(allow_precision_upgrade); + constexpr T Huge = std::numeric_limits<T>::infinity(); + + if constexpr (std::numeric_limits<double>::max_exponent <= + std::numeric_limits<T>::max_exponent) { + // no UB can happen + *value = T(v); + return true; + } + if (!qt_is_finite(v) && std::numeric_limits<T>::has_infinity) { + // infinity (or NaN) + *value = T(v); + return true; + } + + // Check for in-range value to ensure the conversion is not UB (see the + // comment above for Standard language). + if (std::fabs(v) > (std::numeric_limits<T>::max)()) { + *value = v < 0 ? -Huge : Huge; + return false; + } + + *value = T(v); + if (v != 0 && *value == 0) { + // Underflow through loss of precision + return false; + } + return true; +} + template <typename T> inline bool add_overflow(T v1, T v2, T *r) { return qAddOverflow(v1, v2, r); } template <typename T> inline bool sub_overflow(T v1, T v2, T *r) { return qSubOverflow(v1, v2, r); } template <typename T> inline bool mul_overflow(T v1, T v2, T *r) { return qMulOverflow(v1, v2, r); } diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h index ee0a28e94e..fb312c5dfb 100644 --- a/src/corelib/text/qlocale_p.h +++ b/src/corelib/text/qlocale_p.h @@ -18,10 +18,10 @@ #include "qlocale.h" -#include <QtCore/private/qglobal_p.h> #include <QtCore/qcalendar.h> #include <QtCore/qlist.h> #include <QtCore/qnumeric.h> +#include <QtCore/private/qnumeric_p.h> #include <QtCore/qstring.h> #include <QtCore/qvariant.h> #include <QtCore/qvarlengtharray.h> @@ -304,23 +304,14 @@ public: unsigned flags = NoFlags) const; // this function is meant to be called with the result of stringToDouble or bytearrayToDouble + // so *ok must have been properly set (if not null) [[nodiscard]] static float convertDoubleToFloat(double d, bool *ok) { - if (qIsInf(d)) - return float(d); - if (std::fabs(d) > (std::numeric_limits<float>::max)()) { - if (ok) - *ok = false; - const float huge = std::numeric_limits<float>::infinity(); - return d < 0 ? -huge : huge; - } - if (d != 0 && float(d) == 0) { - // Values that underflow double already failed. Match them: - if (ok) - *ok = false; - return 0; - } - return float(d); + float result; + bool b = convertDoubleTo<float>(d, &result); + if (ok && *ok) + *ok = b; + return result; } [[nodiscard]] double stringToDouble(QStringView str, bool *ok, |