]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/digitformatter.cpp
ICU-59180.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / digitformatter.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
2ca993e8
A
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
26U_NAMESPACE_BEGIN
27
28DigitFormatter::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);
34 }
35 fInfinity.setTo(UnicodeString("Inf", -1, US_INV), UNUM_INTEGER_FIELD);
36 fNan.setTo(UnicodeString("Nan", -1, US_INV), UNUM_INTEGER_FIELD);
37}
38
39DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) {
40 setDecimalFormatSymbols(symbols);
41}
42
43void
44DigitFormatter::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);
62}
63
64void
65DigitFormatter::setDecimalFormatSymbolsForMonetary(
66 const DecimalFormatSymbols &symbols) {
67 setOtherDecimalFormatSymbols(symbols);
68 fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
69 fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
70}
71
72void
73DigitFormatter::setDecimalFormatSymbols(
74 const DecimalFormatSymbols &symbols) {
75 setOtherDecimalFormatSymbols(symbols);
76 fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
77 fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
78}
79
80static void appendField(
81 int32_t fieldId,
82 const UnicodeString &value,
83 FieldPositionHandler &handler,
84 UnicodeString &appendTo) {
85 int32_t currentLength = appendTo.length();
86 appendTo.append(value);
87 handler.addAttribute(
88 fieldId,
89 currentLength,
90 appendTo.length());
91}
92
93int32_t DigitFormatter::countChar32(
94 const DigitGrouping &grouping,
95 const DigitInterval &interval,
96 const DigitFormatterOptions &options) const {
97 int32_t result = interval.length();
98
99 // We always emit '0' in lieu of no digits.
100 if (result == 0) {
101 result = 1;
102 }
103 if (options.fAlwaysShowDecimal || interval.getLeastSignificantInclusive() < 0) {
104 result += fDecimal.countChar32();
105 }
106 result += grouping.getSeparatorCount(interval.getIntDigitCount()) * fGroupingSeparator.countChar32();
107 return result;
108}
109
110int32_t
111DigitFormatter::countChar32(
112 const VisibleDigits &digits,
113 const DigitGrouping &grouping,
114 const DigitFormatterOptions &options) const {
115 if (digits.isNaN()) {
116 return countChar32ForNaN();
117 }
118 if (digits.isInfinite()) {
119 return countChar32ForInfinity();
120 }
121 return countChar32(
122 grouping,
123 digits.getInterval(),
124 options);
125}
126
127int32_t
128DigitFormatter::countChar32(
129 const VisibleDigitsWithExponent &digits,
130 const SciFormatterOptions &options) const {
131 if (digits.isNaN()) {
132 return countChar32ForNaN();
133 }
134 if (digits.isInfinite()) {
135 return countChar32ForInfinity();
136 }
137 const VisibleDigits *exponent = digits.getExponent();
138 if (exponent == NULL) {
139 DigitGrouping grouping;
140 return countChar32(
141 grouping,
142 digits.getMantissa().getInterval(),
143 options.fMantissa);
144 }
145 return countChar32(
146 *exponent, digits.getMantissa().getInterval(), options);
147}
148
149int32_t
150DigitFormatter::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);
160 return count;
161}
162
163UnicodeString &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);
171 }
172 if (digits.isInfinite()) {
173 return formatInfinity(handler, appendTo);
174 }
175
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;
181
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) {
187 appendField(
188 UNUM_DECIMAL_SEPARATOR_FIELD,
189 fDecimal,
190 handler,
191 appendTo);
192 }
193 return appendTo;
194 }
195 {
196 UnicodeStringAppender appender(appendTo);
197 for (int32_t i = interval.getMostSignificantExclusive() - 1;
198 i >= interval.getLeastSignificantInclusive(); --i) {
199 if (i == -1) {
200 appender.flush();
201 appendField(
202 UNUM_DECIMAL_SEPARATOR_FIELD,
203 fDecimal,
204 handler,
205 appendTo);
206 fracBegin = appendTo.length();
207 }
208 appender.append(fLocalizedDigits[digits.getDigitByExponent(i)]);
209 if (grouping.isSeparatorAt(digitsLeftOfDecimal, i)) {
210 appender.flush();
211 appendField(
212 UNUM_GROUPING_SEPARATOR_FIELD,
213 fGroupingSeparator,
214 handler,
215 appendTo);
216 }
217 if (i == 0) {
218 appender.flush();
219 if (digitsLeftOfDecimal > 0) {
220 handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
221 }
222 }
223 }
224 if (options.fAlwaysShowDecimal && lastDigitPos == 0) {
225 appender.flush();
226 appendField(
227 UNUM_DECIMAL_SEPARATOR_FIELD,
228 fDecimal,
229 handler,
230 appendTo);
231 }
232 }
233 // lastDigitPos is never > 0 so we are guaranteed that kIntegerField
234 // is already added.
235 if (lastDigitPos < 0) {
236 handler.addAttribute(UNUM_FRACTION_FIELD, fracBegin, appendTo.length());
237 }
238 return appendTo;
239}
240
241UnicodeString &
242DigitFormatter::format(
243 const VisibleDigitsWithExponent &digits,
244 const SciFormatterOptions &options,
245 FieldPositionHandler &handler,
246 UnicodeString &appendTo) const {
247 DigitGrouping grouping;
248 format(
249 digits.getMantissa(),
250 grouping,
251 options.fMantissa,
252 handler,
253 appendTo);
254 const VisibleDigits *exponent = digits.getExponent();
255 if (exponent == NULL) {
256 return appendTo;
257 }
258 int32_t expBegin = appendTo.length();
259 appendTo.append(fExponent);
260 handler.addAttribute(
261 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 appendTo);
269}
270
271static int32_t formatInt(
272 int32_t value, uint8_t *digits) {
273 int32_t idx = 0;
274 while (value > 0) {
275 digits[idx++] = (uint8_t) (value % 10);
276 value /= 10;
277 }
278 return idx;
279}
280
281UnicodeString &
282DigitFormatter::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 int32_t i = range.pin(count) - 1;
290 int32_t begin = appendTo.length();
291
292 // Always emit '0' as placeholder for empty string.
293 if (i == -1) {
294 appendTo.append(fLocalizedDigits[0]);
295 handler.addAttribute(intField, begin, appendTo.length());
296 return appendTo;
297 }
298 {
299 UnicodeStringAppender appender(appendTo);
300 for (; i >= count; --i) {
301 appender.append(fLocalizedDigits[0]);
302 }
303 for (; i >= 0; --i) {
304 appender.append(fLocalizedDigits[digits[i]]);
305 }
306 }
307 handler.addAttribute(intField, begin, appendTo.length());
308 return appendTo;
309}
310
311UnicodeString &
312DigitFormatter::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 UBool neg = digits.isNegative();
320 if (neg || options.fAlwaysShowSign) {
321 appendField(
322 signField,
323 neg ? fNegativeSign : fPositiveSign,
324 handler,
325 appendTo);
326 }
327 int32_t begin = appendTo.length();
328 DigitGrouping grouping;
329 DigitFormatterOptions expOptions;
330 FieldPosition fpos(FieldPosition::DONT_CARE);
331 FieldPositionOnlyHandler noHandler(fpos);
332 format(
333 digits,
334 grouping,
335 expOptions,
336 noHandler,
337 appendTo);
338 handler.addAttribute(intField, begin, appendTo.length());
339 return appendTo;
340}
341
342int32_t
343DigitFormatter::countChar32ForExponent(
344 const VisibleDigits &exponent,
345 const DigitFormatterIntOptions &options) const {
346 int32_t result = 0;
347 UBool neg = exponent.isNegative();
348 if (neg || options.fAlwaysShowSign) {
349 result += neg ? fNegativeSign.countChar32() : fPositiveSign.countChar32();
350 }
351 DigitGrouping grouping;
352 DigitFormatterOptions expOptions;
353 result += countChar32(grouping, exponent.getInterval(), expOptions);
354 return result;
355}
356
357UnicodeString &
358DigitFormatter::formatPositiveInt32(
359 int32_t positiveValue,
360 const IntDigitCountRange &range,
361 FieldPositionHandler &handler,
362 UnicodeString &appendTo) const {
363 // super fast path
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());
368 return appendTo;
369 }
370 uint8_t digits[10];
371 int32_t count = formatInt(positiveValue, digits);
372 return formatDigits(
373 digits,
374 count,
375 range,
376 UNUM_INTEGER_FIELD,
377 handler,
378 appendTo);
379}
380
381UBool DigitFormatter::isStandardDigits() const {
382 UChar32 cdigit = 0x30;
383 for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
384 if (fLocalizedDigits[i] != cdigit) {
385 return FALSE;
386 }
387 ++cdigit;
388 }
389 return TRUE;
390}
391
392UBool
393DigitFormatter::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);
402
403 if (!result) {
404 return FALSE;
405 }
406 for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
407 if (fLocalizedDigits[i] != rhs.fLocalizedDigits[i]) {
408 return FALSE;
409 }
410 }
411 return TRUE;
412}
413
414
415U_NAMESPACE_END
416
417#endif /* #if !UCONFIG_NO_FORMATTING */