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