• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015, International Business Machines
3  * Corporation and others.  All Rights Reserved.
4  *
5  * file name: digitformatter.cpp
6  */
7 
8 #include "unicode/utypes.h"
9 
10 #if !UCONFIG_NO_FORMATTING
11 
12 #include "unicode/dcfmtsym.h"
13 #include "unicode/unum.h"
14 
15 #include "digitformatter.h"
16 #include "digitgrouping.h"
17 #include "digitinterval.h"
18 #include "digitlst.h"
19 #include "fphdlimp.h"
20 #include "smallintformatter.h"
21 #include "unistrappender.h"
22 #include "visibledigits.h"
23 
24 U_NAMESPACE_BEGIN
25 
DigitFormatter()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);
32     }
33     fInfinity.setTo(UnicodeString("Inf", -1, US_INV), UNUM_INTEGER_FIELD);
34     fNan.setTo(UnicodeString("Nan", -1, US_INV), UNUM_INTEGER_FIELD);
35 }
36 
DigitFormatter(const DecimalFormatSymbols & symbols)37 DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) {
38     setDecimalFormatSymbols(symbols);
39 }
40 
41 void
setOtherDecimalFormatSymbols(const DecimalFormatSymbols & 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);
60 }
61 
62 void
setDecimalFormatSymbolsForMonetary(const DecimalFormatSymbols & symbols)63 DigitFormatter::setDecimalFormatSymbolsForMonetary(
64         const DecimalFormatSymbols &symbols) {
65     setOtherDecimalFormatSymbols(symbols);
66     fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
67     fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
68 }
69 
70 void
setDecimalFormatSymbols(const DecimalFormatSymbols & symbols)71 DigitFormatter::setDecimalFormatSymbols(
72         const DecimalFormatSymbols &symbols) {
73     setOtherDecimalFormatSymbols(symbols);
74     fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
75     fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
76 }
77 
appendField(int32_t fieldId,const UnicodeString & value,FieldPositionHandler & handler,UnicodeString & appendTo)78 static void appendField(
79         int32_t fieldId,
80         const UnicodeString &value,
81         FieldPositionHandler &handler,
82         UnicodeString &appendTo) {
83     int32_t currentLength = appendTo.length();
84     appendTo.append(value);
85     handler.addAttribute(
86             fieldId,
87             currentLength,
88             appendTo.length());
89 }
90 
countChar32(const DigitGrouping & grouping,const DigitInterval & interval,const DigitFormatterOptions & options) const91 int32_t DigitFormatter::countChar32(
92         const DigitGrouping &grouping,
93         const DigitInterval &interval,
94         const DigitFormatterOptions &options) const {
95     int32_t result = interval.length();
96 
97     // We always emit '0' in lieu of no digits.
98     if (result == 0) {
99         result = 1;
100     }
101     if (options.fAlwaysShowDecimal || interval.getLeastSignificantInclusive() < 0) {
102         result += fDecimal.countChar32();
103     }
104     result += grouping.getSeparatorCount(interval.getIntDigitCount()) * fGroupingSeparator.countChar32();
105     return result;
106 }
107 
108 int32_t
countChar32(const VisibleDigits & digits,const DigitGrouping & grouping,const DigitFormatterOptions & options) const109 DigitFormatter::countChar32(
110         const VisibleDigits &digits,
111         const DigitGrouping &grouping,
112         const DigitFormatterOptions &options) const {
113     if (digits.isNaN()) {
114         return countChar32ForNaN();
115     }
116     if (digits.isInfinite()) {
117         return countChar32ForInfinity();
118     }
119     return countChar32(
120             grouping,
121             digits.getInterval(),
122             options);
123 }
124 
125 int32_t
countChar32(const VisibleDigitsWithExponent & digits,const SciFormatterOptions & options) const126 DigitFormatter::countChar32(
127         const VisibleDigitsWithExponent &digits,
128         const SciFormatterOptions &options) const {
129     if (digits.isNaN()) {
130         return countChar32ForNaN();
131     }
132     if (digits.isInfinite()) {
133         return countChar32ForInfinity();
134     }
135     const VisibleDigits *exponent = digits.getExponent();
136     if (exponent == NULL) {
137         DigitGrouping grouping;
138         return countChar32(
139                 grouping,
140                 digits.getMantissa().getInterval(),
141                 options.fMantissa);
142     }
143     return countChar32(
144             *exponent, digits.getMantissa().getInterval(), options);
145 }
146 
147 int32_t
countChar32(const VisibleDigits & exponent,const DigitInterval & mantissaInterval,const SciFormatterOptions & options) const148 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);
158     return count;
159 }
160 
format(const VisibleDigits & digits,const DigitGrouping & grouping,const DigitFormatterOptions & options,FieldPositionHandler & handler,UnicodeString & appendTo) const161 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);
169     }
170     if (digits.isInfinite()) {
171         return formatInfinity(handler, appendTo);
172     }
173 
174     const DigitInterval &interval = digits.getInterval();
175     int32_t digitsLeftOfDecimal = interval.getMostSignificantExclusive();
176     int32_t lastDigitPos = interval.getLeastSignificantInclusive();
177     int32_t intBegin = appendTo.length();
178     int32_t fracBegin;
179 
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) {
185             appendField(
186                     UNUM_DECIMAL_SEPARATOR_FIELD,
187                     fDecimal,
188                     handler,
189                     appendTo);
190         }
191         return appendTo;
192     }
193     {
194         UnicodeStringAppender appender(appendTo);
195         for (int32_t i = interval.getMostSignificantExclusive() - 1;
196                 i >= interval.getLeastSignificantInclusive(); --i) {
197             if (i == -1) {
198                 appender.flush();
199                 appendField(
200                         UNUM_DECIMAL_SEPARATOR_FIELD,
201                         fDecimal,
202                         handler,
203                         appendTo);
204                 fracBegin = appendTo.length();
205             }
206             appender.append(fLocalizedDigits[digits.getDigitByExponent(i)]);
207             if (grouping.isSeparatorAt(digitsLeftOfDecimal, i)) {
208                 appender.flush();
209                 appendField(
210                         UNUM_GROUPING_SEPARATOR_FIELD,
211                         fGroupingSeparator,
212                         handler,
213                         appendTo);
214             }
215             if (i == 0) {
216                 appender.flush();
217                 if (digitsLeftOfDecimal > 0) {
218                     handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
219                 }
220             }
221         }
222         if (options.fAlwaysShowDecimal && lastDigitPos == 0) {
223             appender.flush();
224             appendField(
225                     UNUM_DECIMAL_SEPARATOR_FIELD,
226                     fDecimal,
227                     handler,
228                     appendTo);
229         }
230     }
231     // lastDigitPos is never > 0 so we are guaranteed that kIntegerField
232     // is already added.
233     if (lastDigitPos < 0) {
234         handler.addAttribute(UNUM_FRACTION_FIELD, fracBegin, appendTo.length());
235     }
236     return appendTo;
237 }
238 
239 UnicodeString &
format(const VisibleDigitsWithExponent & digits,const SciFormatterOptions & options,FieldPositionHandler & handler,UnicodeString & appendTo) const240 DigitFormatter::format(
241         const VisibleDigitsWithExponent &digits,
242         const SciFormatterOptions &options,
243         FieldPositionHandler &handler,
244         UnicodeString &appendTo) const {
245     DigitGrouping grouping;
246     format(
247             digits.getMantissa(),
248             grouping,
249             options.fMantissa,
250             handler,
251             appendTo);
252     const VisibleDigits *exponent = digits.getExponent();
253     if (exponent == NULL) {
254         return appendTo;
255     }
256     int32_t expBegin = appendTo.length();
257     appendTo.append(fExponent);
258     handler.addAttribute(
259             UNUM_EXPONENT_SYMBOL_FIELD, expBegin, appendTo.length());
260     return formatExponent(
261             *exponent,
262             options.fExponent,
263             UNUM_EXPONENT_SIGN_FIELD,
264             UNUM_EXPONENT_FIELD,
265             handler,
266             appendTo);
267 }
268 
formatInt(int32_t value,uint8_t * digits)269 static int32_t formatInt(
270         int32_t value, uint8_t *digits) {
271     int32_t idx = 0;
272     while (value > 0) {
273         digits[idx++] = (uint8_t) (value % 10);
274         value /= 10;
275     }
276     return idx;
277 }
278 
279 UnicodeString &
formatDigits(const uint8_t * digits,int32_t count,const IntDigitCountRange & range,int32_t intField,FieldPositionHandler & handler,UnicodeString & appendTo) const280 DigitFormatter::formatDigits(
281         const uint8_t *digits,
282         int32_t count,
283         const IntDigitCountRange &range,
284         int32_t intField,
285         FieldPositionHandler &handler,
286         UnicodeString &appendTo) const {
287     int32_t i = range.pin(count) - 1;
288     int32_t begin = appendTo.length();
289 
290     // Always emit '0' as placeholder for empty string.
291     if (i == -1) {
292         appendTo.append(fLocalizedDigits[0]);
293         handler.addAttribute(intField, begin, appendTo.length());
294         return appendTo;
295     }
296     {
297         UnicodeStringAppender appender(appendTo);
298         for (; i >= count; --i) {
299             appender.append(fLocalizedDigits[0]);
300         }
301         for (; i >= 0; --i) {
302             appender.append(fLocalizedDigits[digits[i]]);
303         }
304     }
305     handler.addAttribute(intField, begin, appendTo.length());
306     return appendTo;
307 }
308 
309 UnicodeString &
formatExponent(const VisibleDigits & digits,const DigitFormatterIntOptions & options,int32_t signField,int32_t intField,FieldPositionHandler & handler,UnicodeString & appendTo) const310 DigitFormatter::formatExponent(
311         const VisibleDigits &digits,
312         const DigitFormatterIntOptions &options,
313         int32_t signField,
314         int32_t intField,
315         FieldPositionHandler &handler,
316         UnicodeString &appendTo) const {
317     UBool neg = digits.isNegative();
318     if (neg || options.fAlwaysShowSign) {
319         appendField(
320                 signField,
321                 neg ? fNegativeSign : fPositiveSign,
322                 handler,
323                 appendTo);
324     }
325     int32_t begin = appendTo.length();
326     DigitGrouping grouping;
327     DigitFormatterOptions expOptions;
328     FieldPosition fpos(FieldPosition::DONT_CARE);
329     FieldPositionOnlyHandler noHandler(fpos);
330     format(
331             digits,
332             grouping,
333             expOptions,
334             noHandler,
335             appendTo);
336     handler.addAttribute(intField, begin, appendTo.length());
337     return appendTo;
338 }
339 
340 int32_t
countChar32ForExponent(const VisibleDigits & exponent,const DigitFormatterIntOptions & options) const341 DigitFormatter::countChar32ForExponent(
342         const VisibleDigits &exponent,
343         const DigitFormatterIntOptions &options) const {
344     int32_t result = 0;
345     UBool neg = exponent.isNegative();
346     if (neg || options.fAlwaysShowSign) {
347         result += neg ? fNegativeSign.countChar32() : fPositiveSign.countChar32();
348     }
349     DigitGrouping grouping;
350     DigitFormatterOptions expOptions;
351     result += countChar32(grouping, exponent.getInterval(), expOptions);
352     return result;
353 }
354 
355 UnicodeString &
formatPositiveInt32(int32_t positiveValue,const IntDigitCountRange & range,FieldPositionHandler & handler,UnicodeString & appendTo) const356 DigitFormatter::formatPositiveInt32(
357         int32_t positiveValue,
358         const IntDigitCountRange &range,
359         FieldPositionHandler &handler,
360         UnicodeString &appendTo) const {
361     // super fast path
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());
366         return appendTo;
367     }
368     uint8_t digits[10];
369     int32_t count = formatInt(positiveValue, digits);
370     return formatDigits(
371             digits,
372             count,
373             range,
374             UNUM_INTEGER_FIELD,
375             handler,
376             appendTo);
377 }
378 
isStandardDigits() const379 UBool DigitFormatter::isStandardDigits() const {
380     UChar32 cdigit = 0x30;
381     for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
382         if (fLocalizedDigits[i] != cdigit) {
383             return FALSE;
384         }
385         ++cdigit;
386     }
387     return TRUE;
388 }
389 
390 UBool
equals(const DigitFormatter & rhs) const391 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);
400 
401     if (!result) {
402         return FALSE;
403     }
404     for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
405         if (fLocalizedDigits[i] != rhs.fLocalizedDigits[i]) {
406             return FALSE;
407         }
408     }
409     return TRUE;
410 }
411 
412 
413 U_NAMESPACE_END
414 
415 #endif /* #if !UCONFIG_NO_FORMATTING */
416