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