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  * Copyright (C) 2015, International Business Machines
      5  * Corporation and others.  All Rights Reserved.
      6  *
      7  * file name: digitformatter.cpp
      8  */
      9 
     10 #include "unicode/utypes.h"
     11 
     12 #if !UCONFIG_NO_FORMATTING
     13 
     14 #include "unicode/dcfmtsym.h"
     15 #include "unicode/unum.h"
     16 
     17 #include "digitformatter.h"
     18 #include "digitgrouping.h"
     19 #include "digitinterval.h"
     20 #include "digitlst.h"
     21 #include "fphdlimp.h"
     22 #include "smallintformatter.h"
     23 #include "unistrappender.h"
     24 #include "visibledigits.h"
     25 
     26 U_NAMESPACE_BEGIN
     27 
     28 DigitFormatter::DigitFormatter()
     29         : fGroupingSeparator(",", -1, US_INV), fDecimal(".", -1, US_INV),
     30           fNegativeSign("-", -1, US_INV), fPositiveSign("+", -1, US_INV),
     31           fIsStandardDigits(TRUE), fExponent("E", -1, US_INV) {
     32     for (int32_t i = 0; i < 10; ++i) {
     33         fLocalizedDigits[i] = (UChar32) (0x30 + i);
     34     }
     35     fInfinity.setTo(UnicodeString("Inf", -1, US_INV), UNUM_INTEGER_FIELD);
     36     fNan.setTo(UnicodeString("Nan", -1, US_INV), UNUM_INTEGER_FIELD);
     37 }
     38 
     39 DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) {
     40     setDecimalFormatSymbols(symbols);
     41 }
     42 
     43 void
     44 DigitFormatter::setOtherDecimalFormatSymbols(
     45         const DecimalFormatSymbols &symbols) {
     46     fLocalizedDigits[0] = symbols.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
     47     fLocalizedDigits[1] = symbols.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0);
     48     fLocalizedDigits[2] = symbols.getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0);
     49     fLocalizedDigits[3] = symbols.getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0);
     50     fLocalizedDigits[4] = symbols.getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0);
     51     fLocalizedDigits[5] = symbols.getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0);
     52     fLocalizedDigits[6] = symbols.getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0);
     53     fLocalizedDigits[7] = symbols.getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0);
     54     fLocalizedDigits[8] = symbols.getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0);
     55     fLocalizedDigits[9] = symbols.getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
     56     fIsStandardDigits = isStandardDigits();
     57     fNegativeSign = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
     58     fPositiveSign = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
     59     fInfinity.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), UNUM_INTEGER_FIELD);
     60     fNan.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), UNUM_INTEGER_FIELD);
     61     fExponent = symbols.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
     62 }
     63 
     64 void
     65 DigitFormatter::setDecimalFormatSymbolsForMonetary(
     66         const DecimalFormatSymbols &symbols) {
     67     setOtherDecimalFormatSymbols(symbols);
     68     fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
     69     fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
     70 }
     71 
     72 void
     73 DigitFormatter::setDecimalFormatSymbols(
     74         const DecimalFormatSymbols &symbols) {
     75     setOtherDecimalFormatSymbols(symbols);
     76     fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
     77     fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
     78 }
     79 
     80 static void appendField(
     81         int32_t fieldId,
     82         const UnicodeString &value,
     83         FieldPositionHandler &handler,
     84         UnicodeString &appendTo) {
     85     int32_t currentLength = appendTo.length();
     86     appendTo.append(value);
     87     handler.addAttribute(
     88             fieldId,
     89             currentLength,
     90             appendTo.length());
     91 }
     92 
     93 int32_t DigitFormatter::countChar32(
     94         const DigitGrouping &grouping,
     95         const DigitInterval &interval,
     96         const DigitFormatterOptions &options) const {
     97     int32_t result = interval.length();
     98 
     99     // We always emit '0' in lieu of no digits.
    100     if (result == 0) {
    101         result = 1;
    102     }
    103     if (options.fAlwaysShowDecimal || interval.getLeastSignificantInclusive() < 0) {
    104         result += fDecimal.countChar32();
    105     }
    106     result += grouping.getSeparatorCount(interval.getIntDigitCount()) * fGroupingSeparator.countChar32();
    107     return result;
    108 }
    109 
    110 int32_t
    111 DigitFormatter::countChar32(
    112         const VisibleDigits &digits,
    113         const DigitGrouping &grouping,
    114         const DigitFormatterOptions &options) const {
    115     if (digits.isNaN()) {
    116         return countChar32ForNaN();
    117     }
    118     if (digits.isInfinite()) {
    119         return countChar32ForInfinity();
    120     }
    121     return countChar32(
    122             grouping,
    123             digits.getInterval(),
    124             options);
    125 }
    126 
    127 int32_t
    128 DigitFormatter::countChar32(
    129         const VisibleDigitsWithExponent &digits,
    130         const SciFormatterOptions &options) const {
    131     if (digits.isNaN()) {
    132         return countChar32ForNaN();
    133     }
    134     if (digits.isInfinite()) {
    135         return countChar32ForInfinity();
    136     }
    137     const VisibleDigits *exponent = digits.getExponent();
    138     if (exponent == NULL) {
    139         DigitGrouping grouping;
    140         return countChar32(
    141                 grouping,
    142                 digits.getMantissa().getInterval(),
    143                 options.fMantissa);
    144     }
    145     return countChar32(
    146             *exponent, digits.getMantissa().getInterval(), options);
    147 }
    148 
    149 int32_t
    150 DigitFormatter::countChar32(
    151         const VisibleDigits &exponent,
    152         const DigitInterval &mantissaInterval,
    153         const SciFormatterOptions &options) const {
    154     DigitGrouping grouping;
    155     int32_t count = countChar32(
    156             grouping, mantissaInterval, options.fMantissa);
    157     count += fExponent.countChar32();
    158     count += countChar32ForExponent(
    159             exponent, options.fExponent);
    160     return count;
    161 }
    162 
    163 UnicodeString &DigitFormatter::format(
    164         const VisibleDigits &digits,
    165         const DigitGrouping &grouping,
    166         const DigitFormatterOptions &options,
    167         FieldPositionHandler &handler,
    168         UnicodeString &appendTo) const {
    169     if (digits.isNaN()) {
    170         return formatNaN(handler, appendTo);
    171     }
    172     if (digits.isInfinite()) {
    173         return formatInfinity(handler, appendTo);
    174     }
    175 
    176     const DigitInterval &interval = digits.getInterval();
    177     int32_t digitsLeftOfDecimal = interval.getMostSignificantExclusive();
    178     int32_t lastDigitPos = interval.getLeastSignificantInclusive();
    179     int32_t intBegin = appendTo.length();
    180     int32_t fracBegin = 0; /* initialize to avoid compiler warning */
    181 
    182     // Emit "0" instead of empty string.
    183     if (digitsLeftOfDecimal == 0 && lastDigitPos == 0) {
    184         appendTo.append(fLocalizedDigits[0]);
    185         handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
    186         if (options.fAlwaysShowDecimal) {
    187             appendField(
    188                     UNUM_DECIMAL_SEPARATOR_FIELD,
    189                     fDecimal,
    190                     handler,
    191                     appendTo);
    192         }
    193         return appendTo;
    194     }
    195     {
    196         UnicodeStringAppender appender(appendTo);
    197         for (int32_t i = interval.getMostSignificantExclusive() - 1;
    198                 i >= interval.getLeastSignificantInclusive(); --i) {
    199             if (i == -1) {
    200                 appender.flush();
    201                 appendField(
    202                         UNUM_DECIMAL_SEPARATOR_FIELD,
    203                         fDecimal,
    204                         handler,
    205                         appendTo);
    206                 fracBegin = appendTo.length();
    207             }
    208             appender.append(fLocalizedDigits[digits.getDigitByExponent(i)]);
    209             if (grouping.isSeparatorAt(digitsLeftOfDecimal, i)) {
    210                 appender.flush();
    211                 appendField(
    212                         UNUM_GROUPING_SEPARATOR_FIELD,
    213                         fGroupingSeparator,
    214                         handler,
    215                         appendTo);
    216             }
    217             if (i == 0) {
    218                 appender.flush();
    219                 if (digitsLeftOfDecimal > 0) {
    220                     handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
    221                 }
    222             }
    223         }
    224         if (options.fAlwaysShowDecimal && lastDigitPos == 0) {
    225             appender.flush();
    226             appendField(
    227                     UNUM_DECIMAL_SEPARATOR_FIELD,
    228                     fDecimal,
    229                     handler,
    230                     appendTo);
    231         }
    232     }
    233     // lastDigitPos is never > 0 so we are guaranteed that kIntegerField
    234     // is already added.
    235     if (lastDigitPos < 0) {
    236         handler.addAttribute(UNUM_FRACTION_FIELD, fracBegin, appendTo.length());
    237     }
    238     return appendTo;
    239 }
    240 
    241 UnicodeString &
    242 DigitFormatter::format(
    243         const VisibleDigitsWithExponent &digits,
    244         const SciFormatterOptions &options,
    245         FieldPositionHandler &handler,
    246         UnicodeString &appendTo) const {
    247     DigitGrouping grouping;
    248     format(
    249             digits.getMantissa(),
    250             grouping,
    251             options.fMantissa,
    252             handler,
    253             appendTo);
    254     const VisibleDigits *exponent = digits.getExponent();
    255     if (exponent == NULL) {
    256         return appendTo;
    257     }
    258     int32_t expBegin = appendTo.length();
    259     appendTo.append(fExponent);
    260     handler.addAttribute(
    261             UNUM_EXPONENT_SYMBOL_FIELD, expBegin, appendTo.length());
    262     return formatExponent(
    263             *exponent,
    264             options.fExponent,
    265             UNUM_EXPONENT_SIGN_FIELD,
    266             UNUM_EXPONENT_FIELD,
    267             handler,
    268             appendTo);
    269 }
    270 
    271 static int32_t formatInt(
    272         int32_t value, uint8_t *digits) {
    273     int32_t idx = 0;
    274     while (value > 0) {
    275         digits[idx++] = (uint8_t) (value % 10);
    276         value /= 10;
    277     }
    278     return idx;
    279 }
    280 
    281 UnicodeString &
    282 DigitFormatter::formatDigits(
    283         const uint8_t *digits,
    284         int32_t count,
    285         const IntDigitCountRange &range,
    286         int32_t intField,
    287         FieldPositionHandler &handler,
    288         UnicodeString &appendTo) const {
    289     int32_t i = range.pin(count) - 1;
    290     int32_t begin = appendTo.length();
    291 
    292     // Always emit '0' as placeholder for empty string.
    293     if (i == -1) {
    294         appendTo.append(fLocalizedDigits[0]);
    295         handler.addAttribute(intField, begin, appendTo.length());
    296         return appendTo;
    297     }
    298     {
    299         UnicodeStringAppender appender(appendTo);
    300         for (; i >= count; --i) {
    301             appender.append(fLocalizedDigits[0]);
    302         }
    303         for (; i >= 0; --i) {
    304             appender.append(fLocalizedDigits[digits[i]]);
    305         }
    306     }
    307     handler.addAttribute(intField, begin, appendTo.length());
    308     return appendTo;
    309 }
    310 
    311 UnicodeString &
    312 DigitFormatter::formatExponent(
    313         const VisibleDigits &digits,
    314         const DigitFormatterIntOptions &options,
    315         int32_t signField,
    316         int32_t intField,
    317         FieldPositionHandler &handler,
    318         UnicodeString &appendTo) const {
    319     UBool neg = digits.isNegative();
    320     if (neg || options.fAlwaysShowSign) {
    321         appendField(
    322                 signField,
    323                 neg ? fNegativeSign : fPositiveSign,
    324                 handler,
    325                 appendTo);
    326     }
    327     int32_t begin = appendTo.length();
    328     DigitGrouping grouping;
    329     DigitFormatterOptions expOptions;
    330     FieldPosition fpos(FieldPosition::DONT_CARE);
    331     FieldPositionOnlyHandler noHandler(fpos);
    332     format(
    333             digits,
    334             grouping,
    335             expOptions,
    336             noHandler,
    337             appendTo);
    338     handler.addAttribute(intField, begin, appendTo.length());
    339     return appendTo;
    340 }
    341 
    342 int32_t
    343 DigitFormatter::countChar32ForExponent(
    344         const VisibleDigits &exponent,
    345         const DigitFormatterIntOptions &options) const {
    346     int32_t result = 0;
    347     UBool neg = exponent.isNegative();
    348     if (neg || options.fAlwaysShowSign) {
    349         result += neg ? fNegativeSign.countChar32() : fPositiveSign.countChar32();
    350     }
    351     DigitGrouping grouping;
    352     DigitFormatterOptions expOptions;
    353     result += countChar32(grouping, exponent.getInterval(), expOptions);
    354     return result;
    355 }
    356 
    357 UnicodeString &
    358 DigitFormatter::formatPositiveInt32(
    359         int32_t positiveValue,
    360         const IntDigitCountRange &range,
    361         FieldPositionHandler &handler,
    362         UnicodeString &appendTo) const {
    363     // super fast path
    364     if (fIsStandardDigits && SmallIntFormatter::canFormat(positiveValue, range)) {
    365         int32_t begin = appendTo.length();
    366         SmallIntFormatter::format(positiveValue, range, appendTo);
    367         handler.addAttribute(UNUM_INTEGER_FIELD, begin, appendTo.length());
    368         return appendTo;
    369     }
    370     uint8_t digits[10];
    371     int32_t count = formatInt(positiveValue, digits);
    372     return formatDigits(
    373             digits,
    374             count,
    375             range,
    376             UNUM_INTEGER_FIELD,
    377             handler,
    378             appendTo);
    379 }
    380 
    381 UBool DigitFormatter::isStandardDigits() const {
    382     UChar32 cdigit = 0x30;
    383     for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
    384         if (fLocalizedDigits[i] != cdigit) {
    385             return FALSE;
    386         }
    387         ++cdigit;
    388     }
    389     return TRUE;
    390 }
    391 
    392 UBool
    393 DigitFormatter::equals(const DigitFormatter &rhs) const {
    394     UBool result = (fGroupingSeparator == rhs.fGroupingSeparator) &&
    395                    (fDecimal == rhs.fDecimal) &&
    396                    (fNegativeSign == rhs.fNegativeSign) &&
    397                    (fPositiveSign == rhs.fPositiveSign) &&
    398                    (fInfinity.equals(rhs.fInfinity)) &&
    399                    (fNan.equals(rhs.fNan)) &&
    400                    (fIsStandardDigits == rhs.fIsStandardDigits) &&
    401                    (fExponent == rhs.fExponent);
    402 
    403     if (!result) {
    404         return FALSE;
    405     }
    406     for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
    407         if (fLocalizedDigits[i] != rhs.fLocalizedDigits[i]) {
    408             return FALSE;
    409         }
    410     }
    411     return TRUE;
    412 }
    413 
    414 
    415 U_NAMESPACE_END
    416 
    417 #endif /* #if !UCONFIG_NO_FORMATTING */
    418