Refactor QLocale's integer formatting

Break out some shared code in the integer formatting to save
duplicating it. Simplify what's left.
Renamed some variables to match Qt style.

Change-Id: I369a013802a267a94725302de0d1d33291c29538
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2020-07-06 13:33:56 +02:00
parent 0b0bc0ce20
commit 19ed60d703
2 changed files with 49 additions and 125 deletions

View File

@ -3561,14 +3561,6 @@ QString QLocaleData::signPrefix(bool negative, unsigned flags) const
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;
precision = 1;
}
bool negative = l < 0;
if (base != 10) {
// these are not supported by sprintf for octal and hex
@ -3584,150 +3576,80 @@ QT_WARNING_DISABLE_MSVC(4146)
Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
taking an absolute value has to cast to unsigned to change sign.
*/
QString num_str = qulltoa(negative ? -qulonglong(l) : qulonglong(l), base, zero);
QString numStr = qulltoa(negative ? -qulonglong(l) : qulonglong(l), base, zeroDigit());
QT_WARNING_POP
const QString resultZero = base == 10 ? zero : QStringLiteral("0");
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);
++cnt_thousand_sep;
}
} else if (flags & IndianNumberGrouping) {
const int size = num_str.length();
if (size > 3 * digitWidth)
num_str.insert(size - 3 * digitWidth , group);
for (int i = size / digitWidth - 5; i > 0; i -= 2) {
num_str.insert(i * digitWidth, group);
++cnt_thousand_sep;
}
}
}
for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i)
num_str.prepend(resultZero);
if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
// LeftAdjusted overrides this flag ZeroPadded. sprintf only padds
// when precision is not specified in the format string
bool zero_padded = flags & ZeroPadded
&& !(flags & LeftAdjusted)
&& precision_not_specified;
if (zero_padded) {
int num_pad_chars = width - num_str.length() / digitWidth;
// leave space for the sign
if (negative
|| flags & AlwaysShowSign
|| flags & BlankBeforePositive)
--num_pad_chars;
// leave space for optional '0x' in hex form
if (base == 16 && (flags & ShowBase))
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
else if (base == 2 && (flags & ShowBase))
num_pad_chars -= 2;
while (num_pad_chars-- > 0)
num_str.prepend(resultZero);
}
if (flags & CapitalEorX)
num_str = std::move(num_str).toUpper();
if (base == 16 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
if (base == 2 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
return signPrefix(negative, flags) + num_str;
return applyIntegerFormatting(std::move(numStr), negative, precision, base, width, flags);
}
QString QLocaleData::unsLongLongToString(qulonglong l, int precision,
int base, int width, unsigned flags) const
{
const QString zero = zeroDigit();
QString resultZero = base == 10 ? zero : QStringLiteral("0");
return applyIntegerFormatting(l ? qulltoa(l, base, zero) : resultZero,
false, precision, base, width, flags);
}
const QString resultZero = base == 10 ? zero : QStringLiteral("0");
QString num_str = l ? qulltoa(l, base, zero) : resultZero;
QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int precision,
int base, int width, unsigned flags) const
{
const QString zero = base == 10 ? zeroDigit() : QStringLiteral("0");
const auto digitWidth = zero.size();
const auto digitCount = numStr.length() / digitWidth;
bool precision_not_specified = false;
if (precision == -1) {
if (flags == NoFlags)
return num_str; // fast-path: nothing below applies, so we're done.
const auto basePrefix = [numStr, zero, base, flags] () -> QStringView {
if (flags & ShowBase) {
const bool upper = flags & UppercaseBase;
if (base == 16)
return upper ? u"0X" : u"0x";
if (base == 2)
return upper ? u"0B" : u"0b";
if (base == 8 && !numStr.startsWith(zero))
return zero;
}
return {};
};
precision_not_specified = true;
precision = 1;
}
const QString prefix = signPrefix(negative, flags) + basePrefix();
// Count how much of width we've used up. Each digit counts as one
int usedWidth = digitCount + prefix.size();
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);
++cnt_thousand_sep;
for (int i = numStr.length() / digitWidth - 3; i > 0; i -= 3) {
numStr.insert(i * digitWidth, group);
++usedWidth;
}
} else if (flags & IndianNumberGrouping) {
const int size = num_str.length();
const int size = numStr.length();
if (size > 3 * digitWidth)
num_str.insert(size - 3 * digitWidth , group);
numStr.insert(size - 3 * digitWidth , group);
for (int i = size / digitWidth - 5; i > 0; i -= 2) {
num_str.insert(i * digitWidth, group);
++cnt_thousand_sep;
numStr.insert(i * digitWidth, group);
++usedWidth;
}
}
}
int zeroPadding = precision - num_str.length() / digitWidth /* + cnt_thousand_sep*/;
while (zeroPadding-- > 0)
num_str.prepend(resultZero);
const bool noPrecision = precision == -1;
if (noPrecision)
precision = 1;
if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str.at(0).unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
// LeftAdjusted overrides this flag ZeroPadded. sprintf only padds
// when precision is not specified in the format string
bool zero_padded = flags & ZeroPadded
&& !(flags & LeftAdjusted)
&& precision_not_specified;
if (zero_padded) {
int num_pad_chars = width - num_str.length() / digitWidth;
// leave space for optional '0x' in hex form
if (base == 16 && flags & ShowBase)
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
else if (base == 2 && flags & ShowBase)
num_pad_chars -= 2;
while (num_pad_chars-- > 0)
num_str.prepend(resultZero);
for (int i = numStr.length(); i < precision; ++i) {
numStr.prepend(zero);
usedWidth++;
}
if (flags & CapitalEorX)
num_str = std::move(num_str).toUpper();
// LeftAdjusted overrides ZeroPadded; and sprintf() only pads when
// precision is not specified in the format string.
if (noPrecision && flags & ZeroPadded && !(flags & LeftAdjusted)) {
for (int i = usedWidth; i < width; ++i)
numStr.prepend(zero);
}
if (base == 16 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
else if (base == 2 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
return signPrefix(false, flags) + num_str;
return prefix + (flags & CapitalEorX ? std::move(numStr).toUpper() : numStr);
}
/*

View File

@ -224,6 +224,8 @@ private:
PrecisionMode pm, bool mustMarkDecimal,
int minExponentDigits) const;
QString signPrefix(bool negative, unsigned flags) const;
QString applyIntegerFormatting(QString &&numStr, bool negative, int precision,
int base, int width, unsigned flags) const;
public:
QString doubleToString(double d,