Home | History | Annotate | Download | only in i18n
      1 //  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