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