2 * Copyright (C) 2015, International Business Machines
3 * Corporation and others. All Rights Reserved.
5 * file name: digitformatter.cpp
8 #include "unicode/utypes.h"
10 #if !UCONFIG_NO_FORMATTING
12 #include "unicode/dcfmtsym.h"
13 #include "unicode/unum.h"
15 #include "digitformatter.h"
16 #include "digitgrouping.h"
17 #include "digitinterval.h"
20 #include "smallintformatter.h"
21 #include "unistrappender.h"
22 #include "visibledigits.h"
26 DigitFormatter::DigitFormatter()
27 : fGroupingSeparator(",", -1, US_INV
), fDecimal(".", -1, US_INV
),
28 fNegativeSign("-", -1, US_INV
), fPositiveSign("+", -1, US_INV
),
29 fIsStandardDigits(TRUE
), fExponent("E", -1, US_INV
) {
30 for (int32_t i
= 0; i
< 10; ++i
) {
31 fLocalizedDigits
[i
] = (UChar32
) (0x30 + i
);
33 fInfinity
.setTo(UnicodeString("Inf", -1, US_INV
), UNUM_INTEGER_FIELD
);
34 fNan
.setTo(UnicodeString("Nan", -1, US_INV
), UNUM_INTEGER_FIELD
);
37 DigitFormatter::DigitFormatter(const DecimalFormatSymbols
&symbols
) {
38 setDecimalFormatSymbols(symbols
);
42 DigitFormatter::setOtherDecimalFormatSymbols(
43 const DecimalFormatSymbols
&symbols
) {
44 fLocalizedDigits
[0] = symbols
.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol
).char32At(0);
45 fLocalizedDigits
[1] = symbols
.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol
).char32At(0);
46 fLocalizedDigits
[2] = symbols
.getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol
).char32At(0);
47 fLocalizedDigits
[3] = symbols
.getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol
).char32At(0);
48 fLocalizedDigits
[4] = symbols
.getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol
).char32At(0);
49 fLocalizedDigits
[5] = symbols
.getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol
).char32At(0);
50 fLocalizedDigits
[6] = symbols
.getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol
).char32At(0);
51 fLocalizedDigits
[7] = symbols
.getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol
).char32At(0);
52 fLocalizedDigits
[8] = symbols
.getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol
).char32At(0);
53 fLocalizedDigits
[9] = symbols
.getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol
).char32At(0);
54 fIsStandardDigits
= isStandardDigits();
55 fNegativeSign
= symbols
.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol
);
56 fPositiveSign
= symbols
.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol
);
57 fInfinity
.setTo(symbols
.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol
), UNUM_INTEGER_FIELD
);
58 fNan
.setTo(symbols
.getConstSymbol(DecimalFormatSymbols::kNaNSymbol
), UNUM_INTEGER_FIELD
);
59 fExponent
= symbols
.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol
);
63 DigitFormatter::setDecimalFormatSymbolsForMonetary(
64 const DecimalFormatSymbols
&symbols
) {
65 setOtherDecimalFormatSymbols(symbols
);
66 fGroupingSeparator
= symbols
.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol
);
67 fDecimal
= symbols
.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol
);
71 DigitFormatter::setDecimalFormatSymbols(
72 const DecimalFormatSymbols
&symbols
) {
73 setOtherDecimalFormatSymbols(symbols
);
74 fGroupingSeparator
= symbols
.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
);
75 fDecimal
= symbols
.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
);
78 static void appendField(
80 const UnicodeString
&value
,
81 FieldPositionHandler
&handler
,
82 UnicodeString
&appendTo
) {
83 int32_t currentLength
= appendTo
.length();
84 appendTo
.append(value
);
91 int32_t DigitFormatter::countChar32(
92 const DigitGrouping
&grouping
,
93 const DigitInterval
&interval
,
94 const DigitFormatterOptions
&options
) const {
95 int32_t result
= interval
.length();
97 // We always emit '0' in lieu of no digits.
101 if (options
.fAlwaysShowDecimal
|| interval
.getLeastSignificantInclusive() < 0) {
102 result
+= fDecimal
.countChar32();
104 result
+= grouping
.getSeparatorCount(interval
.getIntDigitCount()) * fGroupingSeparator
.countChar32();
109 DigitFormatter::countChar32(
110 const VisibleDigits
&digits
,
111 const DigitGrouping
&grouping
,
112 const DigitFormatterOptions
&options
) const {
113 if (digits
.isNaN()) {
114 return countChar32ForNaN();
116 if (digits
.isInfinite()) {
117 return countChar32ForInfinity();
121 digits
.getInterval(),
126 DigitFormatter::countChar32(
127 const VisibleDigitsWithExponent
&digits
,
128 const SciFormatterOptions
&options
) const {
129 if (digits
.isNaN()) {
130 return countChar32ForNaN();
132 if (digits
.isInfinite()) {
133 return countChar32ForInfinity();
135 const VisibleDigits
*exponent
= digits
.getExponent();
136 if (exponent
== NULL
) {
137 DigitGrouping grouping
;
140 digits
.getMantissa().getInterval(),
144 *exponent
, digits
.getMantissa().getInterval(), options
);
148 DigitFormatter::countChar32(
149 const VisibleDigits
&exponent
,
150 const DigitInterval
&mantissaInterval
,
151 const SciFormatterOptions
&options
) const {
152 DigitGrouping grouping
;
153 int32_t count
= countChar32(
154 grouping
, mantissaInterval
, options
.fMantissa
);
155 count
+= fExponent
.countChar32();
156 count
+= countChar32ForExponent(
157 exponent
, options
.fExponent
);
161 UnicodeString
&DigitFormatter::format(
162 const VisibleDigits
&digits
,
163 const DigitGrouping
&grouping
,
164 const DigitFormatterOptions
&options
,
165 FieldPositionHandler
&handler
,
166 UnicodeString
&appendTo
) const {
167 if (digits
.isNaN()) {
168 return formatNaN(handler
, appendTo
);
170 if (digits
.isInfinite()) {
171 return formatInfinity(handler
, appendTo
);
174 const DigitInterval
&interval
= digits
.getInterval();
175 int32_t digitsLeftOfDecimal
= interval
.getMostSignificantExclusive();
176 int32_t lastDigitPos
= interval
.getLeastSignificantInclusive();
177 int32_t intBegin
= appendTo
.length();
180 // Emit "0" instead of empty string.
181 if (digitsLeftOfDecimal
== 0 && lastDigitPos
== 0) {
182 appendTo
.append(fLocalizedDigits
[0]);
183 handler
.addAttribute(UNUM_INTEGER_FIELD
, intBegin
, appendTo
.length());
184 if (options
.fAlwaysShowDecimal
) {
186 UNUM_DECIMAL_SEPARATOR_FIELD
,
194 UnicodeStringAppender
appender(appendTo
);
195 for (int32_t i
= interval
.getMostSignificantExclusive() - 1;
196 i
>= interval
.getLeastSignificantInclusive(); --i
) {
200 UNUM_DECIMAL_SEPARATOR_FIELD
,
204 fracBegin
= appendTo
.length();
206 appender
.append(fLocalizedDigits
[digits
.getDigitByExponent(i
)]);
207 if (grouping
.isSeparatorAt(digitsLeftOfDecimal
, i
)) {
210 UNUM_GROUPING_SEPARATOR_FIELD
,
217 if (digitsLeftOfDecimal
> 0) {
218 handler
.addAttribute(UNUM_INTEGER_FIELD
, intBegin
, appendTo
.length());
222 if (options
.fAlwaysShowDecimal
&& lastDigitPos
== 0) {
225 UNUM_DECIMAL_SEPARATOR_FIELD
,
231 // lastDigitPos is never > 0 so we are guaranteed that kIntegerField
233 if (lastDigitPos
< 0) {
234 handler
.addAttribute(UNUM_FRACTION_FIELD
, fracBegin
, appendTo
.length());
240 DigitFormatter::format(
241 const VisibleDigitsWithExponent
&digits
,
242 const SciFormatterOptions
&options
,
243 FieldPositionHandler
&handler
,
244 UnicodeString
&appendTo
) const {
245 DigitGrouping grouping
;
247 digits
.getMantissa(),
252 const VisibleDigits
*exponent
= digits
.getExponent();
253 if (exponent
== NULL
) {
256 int32_t expBegin
= appendTo
.length();
257 appendTo
.append(fExponent
);
258 handler
.addAttribute(
259 UNUM_EXPONENT_SYMBOL_FIELD
, expBegin
, appendTo
.length());
260 return formatExponent(
263 UNUM_EXPONENT_SIGN_FIELD
,
269 static int32_t formatInt(
270 int32_t value
, uint8_t *digits
) {
273 digits
[idx
++] = (uint8_t) (value
% 10);
280 DigitFormatter::formatDigits(
281 const uint8_t *digits
,
283 const IntDigitCountRange
&range
,
285 FieldPositionHandler
&handler
,
286 UnicodeString
&appendTo
) const {
287 int32_t i
= range
.pin(count
) - 1;
288 int32_t begin
= appendTo
.length();
290 // Always emit '0' as placeholder for empty string.
292 appendTo
.append(fLocalizedDigits
[0]);
293 handler
.addAttribute(intField
, begin
, appendTo
.length());
297 UnicodeStringAppender
appender(appendTo
);
298 for (; i
>= count
; --i
) {
299 appender
.append(fLocalizedDigits
[0]);
301 for (; i
>= 0; --i
) {
302 appender
.append(fLocalizedDigits
[digits
[i
]]);
305 handler
.addAttribute(intField
, begin
, appendTo
.length());
310 DigitFormatter::formatExponent(
311 const VisibleDigits
&digits
,
312 const DigitFormatterIntOptions
&options
,
315 FieldPositionHandler
&handler
,
316 UnicodeString
&appendTo
) const {
317 UBool neg
= digits
.isNegative();
318 if (neg
|| options
.fAlwaysShowSign
) {
321 neg
? fNegativeSign
: fPositiveSign
,
325 int32_t begin
= appendTo
.length();
326 DigitGrouping grouping
;
327 DigitFormatterOptions expOptions
;
328 FieldPosition
fpos(FieldPosition::DONT_CARE
);
329 FieldPositionOnlyHandler
noHandler(fpos
);
336 handler
.addAttribute(intField
, begin
, appendTo
.length());
341 DigitFormatter::countChar32ForExponent(
342 const VisibleDigits
&exponent
,
343 const DigitFormatterIntOptions
&options
) const {
345 UBool neg
= exponent
.isNegative();
346 if (neg
|| options
.fAlwaysShowSign
) {
347 result
+= neg
? fNegativeSign
.countChar32() : fPositiveSign
.countChar32();
349 DigitGrouping grouping
;
350 DigitFormatterOptions expOptions
;
351 result
+= countChar32(grouping
, exponent
.getInterval(), expOptions
);
356 DigitFormatter::formatPositiveInt32(
357 int32_t positiveValue
,
358 const IntDigitCountRange
&range
,
359 FieldPositionHandler
&handler
,
360 UnicodeString
&appendTo
) const {
362 if (fIsStandardDigits
&& SmallIntFormatter::canFormat(positiveValue
, range
)) {
363 int32_t begin
= appendTo
.length();
364 SmallIntFormatter::format(positiveValue
, range
, appendTo
);
365 handler
.addAttribute(UNUM_INTEGER_FIELD
, begin
, appendTo
.length());
369 int32_t count
= formatInt(positiveValue
, digits
);
379 UBool
DigitFormatter::isStandardDigits() const {
380 UChar32 cdigit
= 0x30;
381 for (int32_t i
= 0; i
< UPRV_LENGTHOF(fLocalizedDigits
); ++i
) {
382 if (fLocalizedDigits
[i
] != cdigit
) {
391 DigitFormatter::equals(const DigitFormatter
&rhs
) const {
392 UBool result
= (fGroupingSeparator
== rhs
.fGroupingSeparator
) &&
393 (fDecimal
== rhs
.fDecimal
) &&
394 (fNegativeSign
== rhs
.fNegativeSign
) &&
395 (fPositiveSign
== rhs
.fPositiveSign
) &&
396 (fInfinity
.equals(rhs
.fInfinity
)) &&
397 (fNan
.equals(rhs
.fNan
)) &&
398 (fIsStandardDigits
== rhs
.fIsStandardDigits
) &&
399 (fExponent
== rhs
.fExponent
);
404 for (int32_t i
= 0; i
< UPRV_LENGTHOF(fLocalizedDigits
); ++i
) {
405 if (fLocalizedDigits
[i
] != rhs
.fLocalizedDigits
[i
]) {
415 #endif /* #if !UCONFIG_NO_FORMATTING */