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 24U_NAMESPACE_BEGIN 25 26DigitFormatter::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 37DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) { 38 setDecimalFormatSymbols(symbols); 39} 40 41void 42DigitFormatter::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 62void 63DigitFormatter::setDecimalFormatSymbolsForMonetary( 64 const DecimalFormatSymbols &symbols) { 65 setOtherDecimalFormatSymbols(symbols); 66 fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); 67 fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); 68} 69 70void 71DigitFormatter::setDecimalFormatSymbols( 72 const DecimalFormatSymbols &symbols) { 73 setOtherDecimalFormatSymbols(symbols); 74 fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); 75 fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); 76} 77 78static 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 91int32_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 108int32_t 109DigitFormatter::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 125int32_t 126DigitFormatter::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 147int32_t 148DigitFormatter::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 161UnicodeString &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 239UnicodeString & 240DigitFormatter::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 269static 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 279UnicodeString & 280DigitFormatter::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 309UnicodeString & 310DigitFormatter::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 340int32_t 341DigitFormatter::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 355UnicodeString & 356DigitFormatter::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 379UBool 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 390UBool 391DigitFormatter::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 413U_NAMESPACE_END 414 415#endif /* #if !UCONFIG_NO_FORMATTING */ 416