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>
bb10
Thiago Macieira 2024-02-29 08:27:26 -08:00
parent 26f307ddb1
commit a14bba6803
2 changed files with 48 additions and 20 deletions

View File

@ -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); }

View File

@ -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,