1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 * Copyright (C) 2015, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 * file name: digitformatter.cpp
10 #include "unicode/utypes.h"
12 #if !UCONFIG_NO_FORMATTING
14 #include "unicode/dcfmtsym.h"
15 #include "unicode/unum.h"
17 #include "digitformatter.h"
18 #include "digitgrouping.h"
19 #include "digitinterval.h"
22 #include "smallintformatter.h"
23 #include "unistrappender.h"
24 #include "visibledigits.h"
28 DigitFormatter::DigitFormatter()
29 : fGroupingSeparator(",", -1, US_INV
), fDecimal(".", -1, US_INV
),
30 fNegativeSign("-", -1, US_INV
), fPositiveSign("+", -1, US_INV
),
31 fIsStandardDigits(TRUE
), fExponent("E", -1, US_INV
) {
32 for (int32_t i
= 0; i
< 10; ++i
) {
33 fLocalizedDigits
[i
] = (UChar32
) (0x30 + i
);
35 fInfinity
.setTo(UnicodeString("Inf", -1, US_INV
), UNUM_INTEGER_FIELD
);
36 fNan
.setTo(UnicodeString("Nan", -1, US_INV
), UNUM_INTEGER_FIELD
);
39 DigitFormatter::DigitFormatter(const DecimalFormatSymbols
&symbols
) {
40 setDecimalFormatSymbols(symbols
);
44 DigitFormatter::setOtherDecimalFormatSymbols(
45 const DecimalFormatSymbols
&symbols
) {
46 fLocalizedDigits
[0] = symbols
.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol
).char32At(0);
47 fLocalizedDigits
[1] = symbols
.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol
).char32At(0);
48 fLocalizedDigits
[2] = symbols
.getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol
).char32At(0);
49 fLocalizedDigits
[3] = symbols
.getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol
).char32At(0);
50 fLocalizedDigits
[4] = symbols
.getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol
).char32At(0);
51 fLocalizedDigits
[5] = symbols
.getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol
).char32At(0);
52 fLocalizedDigits
[6] = symbols
.getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol
).char32At(0);
53 fLocalizedDigits
[7] = symbols
.getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol
).char32At(0);
54 fLocalizedDigits
[8] = symbols
.getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol
).char32At(0);
55 fLocalizedDigits
[9] = symbols
.getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol
).char32At(0);
56 fIsStandardDigits
= isStandardDigits();
57 fNegativeSign
= symbols
.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol
);
58 fPositiveSign
= symbols
.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol
);
59 fInfinity
.setTo(symbols
.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol
), UNUM_INTEGER_FIELD
);
60 fNan
.setTo(symbols
.getConstSymbol(DecimalFormatSymbols::kNaNSymbol
), UNUM_INTEGER_FIELD
);
61 fExponent
= symbols
.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol
);
65 DigitFormatter::setDecimalFormatSymbolsForMonetary(
66 const DecimalFormatSymbols
&symbols
) {
67 setOtherDecimalFormatSymbols(symbols
);
68 fGroupingSeparator
= symbols
.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol
);
69 fDecimal
= symbols
.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol
);
73 DigitFormatter::setDecimalFormatSymbols(
74 const DecimalFormatSymbols
&symbols
) {
75 setOtherDecimalFormatSymbols(symbols
);
76 fGroupingSeparator
= symbols
.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
);
77 fDecimal
= symbols
.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
);
80 static void appendField(
82 const UnicodeString
&value
,
83 FieldPositionHandler
&handler
,
84 UnicodeString
&appendTo
) {
85 int32_t currentLength
= appendTo
.length();
86 appendTo
.append(value
);
93 int32_t DigitFormatter::countChar32(
94 const DigitGrouping
&grouping
,
95 const DigitInterval
&interval
,
96 const DigitFormatterOptions
&options
) const {
97 int32_t result
= interval
.length();
99 // We always emit '0' in lieu of no digits.
103 if (options
.fAlwaysShowDecimal
|| interval
.getLeastSignificantInclusive() < 0) {
104 result
+= fDecimal
.countChar32();
106 result
+= grouping
.getSeparatorCount(interval
.getIntDigitCount()) * fGroupingSeparator
.countChar32();
111 DigitFormatter::countChar32(
112 const VisibleDigits
&digits
,
113 const DigitGrouping
&grouping
,
114 const DigitFormatterOptions
&options
) const {
115 if (digits
.isNaN()) {
116 return countChar32ForNaN();
118 if (digits
.isInfinite()) {
119 return countChar32ForInfinity();
123 digits
.getInterval(),
128 DigitFormatter::countChar32(
129 const VisibleDigitsWithExponent
&digits
,
130 const SciFormatterOptions
&options
) const {
131 if (digits
.isNaN()) {
132 return countChar32ForNaN();
134 if (digits
.isInfinite()) {
135 return countChar32ForInfinity();
137 const VisibleDigits
*exponent
= digits
.getExponent();
138 if (exponent
== NULL
) {
139 DigitGrouping grouping
;
142 digits
.getMantissa().getInterval(),
146 *exponent
, digits
.getMantissa().getInterval(), options
);
150 DigitFormatter::countChar32(
151 const VisibleDigits
&exponent
,
152 const DigitInterval
&mantissaInterval
,
153 const SciFormatterOptions
&options
) const {
154 DigitGrouping grouping
;
155 int32_t count
= countChar32(
156 grouping
, mantissaInterval
, options
.fMantissa
);
157 count
+= fExponent
.countChar32();
158 count
+= countChar32ForExponent(
159 exponent
, options
.fExponent
);
163 UnicodeString
&DigitFormatter::format(
164 const VisibleDigits
&digits
,
165 const DigitGrouping
&grouping
,
166 const DigitFormatterOptions
&options
,
167 FieldPositionHandler
&handler
,
168 UnicodeString
&appendTo
) const {
169 if (digits
.isNaN()) {
170 return formatNaN(handler
, appendTo
);
172 if (digits
.isInfinite()) {
173 return formatInfinity(handler
, appendTo
);
176 const DigitInterval
&interval
= digits
.getInterval();
177 int32_t digitsLeftOfDecimal
= interval
.getMostSignificantExclusive();
178 int32_t lastDigitPos
= interval
.getLeastSignificantInclusive();
179 int32_t intBegin
= appendTo
.length();
180 int32_t fracBegin
= 0; /* initialize to avoid compiler warning */
182 // Emit "0" instead of empty string.
183 if (digitsLeftOfDecimal
== 0 && lastDigitPos
== 0) {
184 appendTo
.append(fLocalizedDigits
[0]);
185 handler
.addAttribute(UNUM_INTEGER_FIELD
, intBegin
, appendTo
.length());
186 if (options
.fAlwaysShowDecimal
) {
188 UNUM_DECIMAL_SEPARATOR_FIELD
,
196 UnicodeStringAppender
appender(appendTo
);
197 for (int32_t i
= interval
.getMostSignificantExclusive() - 1;
198 i
>= interval
.getLeastSignificantInclusive(); --i
) {
202 UNUM_DECIMAL_SEPARATOR_FIELD
,
206 fracBegin
= appendTo
.length();
208 appender
.append(fLocalizedDigits
[digits
.getDigitByExponent(i
)]);
209 if (grouping
.isSeparatorAt(digitsLeftOfDecimal
, i
)) {
212 UNUM_GROUPING_SEPARATOR_FIELD
,
219 if (digitsLeftOfDecimal
> 0) {
220 handler
.addAttribute(UNUM_INTEGER_FIELD
, intBegin
, appendTo
.length());
224 if (options
.fAlwaysShowDecimal
&& lastDigitPos
== 0) {
227 UNUM_DECIMAL_SEPARATOR_FIELD
,
233 // lastDigitPos is never > 0 so we are guaranteed that kIntegerField
235 if (lastDigitPos
< 0) {
236 handler
.addAttribute(UNUM_FRACTION_FIELD
, fracBegin
, appendTo
.length());
242 DigitFormatter::format(
243 const VisibleDigitsWithExponent
&digits
,
244 const SciFormatterOptions
&options
,
245 FieldPositionHandler
&handler
,
246 UnicodeString
&appendTo
) const {
247 DigitGrouping grouping
;
249 digits
.getMantissa(),
254 const VisibleDigits
*exponent
= digits
.getExponent();
255 if (exponent
== NULL
) {
258 int32_t expBegin
= appendTo
.length();
259 appendTo
.append(fExponent
);
260 handler
.addAttribute(
261 UNUM_EXPONENT_SYMBOL_FIELD
, expBegin
, appendTo
.length());
262 return formatExponent(
265 UNUM_EXPONENT_SIGN_FIELD
,
271 static int32_t formatInt(
272 int32_t value
, uint8_t *digits
) {
275 digits
[idx
++] = (uint8_t) (value
% 10);
282 DigitFormatter::formatDigits(
283 const uint8_t *digits
,
285 const IntDigitCountRange
&range
,
287 FieldPositionHandler
&handler
,
288 UnicodeString
&appendTo
) const {
289 int32_t i
= range
.pin(count
) - 1;
290 int32_t begin
= appendTo
.length();
292 // Always emit '0' as placeholder for empty string.
294 appendTo
.append(fLocalizedDigits
[0]);
295 handler
.addAttribute(intField
, begin
, appendTo
.length());
299 UnicodeStringAppender
appender(appendTo
);
300 for (; i
>= count
; --i
) {
301 appender
.append(fLocalizedDigits
[0]);
303 for (; i
>= 0; --i
) {
304 appender
.append(fLocalizedDigits
[digits
[i
]]);
307 handler
.addAttribute(intField
, begin
, appendTo
.length());
312 DigitFormatter::formatExponent(
313 const VisibleDigits
&digits
,
314 const DigitFormatterIntOptions
&options
,
317 FieldPositionHandler
&handler
,
318 UnicodeString
&appendTo
) const {
319 UBool neg
= digits
.isNegative();
320 if (neg
|| options
.fAlwaysShowSign
) {
323 neg
? fNegativeSign
: fPositiveSign
,
327 int32_t begin
= appendTo
.length();
328 DigitGrouping grouping
;
329 DigitFormatterOptions expOptions
;
330 FieldPosition
fpos(FieldPosition::DONT_CARE
);
331 FieldPositionOnlyHandler
noHandler(fpos
);
338 handler
.addAttribute(intField
, begin
, appendTo
.length());
343 DigitFormatter::countChar32ForExponent(
344 const VisibleDigits
&exponent
,
345 const DigitFormatterIntOptions
&options
) const {
347 UBool neg
= exponent
.isNegative();
348 if (neg
|| options
.fAlwaysShowSign
) {
349 result
+= neg
? fNegativeSign
.countChar32() : fPositiveSign
.countChar32();
351 DigitGrouping grouping
;
352 DigitFormatterOptions expOptions
;
353 result
+= countChar32(grouping
, exponent
.getInterval(), expOptions
);
358 DigitFormatter::formatPositiveInt32(
359 int32_t positiveValue
,
360 const IntDigitCountRange
&range
,
361 FieldPositionHandler
&handler
,
362 UnicodeString
&appendTo
) const {
364 if (fIsStandardDigits
&& SmallIntFormatter::canFormat(positiveValue
, range
)) {
365 int32_t begin
= appendTo
.length();
366 SmallIntFormatter::format(positiveValue
, range
, appendTo
);
367 handler
.addAttribute(UNUM_INTEGER_FIELD
, begin
, appendTo
.length());
371 int32_t count
= formatInt(positiveValue
, digits
);
381 UBool
DigitFormatter::isStandardDigits() const {
382 UChar32 cdigit
= 0x30;
383 for (int32_t i
= 0; i
< UPRV_LENGTHOF(fLocalizedDigits
); ++i
) {
384 if (fLocalizedDigits
[i
] != cdigit
) {
393 DigitFormatter::equals(const DigitFormatter
&rhs
) const {
394 UBool result
= (fGroupingSeparator
== rhs
.fGroupingSeparator
) &&
395 (fDecimal
== rhs
.fDecimal
) &&
396 (fNegativeSign
== rhs
.fNegativeSign
) &&
397 (fPositiveSign
== rhs
.fPositiveSign
) &&
398 (fInfinity
.equals(rhs
.fInfinity
)) &&
399 (fNan
.equals(rhs
.fNan
)) &&
400 (fIsStandardDigits
== rhs
.fIsStandardDigits
) &&
401 (fExponent
== rhs
.fExponent
);
406 for (int32_t i
= 0; i
< UPRV_LENGTHOF(fLocalizedDigits
); ++i
) {
407 if (fLocalizedDigits
[i
] != rhs
.fLocalizedDigits
[i
]) {
417 #endif /* #if !UCONFIG_NO_FORMATTING */