// Copyright (C) 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* * Copyright (C) 2015, International Business Machines * Corporation and others. All Rights Reserved. * * file name: digitformatter.cpp */ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include "unicode/dcfmtsym.h" #include "unicode/unum.h" #include "digitformatter.h" #include "digitgrouping.h" #include "digitinterval.h" #include "digitlst.h" #include "fphdlimp.h" #include "smallintformatter.h" #include "unistrappender.h" #include "visibledigits.h" U_NAMESPACE_BEGIN DigitFormatter::DigitFormatter() : fGroupingSeparator(",", -1, US_INV), fDecimal(".", -1, US_INV), fNegativeSign("-", -1, US_INV), fPositiveSign("+", -1, US_INV), fIsStandardDigits(TRUE), fExponent("E", -1, US_INV) { for (int32_t i = 0; i < 10; ++i) { fLocalizedDigits[i] = (UChar32) (0x30 + i); } fInfinity.setTo(UnicodeString("Inf", -1, US_INV), UNUM_INTEGER_FIELD); fNan.setTo(UnicodeString("Nan", -1, US_INV), UNUM_INTEGER_FIELD); } DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) { setDecimalFormatSymbols(symbols); } void DigitFormatter::setOtherDecimalFormatSymbols( const DecimalFormatSymbols &symbols) { fLocalizedDigits[0] = symbols.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0); fLocalizedDigits[1] = symbols.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0); fLocalizedDigits[2] = symbols.getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0); fLocalizedDigits[3] = symbols.getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0); fLocalizedDigits[4] = symbols.getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0); fLocalizedDigits[5] = symbols.getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0); fLocalizedDigits[6] = symbols.getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0); fLocalizedDigits[7] = symbols.getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0); fLocalizedDigits[8] = symbols.getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0); fLocalizedDigits[9] = symbols.getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0); fIsStandardDigits = isStandardDigits(); fNegativeSign = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); fPositiveSign = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); fInfinity.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), UNUM_INTEGER_FIELD); fNan.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), UNUM_INTEGER_FIELD); fExponent = symbols.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); } void DigitFormatter::setDecimalFormatSymbolsForMonetary( const DecimalFormatSymbols &symbols) { setOtherDecimalFormatSymbols(symbols); fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); } void DigitFormatter::setDecimalFormatSymbols( const DecimalFormatSymbols &symbols) { setOtherDecimalFormatSymbols(symbols); fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); } static void appendField( int32_t fieldId, const UnicodeString &value, FieldPositionHandler &handler, UnicodeString &appendTo) { int32_t currentLength = appendTo.length(); appendTo.append(value); handler.addAttribute( fieldId, currentLength, appendTo.length()); } int32_t DigitFormatter::countChar32( const DigitGrouping &grouping, const DigitInterval &interval, const DigitFormatterOptions &options) const { int32_t result = interval.length(); // We always emit '0' in lieu of no digits. if (result == 0) { result = 1; } if (options.fAlwaysShowDecimal || interval.getLeastSignificantInclusive() < 0) { result += fDecimal.countChar32(); } result += grouping.getSeparatorCount(interval.getIntDigitCount()) * fGroupingSeparator.countChar32(); return result; } int32_t DigitFormatter::countChar32( const VisibleDigits &digits, const DigitGrouping &grouping, const DigitFormatterOptions &options) const { if (digits.isNaN()) { return countChar32ForNaN(); } if (digits.isInfinite()) { return countChar32ForInfinity(); } return countChar32( grouping, digits.getInterval(), options); } int32_t DigitFormatter::countChar32( const VisibleDigitsWithExponent &digits, const SciFormatterOptions &options) const { if (digits.isNaN()) { return countChar32ForNaN(); } if (digits.isInfinite()) { return countChar32ForInfinity(); } const VisibleDigits *exponent = digits.getExponent(); if (exponent == NULL) { DigitGrouping grouping; return countChar32( grouping, digits.getMantissa().getInterval(), options.fMantissa); } return countChar32( *exponent, digits.getMantissa().getInterval(), options); } int32_t DigitFormatter::countChar32( const VisibleDigits &exponent, const DigitInterval &mantissaInterval, const SciFormatterOptions &options) const { DigitGrouping grouping; int32_t count = countChar32( grouping, mantissaInterval, options.fMantissa); count += fExponent.countChar32(); count += countChar32ForExponent( exponent, options.fExponent); return count; } UnicodeString &DigitFormatter::format( const VisibleDigits &digits, const DigitGrouping &grouping, const DigitFormatterOptions &options, FieldPositionHandler &handler, UnicodeString &appendTo) const { if (digits.isNaN()) { return formatNaN(handler, appendTo); } if (digits.isInfinite()) { return formatInfinity(handler, appendTo); } const DigitInterval &interval = digits.getInterval(); int32_t digitsLeftOfDecimal = interval.getMostSignificantExclusive(); int32_t lastDigitPos = interval.getLeastSignificantInclusive(); int32_t intBegin = appendTo.length(); int32_t fracBegin; // Emit "0" instead of empty string. if (digitsLeftOfDecimal == 0 && lastDigitPos == 0) { appendTo.append(fLocalizedDigits[0]); handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length()); if (options.fAlwaysShowDecimal) { appendField( UNUM_DECIMAL_SEPARATOR_FIELD, fDecimal, handler, appendTo); } return appendTo; } { UnicodeStringAppender appender(appendTo); for (int32_t i = interval.getMostSignificantExclusive() - 1; i >= interval.getLeastSignificantInclusive(); --i) { if (i == -1) { appender.flush(); appendField( UNUM_DECIMAL_SEPARATOR_FIELD, fDecimal, handler, appendTo); fracBegin = appendTo.length(); } appender.append(fLocalizedDigits[digits.getDigitByExponent(i)]); if (grouping.isSeparatorAt(digitsLeftOfDecimal, i)) { appender.flush(); appendField( UNUM_GROUPING_SEPARATOR_FIELD, fGroupingSeparator, handler, appendTo); } if (i == 0) { appender.flush(); if (digitsLeftOfDecimal > 0) { handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length()); } } } if (options.fAlwaysShowDecimal && lastDigitPos == 0) { appender.flush(); appendField( UNUM_DECIMAL_SEPARATOR_FIELD, fDecimal, handler, appendTo); } } // lastDigitPos is never > 0 so we are guaranteed that kIntegerField // is already added. if (lastDigitPos < 0) { handler.addAttribute(UNUM_FRACTION_FIELD, fracBegin, appendTo.length()); } return appendTo; } UnicodeString & DigitFormatter::format( const VisibleDigitsWithExponent &digits, const SciFormatterOptions &options, FieldPositionHandler &handler, UnicodeString &appendTo) const { DigitGrouping grouping; format( digits.getMantissa(), grouping, options.fMantissa, handler, appendTo); const VisibleDigits *exponent = digits.getExponent(); if (exponent == NULL) { return appendTo; } int32_t expBegin = appendTo.length(); appendTo.append(fExponent); handler.addAttribute( UNUM_EXPONENT_SYMBOL_FIELD, expBegin, appendTo.length()); return formatExponent( *exponent, options.fExponent, UNUM_EXPONENT_SIGN_FIELD, UNUM_EXPONENT_FIELD, handler, appendTo); } static int32_t formatInt( int32_t value, uint8_t *digits) { int32_t idx = 0; while (value > 0) { digits[idx++] = (uint8_t) (value % 10); value /= 10; } return idx; } UnicodeString & DigitFormatter::formatDigits( const uint8_t *digits, int32_t count, const IntDigitCountRange &range, int32_t intField, FieldPositionHandler &handler, UnicodeString &appendTo) const { int32_t i = range.pin(count) - 1; int32_t begin = appendTo.length(); // Always emit '0' as placeholder for empty string. if (i == -1) { appendTo.append(fLocalizedDigits[0]); handler.addAttribute(intField, begin, appendTo.length()); return appendTo; } { UnicodeStringAppender appender(appendTo); for (; i >= count; --i) { appender.append(fLocalizedDigits[0]); } for (; i >= 0; --i) { appender.append(fLocalizedDigits[digits[i]]); } } handler.addAttribute(intField, begin, appendTo.length()); return appendTo; } UnicodeString & DigitFormatter::formatExponent( const VisibleDigits &digits, const DigitFormatterIntOptions &options, int32_t signField, int32_t intField, FieldPositionHandler &handler, UnicodeString &appendTo) const { UBool neg = digits.isNegative(); if (neg || options.fAlwaysShowSign) { appendField( signField, neg ? fNegativeSign : fPositiveSign, handler, appendTo); } int32_t begin = appendTo.length(); DigitGrouping grouping; DigitFormatterOptions expOptions; FieldPosition fpos(FieldPosition::DONT_CARE); FieldPositionOnlyHandler noHandler(fpos); format( digits, grouping, expOptions, noHandler, appendTo); handler.addAttribute(intField, begin, appendTo.length()); return appendTo; } int32_t DigitFormatter::countChar32ForExponent( const VisibleDigits &exponent, const DigitFormatterIntOptions &options) const { int32_t result = 0; UBool neg = exponent.isNegative(); if (neg || options.fAlwaysShowSign) { result += neg ? fNegativeSign.countChar32() : fPositiveSign.countChar32(); } DigitGrouping grouping; DigitFormatterOptions expOptions; result += countChar32(grouping, exponent.getInterval(), expOptions); return result; } UnicodeString & DigitFormatter::formatPositiveInt32( int32_t positiveValue, const IntDigitCountRange &range, FieldPositionHandler &handler, UnicodeString &appendTo) const { // super fast path if (fIsStandardDigits && SmallIntFormatter::canFormat(positiveValue, range)) { int32_t begin = appendTo.length(); SmallIntFormatter::format(positiveValue, range, appendTo); handler.addAttribute(UNUM_INTEGER_FIELD, begin, appendTo.length()); return appendTo; } uint8_t digits[10]; int32_t count = formatInt(positiveValue, digits); return formatDigits( digits, count, range, UNUM_INTEGER_FIELD, handler, appendTo); } UBool DigitFormatter::isStandardDigits() const { UChar32 cdigit = 0x30; for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) { if (fLocalizedDigits[i] != cdigit) { return FALSE; } ++cdigit; } return TRUE; } UBool DigitFormatter::equals(const DigitFormatter &rhs) const { UBool result = (fGroupingSeparator == rhs.fGroupingSeparator) && (fDecimal == rhs.fDecimal) && (fNegativeSign == rhs.fNegativeSign) && (fPositiveSign == rhs.fPositiveSign) && (fInfinity.equals(rhs.fInfinity)) && (fNan.equals(rhs.fNan)) && (fIsStandardDigits == rhs.fIsStandardDigits) && (fExponent == rhs.fExponent); if (!result) { return FALSE; } for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) { if (fLocalizedDigits[i] != rhs.fLocalizedDigits[i]) { return FALSE; } } return TRUE; } U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */