1 /* 2 ******************************************************************************** 3 * Copyright (C) 2015, International Business Machines 4 * Corporation and others. All Rights Reserved. 5 ******************************************************************************** 6 * 7 * File decimfmtimpl.h 8 ******************************************************************************** 9 */ 10 11 #ifndef DECIMFMTIMPL_H 12 #define DECIMFMTIMPL_H 13 14 #include "unicode/utypes.h" 15 16 #if !UCONFIG_NO_FORMATTING 17 18 #include "unicode/decimfmt.h" 19 #include "unicode/uobject.h" 20 #include "affixpatternparser.h" 21 #include "digitaffixesandpadding.h" 22 #include "digitformatter.h" 23 #include "digitgrouping.h" 24 #include "precision.h" 25 26 U_NAMESPACE_BEGIN 27 28 class UnicodeString; 29 class FieldPosition; 30 class ValueFormatter; 31 class FieldPositionHandler; 32 class FixedDecimal; 33 34 /** 35 * DecimalFormatImpl is the glue code between the legacy DecimalFormat class 36 * and the new decimal formatting classes. DecimalFormat still handles 37 * parsing directly. However, DecimalFormat uses attributes of this class 38 * for parsing when possible. 39 * 40 * The public API of this class closely mirrors the legacy API of the 41 * legacy DecimalFormat deviating only when the legacy API does not make 42 * sense. For example, although DecimalFormat has a 43 * getPadCharacterString() method, DecimalFormatImpl has a getPadCharacter() 44 * method because formatting uses only a single pad character for padding. 45 * 46 * Each legacy DecimalFormat instance heap allocates its own instance of 47 * this class. Most DecimalFormat methods that deal with formatting simply 48 * delegate to the DecimalFormat's DecimalFormatImpl method. 49 * 50 * Because DecimalFormat extends NumberFormat, Each instance of this class 51 * "borrows" a pointer to the NumberFormat part of its enclosing DecimalFormat 52 * instance. This way each DecimalFormatImpl instance can read or even modify 53 * the NumberFormat portion of its enclosing DecimalFormat instance. 54 * 55 * Directed acyclic graph (DAG): 56 * 57 * This class can be represented as a directed acyclic graph (DAG) where each 58 * vertex is an attribute, and each directed edge indicates that the value 59 * of the destination attribute is calculated from the value of the source 60 * attribute. Attributes with setter methods reside at the bottom of the 61 * DAG. That is, no edges point to them. We call these independent attributes 62 * because their values can be set independently of one another. The rest of 63 * the attributes are derived attributes because their values depend on the 64 * independent attributes. DecimalFormatImpl often uses the derived 65 * attributes, not the independent attributes, when formatting numbers. 66 * 67 * The independent attributes at the bottom of the DAG correspond to the legacy 68 * attributes of DecimalFormat while the attributes at the top of the DAG 69 * correspond to the attributes of the new code. The edges of the DAG 70 * correspond to the code that handles the complex interaction among all the 71 * legacy attributes of the DecimalFormat API. 72 * 73 * We use a DAG for three reasons. 74 * 75 * First, the DAG preserves backward compatibility. Clients of the legacy 76 * DecimalFormat expect existing getters and setters of each attribute to be 77 * consistent. That means if a client sets a particular attribute to a new 78 * value, the attribute should retain that value until the client sets it to 79 * a new value. The DAG allows these attributes to remain consistent even 80 * though the new code may not use them when formatting. 81 * 82 * Second, the DAG obviates the need to recalculate derived attributes with 83 * each format. Instead, the DAG "remembers" the values of all derived 84 * attributes. Only setting an independent attribute requires a recalculation. 85 * Moreover, setting an independent attribute recalculates only the affected 86 * dependent attributes rather than all dependent attributes. 87 * 88 * Third, the DAG abstracts away the complex interaction among the legacy 89 * attributes of the DecimalFormat API. 90 * 91 * Only the independent attributes of the DAG have setters and getters. 92 * Derived attributes have no setters (and often no getters either). 93 * 94 * Copy and assign: 95 * 96 * For copy and assign, DecimalFormatImpl copies and assigns every attribute 97 * regardless of whether or not it is independent. We do this for simplicity. 98 * 99 * Implementation of the DAG: 100 * 101 * The DAG consists of three smaller DAGs: 102 * 1. Grouping attributes 103 * 2. Precision attributes 104 * 3. Formatting attributes. 105 * 106 * The first two DAGs are simple in that setting any independent attribute 107 * in the DAG recalculates all the dependent attributes in that DAG. 108 * The updateGrouping() and updatePrecision() perform the respective 109 * recalculations. 110 * 111 * Because some of the derived formatting attributes are expensive to 112 * calculate, the formatting attributes DAG is more complex. The 113 * updateFormatting() method is composed of many updateFormattingXXX() 114 * methods, each of which recalculates a single derived attribute. The 115 * updateFormatting() method accepts a bitfield of recently changed 116 * attributes and passes this bitfield by reference to each of the 117 * updateFormattingXXX() methods. Each updateFormattingXXX() method checks 118 * the bitfield to see if any of the attributes it uses to compute the XXX 119 * attribute changed. If none of them changed, it exists immediately. However, 120 * if at least one of them changed, it recalculates the XXX attribute and 121 * sets the corresponding bit in the bitfield. In this way, each 122 * updateFormattingXXX() method encodes the directed edges in the formatting 123 * DAG that point to the attribute its calculating. 124 * 125 * Maintenance of the updateFormatting() method. 126 * 127 * Use care when changing the updateFormatting() method. 128 * The updateFormatting() method must call each updateFormattingXXX() in the 129 * same partial order that the formatting DAG prescribes. That is, the 130 * attributes near the bottom of the DAG must be calculated before attributes 131 * further up. As we mentioned in the prvious paragraph, the directed edges of 132 * the formatting DAG are encoded within each updateFormattingXXX() method. 133 * Finally, adding new attributes may involve adding to the bitmap that the 134 * updateFormatting() method uses. The top most attributes in the DAG, 135 * those that do not point to any attributes but only have attributes 136 * pointing to it, need not have a slot in the bitmap. 137 * 138 * Keep in mind that most of the code that makes the legacy DecimalFormat API 139 * work the way it always has before can be found in these various updateXXX() 140 * methods. For example the updatePrecisionForScientific() method 141 * handles the complex interactions amoung the various precision attributes 142 * when formatting in scientific notation. Changing the way attributes 143 * interract, often means changing one of these updateXXX() methods. 144 * 145 * Conclusion: 146 * 147 * The DecimFmtImpl class is the glue code between the legacy and new 148 * number formatting code. It uses a direct acyclic graph (DAG) to 149 * maintain backward compatibility, to make the code efficient, and to 150 * abstract away the complex interraction among legacy attributs. 151 */ 152 153 154 class DecimalFormatImpl : public UObject { 155 public: 156 157 DecimalFormatImpl( 158 NumberFormat *super, 159 const Locale &locale, 160 const UnicodeString &pattern, 161 UErrorCode &status); 162 DecimalFormatImpl( 163 NumberFormat *super, 164 const UnicodeString &pattern, 165 DecimalFormatSymbols *symbolsToAdopt, 166 UParseError &parseError, 167 UErrorCode &status); 168 DecimalFormatImpl( 169 NumberFormat *super, 170 const DecimalFormatImpl &other, 171 UErrorCode &status); 172 DecimalFormatImpl &assign( 173 const DecimalFormatImpl &other, UErrorCode &status); 174 virtual ~DecimalFormatImpl(); 175 void adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt); 176 const DecimalFormatSymbols &getDecimalFormatSymbols() const { 177 return *fSymbols; 178 } 179 UnicodeString &format( 180 int32_t number, 181 UnicodeString &appendTo, 182 FieldPosition &pos, 183 UErrorCode &status) const; 184 UnicodeString &format( 185 int32_t number, 186 UnicodeString &appendTo, 187 FieldPositionIterator *posIter, 188 UErrorCode &status) const; 189 UnicodeString &format( 190 int64_t number, 191 UnicodeString &appendTo, 192 FieldPosition &pos, 193 UErrorCode &status) const; 194 UnicodeString &format( 195 double number, 196 UnicodeString &appendTo, 197 FieldPosition &pos, 198 UErrorCode &status) const; 199 UnicodeString &format( 200 const DigitList &number, 201 UnicodeString &appendTo, 202 FieldPosition &pos, 203 UErrorCode &status) const; 204 UnicodeString &format( 205 int64_t number, 206 UnicodeString &appendTo, 207 FieldPositionIterator *posIter, 208 UErrorCode &status) const; 209 UnicodeString &format( 210 double number, 211 UnicodeString &appendTo, 212 FieldPositionIterator *posIter, 213 UErrorCode &status) const; 214 UnicodeString &format( 215 const DigitList &number, 216 UnicodeString &appendTo, 217 FieldPositionIterator *posIter, 218 UErrorCode &status) const; 219 UnicodeString &format( 220 const StringPiece &number, 221 UnicodeString &appendTo, 222 FieldPositionIterator *posIter, 223 UErrorCode &status) const; 224 UnicodeString &format( 225 const VisibleDigitsWithExponent &digits, 226 UnicodeString &appendTo, 227 FieldPosition &pos, 228 UErrorCode &status) const; 229 UnicodeString &format( 230 const VisibleDigitsWithExponent &digits, 231 UnicodeString &appendTo, 232 FieldPositionIterator *posIter, 233 UErrorCode &status) const; 234 235 UBool operator==(const DecimalFormatImpl &) const; 236 237 UBool operator!=(const DecimalFormatImpl &other) const { 238 return !(*this == other); 239 } 240 241 void setRoundingMode(DecimalFormat::ERoundingMode mode) { 242 fRoundingMode = mode; 243 fEffPrecision.fMantissa.fExactOnly = (fRoundingMode == DecimalFormat::kRoundUnnecessary); 244 fEffPrecision.fMantissa.fRoundingMode = mode; 245 } 246 DecimalFormat::ERoundingMode getRoundingMode() const { 247 return fRoundingMode; 248 } 249 void setFailIfMoreThanMaxDigits(UBool b) { 250 fEffPrecision.fMantissa.fFailIfOverMax = b; 251 } 252 UBool isFailIfMoreThanMaxDigits() const { return fEffPrecision.fMantissa.fFailIfOverMax; } 253 void setMinimumSignificantDigits(int32_t newValue); 254 void setMaximumSignificantDigits(int32_t newValue); 255 void setMinMaxSignificantDigits(int32_t min, int32_t max); 256 void setScientificNotation(UBool newValue); 257 void setSignificantDigitsUsed(UBool newValue); 258 259 int32_t getMinimumSignificantDigits() const { 260 return fMinSigDigits; } 261 int32_t getMaximumSignificantDigits() const { 262 return fMaxSigDigits; } 263 UBool isScientificNotation() const { return fUseScientific; } 264 UBool areSignificantDigitsUsed() const { return fUseSigDigits; } 265 void setGroupingSize(int32_t newValue); 266 void setSecondaryGroupingSize(int32_t newValue); 267 void setMinimumGroupingDigits(int32_t newValue); 268 int32_t getGroupingSize() const { return fGrouping.fGrouping; } 269 int32_t getSecondaryGroupingSize() const { return fGrouping.fGrouping2; } 270 int32_t getMinimumGroupingDigits() const { return fGrouping.fMinGrouping; } 271 void applyPattern(const UnicodeString &pattern, UErrorCode &status); 272 void applyPatternFavorCurrencyPrecision( 273 const UnicodeString &pattern, UErrorCode &status); 274 void applyPattern( 275 const UnicodeString &pattern, UParseError &perror, UErrorCode &status); 276 void applyLocalizedPattern(const UnicodeString &pattern, UErrorCode &status); 277 void applyLocalizedPattern( 278 const UnicodeString &pattern, UParseError &perror, UErrorCode &status); 279 void setCurrencyUsage(UCurrencyUsage usage, UErrorCode &status); 280 UCurrencyUsage getCurrencyUsage() const { return fCurrencyUsage; } 281 void setRoundingIncrement(double d); 282 double getRoundingIncrement() const; 283 int32_t getMultiplier() const; 284 void setMultiplier(int32_t m); 285 UChar32 getPadCharacter() const { return fAffixes.fPadChar; } 286 void setPadCharacter(UChar32 c) { fAffixes.fPadChar = c; } 287 int32_t getFormatWidth() const { return fAffixes.fWidth; } 288 void setFormatWidth(int32_t x) { fAffixes.fWidth = x; } 289 DigitAffixesAndPadding::EPadPosition getPadPosition() const { 290 return fAffixes.fPadPosition; 291 } 292 void setPadPosition(DigitAffixesAndPadding::EPadPosition x) { 293 fAffixes.fPadPosition = x; 294 } 295 int32_t getMinimumExponentDigits() const { 296 return fEffPrecision.fMinExponentDigits; 297 } 298 void setMinimumExponentDigits(int32_t x) { 299 fEffPrecision.fMinExponentDigits = x; 300 } 301 UBool isExponentSignAlwaysShown() const { 302 return fOptions.fExponent.fAlwaysShowSign; 303 } 304 void setExponentSignAlwaysShown(UBool x) { 305 fOptions.fExponent.fAlwaysShowSign = x; 306 } 307 UBool isDecimalSeparatorAlwaysShown() const { 308 return fOptions.fMantissa.fAlwaysShowDecimal; 309 } 310 void setDecimalSeparatorAlwaysShown(UBool x) { 311 fOptions.fMantissa.fAlwaysShowDecimal = x; 312 } 313 UnicodeString &getPositivePrefix(UnicodeString &result) const; 314 UnicodeString &getPositiveSuffix(UnicodeString &result) const; 315 UnicodeString &getNegativePrefix(UnicodeString &result) const; 316 UnicodeString &getNegativeSuffix(UnicodeString &result) const; 317 void setPositivePrefix(const UnicodeString &str); 318 void setPositiveSuffix(const UnicodeString &str); 319 void setNegativePrefix(const UnicodeString &str); 320 void setNegativeSuffix(const UnicodeString &str); 321 UnicodeString &toPattern(UnicodeString& result) const; 322 FixedDecimal &getFixedDecimal(double value, FixedDecimal &result, UErrorCode &status) const; 323 FixedDecimal &getFixedDecimal(DigitList &number, FixedDecimal &result, UErrorCode &status) const; 324 DigitList &round(DigitList &number, UErrorCode &status) const; 325 326 VisibleDigitsWithExponent & 327 initVisibleDigitsWithExponent( 328 int64_t number, 329 VisibleDigitsWithExponent &digits, 330 UErrorCode &status) const; 331 VisibleDigitsWithExponent & 332 initVisibleDigitsWithExponent( 333 double number, 334 VisibleDigitsWithExponent &digits, 335 UErrorCode &status) const; 336 VisibleDigitsWithExponent & 337 initVisibleDigitsWithExponent( 338 DigitList &number, 339 VisibleDigitsWithExponent &digits, 340 UErrorCode &status) const; 341 342 void updatePrecision(); 343 void updateGrouping(); 344 void updateCurrency(UErrorCode &status); 345 346 347 private: 348 // Disallow copy and assign 349 DecimalFormatImpl(const DecimalFormatImpl &other); 350 DecimalFormatImpl &operator=(const DecimalFormatImpl &other); 351 NumberFormat *fSuper; 352 DigitList fMultiplier; 353 int32_t fScale; 354 355 DecimalFormat::ERoundingMode fRoundingMode; 356 357 // These fields include what the user can see and set. 358 // When the user updates these fields, it triggers automatic updates of 359 // other fields that may be invisible to user 360 361 // Updating any of the following fields triggers an update to 362 // fEffPrecision.fMantissa.fMin, 363 // fEffPrecision.fMantissa.fMax, 364 // fEffPrecision.fMantissa.fSignificant fields 365 // We have this two phase update because of backward compatibility. 366 // DecimalFormat has to remember all settings even if those settings are 367 // invalid or disabled. 368 int32_t fMinSigDigits; 369 int32_t fMaxSigDigits; 370 UBool fUseScientific; 371 UBool fUseSigDigits; 372 // In addition to these listed above, changes to min/max int digits and 373 // min/max frac digits from fSuper also trigger an update. 374 375 // Updating any of the following fields triggers an update to 376 // fEffGrouping field Again we do it this way because original 377 // grouping settings have to be retained if grouping is turned off. 378 DigitGrouping fGrouping; 379 // In addition to these listed above, changes to isGroupingUsed in 380 // fSuper also triggers an update to fEffGrouping. 381 382 // Updating any of the following fields triggers updates on the following: 383 // fMonetary, fRules, fAffixParser, fCurrencyAffixInfo, 384 // fFormatter, fAffixes.fPositivePrefiix, fAffixes.fPositiveSuffix, 385 // fAffixes.fNegativePrefiix, fAffixes.fNegativeSuffix 386 // We do this two phase update because localizing the affix patterns 387 // and formatters can be expensive. Better to do it once with the setters 388 // than each time within format. 389 AffixPattern fPositivePrefixPattern; 390 AffixPattern fNegativePrefixPattern; 391 AffixPattern fPositiveSuffixPattern; 392 AffixPattern fNegativeSuffixPattern; 393 DecimalFormatSymbols *fSymbols; 394 UCurrencyUsage fCurrencyUsage; 395 // In addition to these listed above, changes to getCurrency() in 396 // fSuper also triggers an update. 397 398 // Optional may be NULL 399 PluralRules *fRules; 400 401 // These fields are totally hidden from user and are used to derive the affixes 402 // in fAffixes below from the four affix patterns above. 403 UBool fMonetary; 404 AffixPatternParser fAffixParser; 405 CurrencyAffixInfo fCurrencyAffixInfo; 406 407 // The actual precision used when formatting 408 ScientificPrecision fEffPrecision; 409 410 // The actual grouping used when formatting 411 DigitGrouping fEffGrouping; 412 SciFormatterOptions fOptions; // Encapsulates fixed precision options 413 DigitFormatter fFormatter; 414 DigitAffixesAndPadding fAffixes; 415 416 UnicodeString &formatInt32( 417 int32_t number, 418 UnicodeString &appendTo, 419 FieldPositionHandler &handler, 420 UErrorCode &status) const; 421 422 UnicodeString &formatInt64( 423 int64_t number, 424 UnicodeString &appendTo, 425 FieldPositionHandler &handler, 426 UErrorCode &status) const; 427 428 UnicodeString &formatDouble( 429 double number, 430 UnicodeString &appendTo, 431 FieldPositionHandler &handler, 432 UErrorCode &status) const; 433 434 // Scales for precent or permille symbols 435 UnicodeString &formatDigitList( 436 DigitList &number, 437 UnicodeString &appendTo, 438 FieldPositionHandler &handler, 439 UErrorCode &status) const; 440 441 // Does not scale for precent or permille symbols 442 UnicodeString &formatAdjustedDigitList( 443 DigitList &number, 444 UnicodeString &appendTo, 445 FieldPositionHandler &handler, 446 UErrorCode &status) const; 447 448 UnicodeString &formatVisibleDigitsWithExponent( 449 const VisibleDigitsWithExponent &number, 450 UnicodeString &appendTo, 451 FieldPositionHandler &handler, 452 UErrorCode &status) const; 453 454 VisibleDigitsWithExponent & 455 initVisibleDigitsFromAdjusted( 456 DigitList &number, 457 VisibleDigitsWithExponent &digits, 458 UErrorCode &status) const; 459 460 template<class T> 461 UBool maybeFormatWithDigitList( 462 T number, 463 UnicodeString &appendTo, 464 FieldPositionHandler &handler, 465 UErrorCode &status) const; 466 467 template<class T> 468 UBool maybeInitVisibleDigitsFromDigitList( 469 T number, 470 VisibleDigitsWithExponent &digits, 471 UErrorCode &status) const; 472 473 DigitList &adjustDigitList(DigitList &number, UErrorCode &status) const; 474 475 void applyPattern( 476 const UnicodeString &pattern, 477 UBool localized, UParseError &perror, UErrorCode &status); 478 479 ValueFormatter &prepareValueFormatter(ValueFormatter &vf) const; 480 void setMultiplierScale(int32_t s); 481 int32_t getPatternScale() const; 482 void setScale(int32_t s) { fScale = s; } 483 int32_t getScale() const { return fScale; } 484 485 // Updates everything 486 void updateAll(UErrorCode &status); 487 void updateAll( 488 int32_t formattingFlags, 489 UBool updatePrecisionBasedOnCurrency, 490 UErrorCode &status); 491 492 // Updates from formatting pattern changes 493 void updateForApplyPattern(UErrorCode &status); 494 void updateForApplyPatternFavorCurrencyPrecision(UErrorCode &status); 495 496 // Updates from changes to third group of attributes 497 void updateFormatting(int32_t changedFormattingFields, UErrorCode &status); 498 void updateFormatting( 499 int32_t changedFormattingFields, 500 UBool updatePrecisionBasedOnCurrency, 501 UErrorCode &status); 502 503 // Helper functions for updatePrecision 504 void updatePrecisionForScientific(); 505 void updatePrecisionForFixed(); 506 void extractMinMaxDigits(DigitInterval &min, DigitInterval &max) const; 507 void extractSigDigits(SignificantDigitInterval &sig) const; 508 509 // Helper functions for updateFormatting 510 void updateFormattingUsesCurrency(int32_t &changedFormattingFields); 511 void updateFormattingPluralRules( 512 int32_t &changedFormattingFields, UErrorCode &status); 513 void updateFormattingAffixParser(int32_t &changedFormattingFields); 514 void updateFormattingCurrencyAffixInfo( 515 int32_t &changedFormattingFields, 516 UBool updatePrecisionBasedOnCurrency, 517 UErrorCode &status); 518 void updateFormattingFixedPointFormatter( 519 int32_t &changedFormattingFields); 520 void updateFormattingLocalizedPositivePrefix( 521 int32_t &changedFormattingFields, UErrorCode &status); 522 void updateFormattingLocalizedPositiveSuffix( 523 int32_t &changedFormattingFields, UErrorCode &status); 524 void updateFormattingLocalizedNegativePrefix( 525 int32_t &changedFormattingFields, UErrorCode &status); 526 void updateFormattingLocalizedNegativeSuffix( 527 int32_t &changedFormattingFields, UErrorCode &status); 528 529 int32_t computeExponentPatternLength() const; 530 int32_t countFractionDigitAndDecimalPatternLength(int32_t fracDigitCount) const; 531 UnicodeString &toNumberPattern( 532 UBool hasPadding, int32_t minimumLength, UnicodeString& result) const; 533 534 int32_t getOldFormatWidth() const; 535 const UnicodeString &getConstSymbol( 536 DecimalFormatSymbols::ENumberFormatSymbol symbol) const; 537 UBool isParseFastpath() const; 538 539 friend class DecimalFormat; 540 541 }; 542 543 544 U_NAMESPACE_END 545 #endif /* #if !UCONFIG_NO_FORMATTING */ 546 #endif // DECIMFMTIMPL_H 547 //eof 548