From 07ac4690c707d8552f251ce2f602c537495c07c4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 10 Nov 2022 23:00:16 -0800 Subject: [PATCH] QLocale: make qt_doubleToAscii not have output arguments Repeat the last commit, now for floating point parsing (and without the benchmarking). Like the last commit, removes one category of parsing, when we would return an advanced parsing pointer and still fail. Change-Id: Ieba79baf5ac34264a988fffd1726759a2359828d Reviewed-by: Edward Welbourne --- src/corelib/text/qbytearray.cpp | 8 ++-- src/corelib/text/qlocale.cpp | 8 ++-- src/corelib/text/qlocale_tools.cpp | 65 ++++++++++-------------------- src/corelib/text/qlocale_tools_p.h | 5 ++- 4 files changed, 31 insertions(+), 55 deletions(-) diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 0f6e57e38b..388646f3f3 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -3982,11 +3982,9 @@ double QByteArray::toDouble(bool *ok) const auto QtPrivate::toDouble(QByteArrayView a) noexcept -> ParsedNumber { - bool nonNullOk = false; - int processed = 0; - double d = qt_asciiToDouble(a.data(), a.size(), nonNullOk, processed, WhitespacesAllowed); - if (nonNullOk) - return ParsedNumber{d}; + auto r = qt_asciiToDouble(a.data(), a.size(), WhitespacesAllowed); + if (r.ok()) + return ParsedNumber{r.result}; else return {}; } diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 16c80dd667..97d84eac4e 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -4111,12 +4111,10 @@ double QLocaleData::stringToDouble(QStringView str, bool *ok, *ok = false; return 0.0; } - int processed = 0; - bool nonNullOk = false; - double d = qt_asciiToDouble(buff.constData(), buff.size() - 1, nonNullOk, processed); + auto r = qt_asciiToDouble(buff.constData(), buff.size() - 1); if (ok != nullptr) - *ok = nonNullOk; - return d; + *ok = r.ok(); + return r.result; } qlonglong QLocaleData::stringToLongLong(QStringView str, int base, bool *ok, diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp index 76ea6c9f33..405f096420 100644 --- a/src/corelib/text/qlocale_tools.cpp +++ b/src/corelib/text/qlocale_tools.cpp @@ -247,48 +247,38 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, --length; } -double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &processed, - StrayCharacterMode strayCharMode) +QSimpleParsedNumber qt_asciiToDouble(const char *num, qsizetype numLen, + StrayCharacterMode strayCharMode) { auto string_equals = [](const char *needle, const char *haystack, qsizetype haystackLen) { qsizetype needleLen = strlen(needle); return needleLen == haystackLen && memcmp(needle, haystack, haystackLen) == 0; }; - if (numLen <= 0) { - ok = false; - processed = 0; - return 0.0; - } - - ok = true; + if (numLen <= 0) + return {}; // We have to catch NaN before because we need NaN as marker for "garbage" in the // libdouble-conversion case and, in contrast to libdouble-conversion or sscanf, we don't allow // "-nan" or "+nan" if (string_equals("nan", num, numLen)) { - processed = 3; - return qt_qnan(); + return { qt_qnan(), num + 3 }; } else if (string_equals("+nan", num, numLen) || string_equals("-nan", num, numLen)) { - processed = 0; - ok = false; - return 0.0; + return {}; } // Infinity values are implementation defined in the sscanf case. In the libdouble-conversion // case we need infinity as overflow marker. if (string_equals("+inf", num, numLen)) { - processed = 4; - return qt_inf(); + return { qt_inf(), num + 4 }; } else if (string_equals("inf", num, numLen)) { - processed = 3; - return qt_inf(); + return { qt_inf(), num + 3 }; } else if (string_equals("-inf", num, numLen)) { - processed = 4; - return -qt_inf(); + return { -qt_inf(), num + 4 }; } double d = 0.0; + int processed; #if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED) int conv_flags = double_conversion::StringToDoubleConverter::NO_FLAGS; if (strayCharMode == TrailingJunkAllowed) { @@ -300,22 +290,18 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces double_conversion::StringToDoubleConverter conv(conv_flags, 0.0, qt_qnan(), nullptr, nullptr); if (int(numLen) != numLen) { // a number over 2 GB in length is silly, just assume it isn't valid - ok = false; - processed = 0; - return 0.0; + return {}; } else { d = conv.StringToDouble(num, numLen, &processed); } if (!qIsFinite(d)) { - ok = false; if (qIsNaN(d)) { // Garbage found. We don't accept it and return 0. - processed = 0; - return 0.0; + return {}; } else { // Overflow. That's not OK, but we still return infinity. - return d; + return { d, nullptr }; } } #else @@ -330,25 +316,21 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces if ((strayCharMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d)) { // Implementation defined nan symbol or garbage found. We don't accept it. - processed = 0; - ok = false; - return 0.0; + return {}; } if (!qIsFinite(d)) { // Overflow. Check for implementation-defined infinity symbols and reject them. // We assume that any infinity symbol has to contain a character that cannot be part of a // "normal" number (that is 0-9, ., -, +, e). - ok = false; for (int i = 0; i < processed; ++i) { char c = num[i]; if ((c < '0' || c > '9') && c != '.' && c != '-' && c != '+' && c != 'e' && c != 'E') { // Garbage found - processed = 0; - return 0.0; + return {}; } } - return d; + return { d, nullptr }; } #endif // !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED) @@ -360,14 +342,13 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces for (int i = 0; i < processed; ++i) { if (num[i] >= '1' && num[i] <= '9') { // if a digit before any 'e' is not 0, then a non-zero number was intended. - ok = false; - return 0.0; + return {}; } else if (num[i] == 'e' || num[i] == 'E') { break; } } } - return d; + return { d, num + processed }; } /* Detect base if 0 and, if base is hex or bin, skip over 0x/0b prefixes */ @@ -563,14 +544,12 @@ QString qulltoa(qulonglong number, int base, const QStringView zero) */ double qstrntod(const char *s00, qsizetype len, const char **se, bool *ok) { - int processed = 0; - bool nonNullOk = false; - double d = qt_asciiToDouble(s00, len, nonNullOk, processed, TrailingJunkAllowed); + auto r = qt_asciiToDouble(s00, len, TrailingJunkAllowed); if (se) - *se = s00 + processed; + *se = r.endptr ? r.endptr : s00; if (ok) - *ok = nonNullOk; - return d; + *ok = r.ok(); + return r.result; } QString qdtoa(qreal d, int *decpt, int *sign) diff --git a/src/corelib/text/qlocale_tools_p.h b/src/corelib/text/qlocale_tools_p.h index b5eb4d344b..c01bf617da 100644 --- a/src/corelib/text/qlocale_tools_p.h +++ b/src/corelib/text/qlocale_tools_p.h @@ -34,8 +34,9 @@ template struct QSimpleParsedNumber }; // API note: this function can't process a number with more than 2.1 billion digits -[[nodiscard]] double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &processed, - StrayCharacterMode strayCharMode = TrailingJunkProhibited); +[[nodiscard]] QSimpleParsedNumber +qt_asciiToDouble(const char *num, qsizetype numLen, + StrayCharacterMode strayCharMode = TrailingJunkProhibited); void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, qsizetype bufSize, bool &sign, int &length, int &decpt);