From e8d5000026dbad4f48dfed882f4b19d6c4b34c67 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 10 Jul 2020 12:30:12 +0200 Subject: [PATCH] Use numeric_limits instead of hand-coded equivalents As a comment noted, the reason for QLocaleData rolling its own values describing the ranges of digits and exponents in a double were all about std::numeric_limits's constants not being constexpr - which they have now been since C++11, so we can do away with our own. One of the constants was used in two places in the same way; so abstract that use out into an inline function in qlocale_tools, to save duplication and give somewhere to document it. Change-Id: I7e3740ece9b499c0ec434de18d70abe69e1fe079 Reviewed-by: Thiago Macieira --- src/corelib/text/qlocale.cpp | 7 +++---- src/corelib/text/qlocale_p.h | 11 ----------- src/corelib/text/qlocale_tools.cpp | 13 +++++++------ src/corelib/text/qlocale_tools_p.h | 11 ++++++++++- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 40defe386f..ec5015a077 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -3354,10 +3354,9 @@ QString QLocaleData::doubleToString(const QString &zero, const QString &plus, co int decpt; int bufSize = 1; if (precision == QLocale::FloatingPointShortest) - bufSize += DoubleMaxSignificant; - else if (form == DFDecimal) // optimize for numbers between -512k and 512k - bufSize += ((d > (1 << 19) || d < -(1 << 19)) ? DoubleMaxDigitsBeforeDecimal : 6) + - precision; + bufSize += std::numeric_limits::max_digits10; + else if (form == DFDecimal) + bufSize += wholePartSpace(qAbs(d)) + precision; else // Add extra digit due to different interpretations of precision. Also, "nan" has to fit. bufSize += qMax(2, precision) + 1; diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h index b4064d747b..10d3be6bb8 100644 --- a/src/corelib/text/qlocale_p.h +++ b/src/corelib/text/qlocale_p.h @@ -182,17 +182,6 @@ public: QLocale::Country country); static const QLocaleData *c(); - // Maximum number of significant digits needed to represent a double. - // We cannot use std::numeric_limits here without constexpr. - static const int DoubleMantissaBits = 53; - static const int Log10_2_100000 = 30103; // log10(2) * 100000 - // same as C++11 std::numeric_limits::max_digits10 - static const int DoubleMaxSignificant = (DoubleMantissaBits * Log10_2_100000) / 100000 + 2; - - // Maximum number of digits before decimal point to represent a double - // Same as std::numeric_limits::max_exponent10 + 1 - static const int DoubleMaxDigitsBeforeDecimal = 309; - enum DoubleForm { DFExponent = 0, DFDecimal, diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp index a1838add72..874f42c8e5 100644 --- a/src/corelib/text/qlocale_tools.cpp +++ b/src/corelib/text/qlocale_tools.cpp @@ -139,7 +139,7 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, cha if (precision > 999) precision = 999; else if (precision == QLocale::FloatingPointShortest) - precision = QLocaleData::DoubleMaxSignificant; // "shortest" mode not supported by snprintf + precision = std::numeric_limits::max_digits10; // snprintf lacks "shortest" mode if (isZero(d)) { // Negative zero is expected as simple "0", not "-0". We cannot do d < 0, though. @@ -167,8 +167,8 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, cha switch (form) { case QLocaleData::DFDecimal: format[formatLength - 2] = 'f'; - // '.' '\0' - optimize for numbers smaller than 512k - extraChars = (d > (1 << 19) ? QLocaleData::DoubleMaxDigitsBeforeDecimal : 6) + 2; + // '.' '\0' + extraChars = wholePartSpace(d) + 2; break; case QLocaleData::DFExponent: format[formatLength - 2] = 'e'; @@ -581,9 +581,10 @@ QString qdtoa(qreal d, int *decpt, int *sign) int length = 0; // Some versions of libdouble-conversion like an extra digit, probably for '\0' - char result[QLocaleData::DoubleMaxSignificant + 1]; - qt_doubleToAscii(d, QLocaleData::DFSignificantDigits, QLocale::FloatingPointShortest, result, - QLocaleData::DoubleMaxSignificant + 1, nonNullSign, length, nonNullDecpt); + constexpr int digits = std::numeric_limits::max_digits10 + 1; + char result[digits]; + qt_doubleToAscii(d, QLocaleData::DFSignificantDigits, QLocale::FloatingPointShortest, + result, digits, nonNullSign, length, nonNullDecpt); if (sign) *sign = nonNullSign ? 1 : 0; diff --git a/src/corelib/text/qlocale_tools_p.h b/src/corelib/text/qlocale_tools_p.h index f04c4512c0..ee6e1e5115 100644 --- a/src/corelib/text/qlocale_tools_p.h +++ b/src/corelib/text/qlocale_tools_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -98,6 +98,15 @@ inline bool isZero(double d) } } +// Enough space for the digits before the decimal separator: +inline int wholePartSpace(double d) +{ + Q_ASSERT(d >= 0); // caller should call qAbs() if needed + // Optimize for numbers between -512k and 512k - otherwise, use the + // maximum number of digits in the whole number part of a double: + return d > (1 << 19) ? std::numeric_limits::max_exponent10 + 1 : 6; +} + Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); Q_CORE_EXPORT double qstrntod(const char *s00, int len, char const **se, bool *ok); qlonglong qstrtoll(const char *nptr, const char **endptr, int base, bool *ok);