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>
This commit is contained in:
parent
3f8eae848e
commit
0b0bc0ce20
@ -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
|
||||
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);
|
||||
|
||||
// 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 std::move(digits);
|
||||
}
|
||||
|
||||
QString QLocaleData::exponentForm(QString &&digits, int decpt, int precision,
|
||||
PrecisionMode pm, bool mustMarkDecimal,
|
||||
int minExponentDigits) const
|
||||
{
|
||||
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::signPrefix(bool negative, unsigned flags) const
|
||||
{
|
||||
if (negative)
|
||||
numStr.prepend(minus);
|
||||
else if (flags & QLocaleData::AlwaysShowSign)
|
||||
numStr.prepend(plus);
|
||||
else if (flags & QLocaleData::BlankBeforePositive)
|
||||
numStr.prepend(QLatin1Char(' '));
|
||||
|
||||
if (flags & QLocaleData::CapitalEorX)
|
||||
numStr = std::move(numStr).toUpper();
|
||||
|
||||
return numStr;
|
||||
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
|
||||
{
|
||||
return longLongToString(zeroDigit(), groupSeparator(), positiveSign(), negativeSign(),
|
||||
l, precision, base, width, flags);
|
||||
}
|
||||
const QString zero = zeroDigit();
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -210,20 +210,22 @@ public:
|
||||
|
||||
typedef QVarLengthArray<char, 256> CharBuff;
|
||||
|
||||
static QString doubleToString(const QString &zero, const QString &plus,
|
||||
const QString &minus, const QString &exponent,
|
||||
const QString &group, const QString &decimal,
|
||||
double d, int precision, DoubleForm form,
|
||||
int width, unsigned flags);
|
||||
static QString longLongToString(const QString &zero, const QString &group,
|
||||
const QString &plus, const QString &minus,
|
||||
qint64 l, int precision, int base,
|
||||
int width, unsigned flags);
|
||||
static QString unsLongLongToString(const QString &zero, const QString &group,
|
||||
const QString &plus,
|
||||
quint64 l, int precision,
|
||||
int base, int width, unsigned flags);
|
||||
private:
|
||||
enum PrecisionMode {
|
||||
PMDecimalDigits = 0x01,
|
||||
PMSignificantDigits = 0x02,
|
||||
PMChopTrailingZeros = 0x03
|
||||
};
|
||||
|
||||
QString decimalForm(QString &&digits, int decpt, int precision,
|
||||
PrecisionMode pm, bool mustMarkDecimal,
|
||||
bool groupDigits) const;
|
||||
QString exponentForm(QString &&digits, int decpt, int precision,
|
||||
PrecisionMode pm, bool mustMarkDecimal,
|
||||
int minExponentDigits) const;
|
||||
QString signPrefix(bool negative, unsigned flags) const;
|
||||
|
||||
public:
|
||||
QString doubleToString(double d,
|
||||
int precision = -1,
|
||||
DoubleForm form = DFSignificantDigits,
|
||||
|
@ -467,91 +467,6 @@ QString qulltoa(qulonglong number, int base, const QStringView zero)
|
||||
return QString(reinterpret_cast<QChar *>(p), end - p);
|
||||
}
|
||||
|
||||
QString &decimalForm(const QString &zero, const QString &decimal, const QString &group,
|
||||
QString &digits, int decpt, int precision,
|
||||
PrecisionMode pm,
|
||||
bool always_show_decpt,
|
||||
bool thousands_group)
|
||||
{
|
||||
const auto digitWidth = zero.size();
|
||||
Q_ASSERT(digitWidth == 1 || digitWidth == 2);
|
||||
Q_ASSERT(digits.size() % digitWidth == 0);
|
||||
|
||||
if (decpt < 0) {
|
||||
for (int i = 0; i < -decpt; ++i)
|
||||
digits.prepend(zero);
|
||||
decpt = 0;
|
||||
} 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 (always_show_decpt || decpt < digits.length() / digitWidth)
|
||||
digits.insert(decpt * digitWidth, decimal);
|
||||
|
||||
// FIXME: they're not simply thousands separators !
|
||||
// Need to mirror IndianNumberGrouping code in QLocaleData::longLongToString()
|
||||
if (thousands_group) {
|
||||
for (int i = decpt - 3; i > 0; i -= 3)
|
||||
digits.insert(i * digitWidth, group);
|
||||
}
|
||||
|
||||
if (decpt == 0)
|
||||
digits.prepend(zero);
|
||||
|
||||
return digits;
|
||||
}
|
||||
|
||||
QString &exponentForm(const QString &zero, const QString &decimal, const QString &exponential,
|
||||
const QString &group, const QString &plus, const QString &minus,
|
||||
QString &digits, int decpt, int precision,
|
||||
PrecisionMode pm,
|
||||
bool always_show_decpt,
|
||||
bool leading_zero_in_exponent)
|
||||
{
|
||||
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 (always_show_decpt || digits.length() > digitWidth)
|
||||
digits.insert(digitWidth, decimal);
|
||||
|
||||
digits.append(exponential);
|
||||
digits.append(QLocaleData::longLongToString(zero, group, plus, minus, decpt - 1,
|
||||
leading_zero_in_exponent ? 2 : 1,
|
||||
10, -1, QLocaleData::AlwaysShowSign));
|
||||
|
||||
return digits;
|
||||
}
|
||||
|
||||
double qstrtod(const char *s00, const char **se, bool *ok)
|
||||
{
|
||||
const int len = static_cast<int>(strlen(s00));
|
||||
|
@ -70,24 +70,6 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, cha
|
||||
QString qulltoa(qulonglong l, int base, const QStringView zero);
|
||||
Q_CORE_EXPORT QString qdtoa(qreal d, int *decpt, int *sign);
|
||||
|
||||
enum PrecisionMode {
|
||||
PMDecimalDigits = 0x01,
|
||||
PMSignificantDigits = 0x02,
|
||||
PMChopTrailingZeros = 0x03
|
||||
};
|
||||
|
||||
QString &decimalForm(const QString &zero, const QString &decimal, const QString &group,
|
||||
QString &digits, int decpt, int precision,
|
||||
PrecisionMode pm,
|
||||
bool always_show_decpt,
|
||||
bool thousands_group);
|
||||
QString &exponentForm(const QString &zero, const QString &decimal, const QString &exponential,
|
||||
const QString &group, const QString &plus, const QString &minus,
|
||||
QString &digits, int decpt, int precision,
|
||||
PrecisionMode pm,
|
||||
bool always_show_decpt,
|
||||
bool leading_zero_in_exponent);
|
||||
|
||||
inline bool isZero(double d)
|
||||
{
|
||||
uchar *ch = (uchar *)&d;
|
||||
|
Loading…
x
Reference in New Issue
Block a user