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