diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2020-07-06 13:33:56 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2020-07-14 14:52:08 +0200 |
commit | 0b0bc0ce20a2adbf19b6dc1c810e0a2fdbcae71d (patch) | |
tree | dadef45fbcf803c94105f1a768647c5ac682e952 /src/corelib/text/qlocale.cpp | |
parent | 3f8eae848e5cf80b45d226ad3ca07664df0f55c6 (diff) |
QLocalePrivate: rearrange number format statics and tools
Instead of passing lots of instance data around among public static
methods and functions in qlocale_tools, do the work in instance
methods that can access the relevant attributes of the locale when
they need them. Incidentally reduces clutter in the global namespace.
Add a signPrefix() to handle a repeated computation. Keep new internal
methods private.
Change-Id: I9556a960acac9fb645872337c61f509fb902984e
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/text/qlocale.cpp')
-rw-r--r-- | src/corelib/text/qlocale.cpp | 200 |
1 files changed, 115 insertions, 85 deletions
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 79291153d5..bd74a13820 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -2480,13 +2480,9 @@ static char qToLower(char c) QString QLocale::toString(double i, char f, int prec) const { QLocaleData::DoubleForm form = QLocaleData::DFDecimal; - uint flags = 0; + uint flags = qIsUpper(f) ? QLocaleData::CapitalEorX : 0; - if (qIsUpper(f)) - flags = QLocaleData::CapitalEorX; - f = qToLower(f); - - switch (f) { + switch (qToLower(f)) { case 'f': form = QLocaleData::DFDecimal; break; @@ -3332,17 +3328,8 @@ QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime & QString QLocaleData::doubleToString(double d, int precision, DoubleForm form, int width, unsigned flags) const { - return doubleToString(zeroDigit(), positiveSign(), negativeSign(), - exponentSeparator(), groupSeparator(), decimalPoint(), - d, precision, form, width, flags); -} - -QString QLocaleData::doubleToString(const QString &zero, const QString &plus, const QString &minus, - const QString &exponential, - const QString &group, const QString &decimal, - double d, int precision, DoubleForm form, int width, - unsigned flags) -{ + // Undocumented: aside from F.P.Shortest, precision < 0 is treated as + // default, 6 - same as printf(). if (precision != QLocale::FloatingPointShortest && precision < 0) precision = 6; if (width < 0) @@ -3362,10 +3349,13 @@ QString QLocaleData::doubleToString(const QString &zero, const QString &plus, co bool negative = false; qt_doubleToAscii(d, form, precision, buf.data(), bufSize, negative, length, decpt); + const QString prefix = signPrefix(negative && !isZero(d), flags); QString numStr; + if (qstrncmp(buf.data(), "inf", 3) == 0 || qstrncmp(buf.data(), "nan", 3) == 0) { numStr = QString::fromLatin1(buf.data(), length); } else { // Handle finite values + const QString zero = zeroDigit(); QString digits = QString::fromLatin1(buf.data(), length); if (zero == u"0") { @@ -3391,23 +3381,20 @@ QString QLocaleData::doubleToString(const QString &zero, const QString &plus, co const bool mustMarkDecimal = flags & ForcePoint; const bool groupDigits = flags & ThousandsGroup; + const int minExponentDigits = flags & ZeroPadExponent ? 2 : 1; switch (form) { case DFExponent: - numStr = exponentForm(zero, decimal, exponential, group, plus, minus, - digits, decpt, precision, PMDecimalDigits, - mustMarkDecimal, flags & ZeroPadExponent); + numStr = exponentForm(std::move(digits), decpt, precision, PMDecimalDigits, + mustMarkDecimal, minExponentDigits); break; case DFDecimal: - numStr = decimalForm(zero, decimal, group, - digits, decpt, precision, PMDecimalDigits, + numStr = decimalForm(std::move(digits), decpt, precision, PMDecimalDigits, mustMarkDecimal, groupDigits); break; case DFSignificantDigits: { PrecisionMode mode = (flags & AddTrailingZeroes) ? PMSignificantDigits : PMChopTrailingZeros; - const int minExponentDigits = flags & ZeroPadExponent ? 2 : 1; - /* POSIX specifies sprintf() to follow fprintf(), whose 'g/G' format says; with P = 6 if precision unspecified else 1 if precision is 0 else precision; when 'e/E' would have exponent @@ -3460,60 +3447,122 @@ QString QLocaleData::doubleToString(const QString &zero, const QString &plus, co } numStr = useDecimal - ? decimalForm(zero, decimal, group, - digits, decpt, precision, mode, + ? decimalForm(std::move(digits), decpt, precision, mode, mustMarkDecimal, groupDigits) - : exponentForm(zero, decimal, exponential, group, plus, minus, - digits, decpt, precision, mode, - mustMarkDecimal, flags & ZeroPadExponent); + : exponentForm(std::move(digits), decpt, precision, mode, + mustMarkDecimal, minExponentDigits); break; } } - if (isZero(d)) - negative = false; - - // pad with zeros. LeftAdjusted overrides this flag. Also, we don't - // pad special numbers - if (flags & QLocaleData::ZeroPadded && !(flags & QLocaleData::LeftAdjusted)) { - int num_pad_chars = width - numStr.length() / zero.length(); - // leave space for the sign - if (negative - || flags & QLocaleData::AlwaysShowSign - || flags & QLocaleData::BlankBeforePositive) - --num_pad_chars; - - for (int i = 0; i < num_pad_chars; ++i) + // Pad with zeros. LeftAdjusted overrides ZeroPadded. + if (flags & ZeroPadded && !(flags & LeftAdjusted)) { + for (int i = numStr.length() / zero.length() + prefix.size(); i < width; ++i) numStr.prepend(zero); } } - // add sign - if (negative) - numStr.prepend(minus); - else if (flags & QLocaleData::AlwaysShowSign) - numStr.prepend(plus); - else if (flags & QLocaleData::BlankBeforePositive) - numStr.prepend(QLatin1Char(' ')); + return prefix + (flags & CapitalEorX ? std::move(numStr).toUpper() : numStr); +} + +QString QLocaleData::decimalForm(QString &&digits, int decpt, int precision, + PrecisionMode pm, bool mustMarkDecimal, + bool groupDigits) const +{ + const QString zero = zeroDigit(); + const auto digitWidth = zero.size(); + Q_ASSERT(digitWidth == 1 || digitWidth == 2); + Q_ASSERT(digits.size() % digitWidth == 0); - if (flags & QLocaleData::CapitalEorX) - numStr = std::move(numStr).toUpper(); + // Separator needs to go at index decpt: so add zeros before or after the + // given digits, if they don't reach that position already: + if (decpt < 0) { + for (; decpt < 0; ++decpt) + digits.prepend(zero); + } else { + for (int i = digits.length() / digitWidth; i < decpt; ++i) + digits.append(zero); + } + + switch (pm) { + case PMDecimalDigits: + for (int i = digits.length() / digitWidth - decpt; i < precision; ++i) + digits.append(zero); + break; + case PMSignificantDigits: + for (int i = digits.length() / digitWidth; i < precision; ++i) + digits.append(zero); + break; + case PMChopTrailingZeros: + Q_ASSERT(digits.length() / digitWidth <= qMax(decpt, 1) || !digits.endsWith(zero)); + break; + } + + if (mustMarkDecimal || decpt < digits.length() / digitWidth) + digits.insert(decpt * digitWidth, decimalPoint()); + + // FIXME: they're not simply thousands separators ! + // Need to mirror IndianNumberGrouping code in longLongToString() + if (groupDigits) { + const QString group = groupSeparator(); + for (int i = decpt - 3; i > 0; i -= 3) + digits.insert(i * digitWidth, group); + } + + if (decpt == 0) + digits.prepend(zero); - return numStr; + return std::move(digits); } -QString QLocaleData::longLongToString(qlonglong l, int precision, - int base, int width, unsigned flags) const +QString QLocaleData::exponentForm(QString &&digits, int decpt, int precision, + PrecisionMode pm, bool mustMarkDecimal, + int minExponentDigits) const { - return longLongToString(zeroDigit(), groupSeparator(), positiveSign(), negativeSign(), - l, precision, base, width, flags); + const QString zero = zeroDigit(); + const auto digitWidth = zero.size(); + Q_ASSERT(digitWidth == 1 || digitWidth == 2); + Q_ASSERT(digits.size() % digitWidth == 0); + + switch (pm) { + case PMDecimalDigits: + for (int i = digits.length() / digitWidth; i < precision + 1; ++i) + digits.append(zero); + break; + case PMSignificantDigits: + for (int i = digits.length() / digitWidth; i < precision; ++i) + digits.append(zero); + break; + case PMChopTrailingZeros: + Q_ASSERT(digits.length() / digitWidth <= 1 || !digits.endsWith(zero)); + break; + } + + if (mustMarkDecimal || digits.length() > digitWidth) + digits.insert(digitWidth, decimalPoint()); + + digits.append(exponentSeparator()); + digits.append(longLongToString(decpt - 1, minExponentDigits, 10, -1, AlwaysShowSign)); + + return std::move(digits); } -QString QLocaleData::longLongToString(const QString &zero, const QString &group, - const QString &plus, const QString &minus, - qlonglong l, int precision, - int base, int width, unsigned flags) +QString QLocaleData::signPrefix(bool negative, unsigned flags) const { + if (negative) + return negativeSign(); + if (flags & AlwaysShowSign) + return positiveSign(); + if (flags & BlankBeforePositive) + return QStringView(u" ").toString(); + return {}; +} + +QString QLocaleData::longLongToString(qlonglong l, int precision, + int base, int width, unsigned flags) const +{ + const QString zero = zeroDigit(); + bool precision_not_specified = false; if (precision == -1) { precision_not_specified = true; @@ -3542,6 +3591,7 @@ QT_WARNING_POP const auto digitWidth = resultZero.size(); uint cnt_thousand_sep = 0; if (base == 10) { + const QString &group = groupSeparator(); if (flags & ThousandsGroup) { for (int i = num_str.length() / digitWidth - 3; i > 0; i -= 3) { num_str.insert(i * digitWidth, group); @@ -3600,29 +3650,14 @@ QT_WARNING_POP if (base == 2 && (flags & ShowBase)) num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b")); - // add sign - if (negative) - num_str.prepend(minus); - else if (flags & AlwaysShowSign) - num_str.prepend(plus); - else if (flags & BlankBeforePositive) - num_str.prepend(QLatin1Char(' ')); - - return num_str; + return signPrefix(negative, flags) + num_str; } QString QLocaleData::unsLongLongToString(qulonglong l, int precision, int base, int width, unsigned flags) const { - return unsLongLongToString(zeroDigit(), groupSeparator(), positiveSign(), - l, precision, base, width, flags); -} + const QString zero = zeroDigit(); -QString QLocaleData::unsLongLongToString(const QString &zero, const QString &group, - const QString &plus, - qulonglong l, int precision, - int base, int width, unsigned flags) -{ const QString resultZero = base == 10 ? zero : QStringLiteral("0"); QString num_str = l ? qulltoa(l, base, zero) : resultZero; @@ -3638,6 +3673,7 @@ QString QLocaleData::unsLongLongToString(const QString &zero, const QString &gro const auto digitWidth = resultZero.size(); uint cnt_thousand_sep = 0; if (base == 10) { + const QString group = groupSeparator(); if (flags & ThousandsGroup) { for (int i = num_str.length() / digitWidth - 3; i > 0; i -= 3) { num_str.insert(i * digitWidth, group); @@ -3691,13 +3727,7 @@ QString QLocaleData::unsLongLongToString(const QString &zero, const QString &gro else if (base == 2 && flags & ShowBase) num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b")); - // add sign - if (flags & AlwaysShowSign) - num_str.prepend(plus); - else if (flags & BlankBeforePositive) - num_str.prepend(QLatin1Char(' ')); - - return num_str; + return signPrefix(false, flags) + num_str; } /* |