1 // Copyright (C) 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 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); 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 39 DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) { 40 setDecimalFormatSymbols(symbols); 41 } 42 43 void 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); 62 } 63 64 void 65 DigitFormatter::setDecimalFormatSymbolsForMonetary( 66 const DecimalFormatSymbols &symbols) { 67 setOtherDecimalFormatSymbols(symbols); 68 fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); 69 fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); 70 } 71 72 void 73 DigitFormatter::setDecimalFormatSymbols( 74 const DecimalFormatSymbols &symbols) { 75 setOtherDecimalFormatSymbols(symbols); 76 fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); 77 fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); 78 } 79 80 static 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 93 int32_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 110 int32_t 111 DigitFormatter::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 127 int32_t 128 DigitFormatter::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 149 int32_t 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); 160 return count; 161 } 162 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); 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 241 UnicodeString & 242 DigitFormatter::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 271 static 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 281 UnicodeString & 282 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 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 311 UnicodeString & 312 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 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 342 int32_t 343 DigitFormatter::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 357 UnicodeString & 358 DigitFormatter::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 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) { 385 return FALSE; 386 } 387 ++cdigit; 388 } 389 return TRUE; 390 } 391 392 UBool 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); 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 415 U_NAMESPACE_END 416 417 #endif /* #if !UCONFIG_NO_FORMATTING */ 418