| /* |
| * Copyright (C) 2015, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| * |
| * file name: decimfmtimpl.cpp |
| */ |
| |
| #include "unicode/utypes.h" |
| |
| #if !UCONFIG_NO_FORMATTING |
| #include "starboard/client_porting/poem/string_poem.h" |
| #if !defined(STARBOARD) |
| #include <math.h> |
| #endif |
| #include "unicode/numfmt.h" |
| #include "unicode/plurrule.h" |
| #include "unicode/ustring.h" |
| #include "decimalformatpattern.h" |
| #include "decimalformatpatternimpl.h" |
| #include "decimfmtimpl.h" |
| #include "fphdlimp.h" |
| #include "plurrule_impl.h" |
| #include "valueformatter.h" |
| #include "visibledigits.h" |
| |
| U_NAMESPACE_BEGIN |
| |
| static const int32_t kMaxScientificIntegerDigits = 8; |
| |
| static const int32_t kFormattingPosPrefix = (1 << 0); |
| static const int32_t kFormattingNegPrefix = (1 << 1); |
| static const int32_t kFormattingPosSuffix = (1 << 2); |
| static const int32_t kFormattingNegSuffix = (1 << 3); |
| static const int32_t kFormattingSymbols = (1 << 4); |
| static const int32_t kFormattingCurrency = (1 << 5); |
| static const int32_t kFormattingUsesCurrency = (1 << 6); |
| static const int32_t kFormattingPluralRules = (1 << 7); |
| static const int32_t kFormattingAffixParser = (1 << 8); |
| static const int32_t kFormattingCurrencyAffixInfo = (1 << 9); |
| static const int32_t kFormattingAll = (1 << 10) - 1; |
| static const int32_t kFormattingAffixes = |
| kFormattingPosPrefix | kFormattingPosSuffix | |
| kFormattingNegPrefix | kFormattingNegSuffix; |
| static const int32_t kFormattingAffixParserWithCurrency = |
| kFormattingAffixParser | kFormattingCurrencyAffixInfo; |
| |
| DecimalFormatImpl::DecimalFormatImpl( |
| NumberFormat *super, |
| const Locale &locale, |
| const UnicodeString &pattern, |
| UErrorCode &status) |
| : fSuper(super), |
| fScale(0), |
| fRoundingMode(DecimalFormat::kRoundHalfEven), |
| fSymbols(NULL), |
| fCurrencyUsage(UCURR_USAGE_STANDARD), |
| fRules(NULL), |
| fMonetary(FALSE) { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| fSymbols = new DecimalFormatSymbols( |
| locale, status); |
| if (fSymbols == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| UParseError parseError; |
| applyPattern(pattern, FALSE, parseError, status); |
| updateAll(status); |
| } |
| |
| DecimalFormatImpl::DecimalFormatImpl( |
| NumberFormat *super, |
| const UnicodeString &pattern, |
| DecimalFormatSymbols *symbolsToAdopt, |
| UParseError &parseError, |
| UErrorCode &status) |
| : fSuper(super), |
| fScale(0), |
| fRoundingMode(DecimalFormat::kRoundHalfEven), |
| fSymbols(symbolsToAdopt), |
| fCurrencyUsage(UCURR_USAGE_STANDARD), |
| fRules(NULL), |
| fMonetary(FALSE) { |
| applyPattern(pattern, FALSE, parseError, status); |
| updateAll(status); |
| } |
| |
| DecimalFormatImpl::DecimalFormatImpl( |
| NumberFormat *super, const DecimalFormatImpl &other, UErrorCode &status) : |
| fSuper(super), |
| fMultiplier(other.fMultiplier), |
| fScale(other.fScale), |
| fRoundingMode(other.fRoundingMode), |
| fMinSigDigits(other.fMinSigDigits), |
| fMaxSigDigits(other.fMaxSigDigits), |
| fUseScientific(other.fUseScientific), |
| fUseSigDigits(other.fUseSigDigits), |
| fGrouping(other.fGrouping), |
| fPositivePrefixPattern(other.fPositivePrefixPattern), |
| fNegativePrefixPattern(other.fNegativePrefixPattern), |
| fPositiveSuffixPattern(other.fPositiveSuffixPattern), |
| fNegativeSuffixPattern(other.fNegativeSuffixPattern), |
| fSymbols(other.fSymbols), |
| fCurrencyUsage(other.fCurrencyUsage), |
| fRules(NULL), |
| fMonetary(other.fMonetary), |
| fAffixParser(other.fAffixParser), |
| fCurrencyAffixInfo(other.fCurrencyAffixInfo), |
| fEffPrecision(other.fEffPrecision), |
| fEffGrouping(other.fEffGrouping), |
| fOptions(other.fOptions), |
| fFormatter(other.fFormatter), |
| fAffixes(other.fAffixes) { |
| fSymbols = new DecimalFormatSymbols(*fSymbols); |
| if (fSymbols == NULL && U_SUCCESS(status)) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| } |
| if (other.fRules != NULL) { |
| fRules = new PluralRules(*other.fRules); |
| if (fRules == NULL && U_SUCCESS(status)) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| } |
| } |
| } |
| |
| |
| DecimalFormatImpl & |
| DecimalFormatImpl::assign(const DecimalFormatImpl &other, UErrorCode &status) { |
| if (U_FAILURE(status) || this == &other) { |
| return (*this); |
| } |
| UObject::operator=(other); |
| fMultiplier = other.fMultiplier; |
| fScale = other.fScale; |
| fRoundingMode = other.fRoundingMode; |
| fMinSigDigits = other.fMinSigDigits; |
| fMaxSigDigits = other.fMaxSigDigits; |
| fUseScientific = other.fUseScientific; |
| fUseSigDigits = other.fUseSigDigits; |
| fGrouping = other.fGrouping; |
| fPositivePrefixPattern = other.fPositivePrefixPattern; |
| fNegativePrefixPattern = other.fNegativePrefixPattern; |
| fPositiveSuffixPattern = other.fPositiveSuffixPattern; |
| fNegativeSuffixPattern = other.fNegativeSuffixPattern; |
| fCurrencyUsage = other.fCurrencyUsage; |
| fMonetary = other.fMonetary; |
| fAffixParser = other.fAffixParser; |
| fCurrencyAffixInfo = other.fCurrencyAffixInfo; |
| fEffPrecision = other.fEffPrecision; |
| fEffGrouping = other.fEffGrouping; |
| fOptions = other.fOptions; |
| fFormatter = other.fFormatter; |
| fAffixes = other.fAffixes; |
| *fSymbols = *other.fSymbols; |
| if (fRules != NULL && other.fRules != NULL) { |
| *fRules = *other.fRules; |
| } else { |
| delete fRules; |
| fRules = other.fRules; |
| if (fRules != NULL) { |
| fRules = new PluralRules(*fRules); |
| if (fRules == NULL) { |
| status = U_MEMORY_ALLOCATION_ERROR; |
| return *this; |
| } |
| } |
| } |
| return *this; |
| } |
| |
| UBool |
| DecimalFormatImpl::operator==(const DecimalFormatImpl &other) const { |
| if (this == &other) { |
| return TRUE; |
| } |
| return (fMultiplier == other.fMultiplier) |
| && (fScale == other.fScale) |
| && (fRoundingMode == other.fRoundingMode) |
| && (fMinSigDigits == other.fMinSigDigits) |
| && (fMaxSigDigits == other.fMaxSigDigits) |
| && (fUseScientific == other.fUseScientific) |
| && (fUseSigDigits == other.fUseSigDigits) |
| && fGrouping.equals(other.fGrouping) |
| && fPositivePrefixPattern.equals(other.fPositivePrefixPattern) |
| && fNegativePrefixPattern.equals(other.fNegativePrefixPattern) |
| && fPositiveSuffixPattern.equals(other.fPositiveSuffixPattern) |
| && fNegativeSuffixPattern.equals(other.fNegativeSuffixPattern) |
| && fCurrencyUsage == other.fCurrencyUsage |
| && fAffixParser.equals(other.fAffixParser) |
| && fCurrencyAffixInfo.equals(other.fCurrencyAffixInfo) |
| && fEffPrecision.equals(other.fEffPrecision) |
| && fEffGrouping.equals(other.fEffGrouping) |
| && fOptions.equals(other.fOptions) |
| && fFormatter.equals(other.fFormatter) |
| && fAffixes.equals(other.fAffixes) |
| && (*fSymbols == *other.fSymbols) |
| && ((fRules == other.fRules) || ( |
| (fRules != NULL) && (other.fRules != NULL) |
| && (*fRules == *other.fRules))) |
| && (fMonetary == other.fMonetary); |
| } |
| |
| DecimalFormatImpl::~DecimalFormatImpl() { |
| delete fSymbols; |
| delete fRules; |
| } |
| |
| ValueFormatter & |
| DecimalFormatImpl::prepareValueFormatter(ValueFormatter &vf) const { |
| if (fUseScientific) { |
| vf.prepareScientificFormatting( |
| fFormatter, fEffPrecision, fOptions); |
| return vf; |
| } |
| vf.prepareFixedDecimalFormatting( |
| fFormatter, fEffGrouping, fEffPrecision.fMantissa, fOptions.fMantissa); |
| return vf; |
| } |
| |
| int32_t |
| DecimalFormatImpl::getPatternScale() const { |
| UBool usesPercent = fPositivePrefixPattern.usesPercent() || |
| fPositiveSuffixPattern.usesPercent() || |
| fNegativePrefixPattern.usesPercent() || |
| fNegativeSuffixPattern.usesPercent(); |
| if (usesPercent) { |
| return 2; |
| } |
| UBool usesPermill = fPositivePrefixPattern.usesPermill() || |
| fPositiveSuffixPattern.usesPermill() || |
| fNegativePrefixPattern.usesPermill() || |
| fNegativeSuffixPattern.usesPermill(); |
| if (usesPermill) { |
| return 3; |
| } |
| return 0; |
| } |
| |
| void |
| DecimalFormatImpl::setMultiplierScale(int32_t scale) { |
| if (scale == 0) { |
| // Needed to preserve equality. fMultiplier == 0 means |
| // multiplier is 1. |
| fMultiplier.set(0); |
| } else { |
| fMultiplier.set(1); |
| fMultiplier.shiftDecimalRight(scale); |
| } |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| int32_t number, |
| UnicodeString &appendTo, |
| FieldPosition &pos, |
| UErrorCode &status) const { |
| FieldPositionOnlyHandler handler(pos); |
| return formatInt32(number, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| int32_t number, |
| UnicodeString &appendTo, |
| FieldPositionIterator *posIter, |
| UErrorCode &status) const { |
| FieldPositionIteratorHandler handler(posIter, status); |
| return formatInt32(number, appendTo, handler, status); |
| } |
| |
| template<class T> |
| UBool DecimalFormatImpl::maybeFormatWithDigitList( |
| T number, |
| UnicodeString &appendTo, |
| FieldPositionHandler &handler, |
| UErrorCode &status) const { |
| if (!fMultiplier.isZero()) { |
| DigitList digits; |
| digits.set(number); |
| digits.mult(fMultiplier, status); |
| digits.shiftDecimalRight(fScale); |
| formatAdjustedDigitList(digits, appendTo, handler, status); |
| return TRUE; |
| } |
| if (fScale != 0) { |
| DigitList digits; |
| digits.set(number); |
| digits.shiftDecimalRight(fScale); |
| formatAdjustedDigitList(digits, appendTo, handler, status); |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| template<class T> |
| UBool DecimalFormatImpl::maybeInitVisibleDigitsFromDigitList( |
| T number, |
| VisibleDigitsWithExponent &visibleDigits, |
| UErrorCode &status) const { |
| if (!fMultiplier.isZero()) { |
| DigitList digits; |
| digits.set(number); |
| digits.mult(fMultiplier, status); |
| digits.shiftDecimalRight(fScale); |
| initVisibleDigitsFromAdjusted(digits, visibleDigits, status); |
| return TRUE; |
| } |
| if (fScale != 0) { |
| DigitList digits; |
| digits.set(number); |
| digits.shiftDecimalRight(fScale); |
| initVisibleDigitsFromAdjusted(digits, visibleDigits, status); |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::formatInt32( |
| int32_t number, |
| UnicodeString &appendTo, |
| FieldPositionHandler &handler, |
| UErrorCode &status) const { |
| if (maybeFormatWithDigitList(number, appendTo, handler, status)) { |
| return appendTo; |
| } |
| ValueFormatter vf; |
| return fAffixes.formatInt32( |
| number, |
| prepareValueFormatter(vf), |
| handler, |
| fRules, |
| appendTo, |
| status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::formatInt64( |
| int64_t number, |
| UnicodeString &appendTo, |
| FieldPositionHandler &handler, |
| UErrorCode &status) const { |
| if (number >= INT32_MIN && number <= INT32_MAX) { |
| return formatInt32((int32_t) number, appendTo, handler, status); |
| } |
| VisibleDigitsWithExponent digits; |
| initVisibleDigitsWithExponent(number, digits, status); |
| return formatVisibleDigitsWithExponent( |
| digits, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::formatDouble( |
| double number, |
| UnicodeString &appendTo, |
| FieldPositionHandler &handler, |
| UErrorCode &status) const { |
| VisibleDigitsWithExponent digits; |
| initVisibleDigitsWithExponent(number, digits, status); |
| return formatVisibleDigitsWithExponent( |
| digits, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| double number, |
| UnicodeString &appendTo, |
| FieldPosition &pos, |
| UErrorCode &status) const { |
| FieldPositionOnlyHandler handler(pos); |
| return formatDouble(number, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| const DigitList &number, |
| UnicodeString &appendTo, |
| FieldPosition &pos, |
| UErrorCode &status) const { |
| DigitList dl(number); |
| FieldPositionOnlyHandler handler(pos); |
| return formatDigitList(dl, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| int64_t number, |
| UnicodeString &appendTo, |
| FieldPosition &pos, |
| UErrorCode &status) const { |
| FieldPositionOnlyHandler handler(pos); |
| return formatInt64(number, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| int64_t number, |
| UnicodeString &appendTo, |
| FieldPositionIterator *posIter, |
| UErrorCode &status) const { |
| FieldPositionIteratorHandler handler(posIter, status); |
| return formatInt64(number, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| double number, |
| UnicodeString &appendTo, |
| FieldPositionIterator *posIter, |
| UErrorCode &status) const { |
| FieldPositionIteratorHandler handler(posIter, status); |
| return formatDouble(number, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| const DigitList &number, |
| UnicodeString &appendTo, |
| FieldPositionIterator *posIter, |
| UErrorCode &status) const { |
| DigitList dl(number); |
| FieldPositionIteratorHandler handler(posIter, status); |
| return formatDigitList(dl, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| const StringPiece &number, |
| UnicodeString &appendTo, |
| FieldPositionIterator *posIter, |
| UErrorCode &status) const { |
| DigitList dl; |
| dl.set(number, status); |
| FieldPositionIteratorHandler handler(posIter, status); |
| return formatDigitList(dl, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| const VisibleDigitsWithExponent &digits, |
| UnicodeString &appendTo, |
| FieldPosition &pos, |
| UErrorCode &status) const { |
| FieldPositionOnlyHandler handler(pos); |
| return formatVisibleDigitsWithExponent( |
| digits, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::format( |
| const VisibleDigitsWithExponent &digits, |
| UnicodeString &appendTo, |
| FieldPositionIterator *posIter, |
| UErrorCode &status) const { |
| FieldPositionIteratorHandler handler(posIter, status); |
| return formatVisibleDigitsWithExponent( |
| digits, appendTo, handler, status); |
| } |
| |
| DigitList & |
| DecimalFormatImpl::adjustDigitList( |
| DigitList &number, UErrorCode &status) const { |
| number.setRoundingMode(fRoundingMode); |
| if (!fMultiplier.isZero()) { |
| number.mult(fMultiplier, status); |
| } |
| if (fScale != 0) { |
| number.shiftDecimalRight(fScale); |
| } |
| number.reduce(); |
| return number; |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::formatDigitList( |
| DigitList &number, |
| UnicodeString &appendTo, |
| FieldPositionHandler &handler, |
| UErrorCode &status) const { |
| VisibleDigitsWithExponent digits; |
| initVisibleDigitsWithExponent(number, digits, status); |
| return formatVisibleDigitsWithExponent( |
| digits, appendTo, handler, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::formatAdjustedDigitList( |
| DigitList &number, |
| UnicodeString &appendTo, |
| FieldPositionHandler &handler, |
| UErrorCode &status) const { |
| ValueFormatter vf; |
| return fAffixes.format( |
| number, |
| prepareValueFormatter(vf), |
| handler, |
| fRules, |
| appendTo, |
| status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::formatVisibleDigitsWithExponent( |
| const VisibleDigitsWithExponent &digits, |
| UnicodeString &appendTo, |
| FieldPositionHandler &handler, |
| UErrorCode &status) const { |
| ValueFormatter vf; |
| return fAffixes.format( |
| digits, |
| prepareValueFormatter(vf), |
| handler, |
| fRules, |
| appendTo, |
| status); |
| } |
| |
| static FixedDecimal &initFixedDecimal( |
| const VisibleDigits &digits, FixedDecimal &result) { |
| result.source = 0.0; |
| result.isNegative = digits.isNegative(); |
| result.isNanOrInfinity = digits.isNaNOrInfinity(); |
| digits.getFixedDecimal( |
| result.source, result.intValue, result.decimalDigits, |
| result.decimalDigitsWithoutTrailingZeros, |
| result.visibleDecimalDigitCount, result.hasIntegerValue); |
| return result; |
| } |
| |
| FixedDecimal & |
| DecimalFormatImpl::getFixedDecimal(double number, FixedDecimal &result, UErrorCode &status) const { |
| if (U_FAILURE(status)) { |
| return result; |
| } |
| VisibleDigits digits; |
| fEffPrecision.fMantissa.initVisibleDigits(number, digits, status); |
| return initFixedDecimal(digits, result); |
| } |
| |
| FixedDecimal & |
| DecimalFormatImpl::getFixedDecimal( |
| DigitList &number, FixedDecimal &result, UErrorCode &status) const { |
| if (U_FAILURE(status)) { |
| return result; |
| } |
| VisibleDigits digits; |
| fEffPrecision.fMantissa.initVisibleDigits(number, digits, status); |
| return initFixedDecimal(digits, result); |
| } |
| |
| VisibleDigitsWithExponent & |
| DecimalFormatImpl::initVisibleDigitsWithExponent( |
| int64_t number, |
| VisibleDigitsWithExponent &digits, |
| UErrorCode &status) const { |
| if (maybeInitVisibleDigitsFromDigitList( |
| number, digits, status)) { |
| return digits; |
| } |
| if (fUseScientific) { |
| fEffPrecision.initVisibleDigitsWithExponent( |
| number, digits, status); |
| } else { |
| fEffPrecision.fMantissa.initVisibleDigitsWithExponent( |
| number, digits, status); |
| } |
| return digits; |
| } |
| |
| VisibleDigitsWithExponent & |
| DecimalFormatImpl::initVisibleDigitsWithExponent( |
| double number, |
| VisibleDigitsWithExponent &digits, |
| UErrorCode &status) const { |
| if (maybeInitVisibleDigitsFromDigitList( |
| number, digits, status)) { |
| return digits; |
| } |
| if (fUseScientific) { |
| fEffPrecision.initVisibleDigitsWithExponent( |
| number, digits, status); |
| } else { |
| fEffPrecision.fMantissa.initVisibleDigitsWithExponent( |
| number, digits, status); |
| } |
| return digits; |
| } |
| |
| VisibleDigitsWithExponent & |
| DecimalFormatImpl::initVisibleDigitsWithExponent( |
| DigitList &number, |
| VisibleDigitsWithExponent &digits, |
| UErrorCode &status) const { |
| adjustDigitList(number, status); |
| return initVisibleDigitsFromAdjusted(number, digits, status); |
| } |
| |
| VisibleDigitsWithExponent & |
| DecimalFormatImpl::initVisibleDigitsFromAdjusted( |
| DigitList &number, |
| VisibleDigitsWithExponent &digits, |
| UErrorCode &status) const { |
| if (fUseScientific) { |
| fEffPrecision.initVisibleDigitsWithExponent( |
| number, digits, status); |
| } else { |
| fEffPrecision.fMantissa.initVisibleDigitsWithExponent( |
| number, digits, status); |
| } |
| return digits; |
| } |
| |
| DigitList & |
| DecimalFormatImpl::round( |
| DigitList &number, UErrorCode &status) const { |
| if (number.isNaN() || number.isInfinite()) { |
| return number; |
| } |
| adjustDigitList(number, status); |
| ValueFormatter vf; |
| prepareValueFormatter(vf); |
| return vf.round(number, status); |
| } |
| |
| void |
| DecimalFormatImpl::setMinimumSignificantDigits(int32_t newValue) { |
| fMinSigDigits = newValue; |
| fUseSigDigits = TRUE; // ticket 9936 |
| updatePrecision(); |
| } |
| |
| void |
| DecimalFormatImpl::setMaximumSignificantDigits(int32_t newValue) { |
| fMaxSigDigits = newValue; |
| fUseSigDigits = TRUE; // ticket 9936 |
| updatePrecision(); |
| } |
| |
| void |
| DecimalFormatImpl::setMinMaxSignificantDigits(int32_t min, int32_t max) { |
| fMinSigDigits = min; |
| fMaxSigDigits = max; |
| fUseSigDigits = TRUE; // ticket 9936 |
| updatePrecision(); |
| } |
| |
| void |
| DecimalFormatImpl::setScientificNotation(UBool newValue) { |
| fUseScientific = newValue; |
| updatePrecision(); |
| } |
| |
| void |
| DecimalFormatImpl::setSignificantDigitsUsed(UBool newValue) { |
| fUseSigDigits = newValue; |
| updatePrecision(); |
| } |
| |
| void |
| DecimalFormatImpl::setGroupingSize(int32_t newValue) { |
| fGrouping.fGrouping = newValue; |
| updateGrouping(); |
| } |
| |
| void |
| DecimalFormatImpl::setSecondaryGroupingSize(int32_t newValue) { |
| fGrouping.fGrouping2 = newValue; |
| updateGrouping(); |
| } |
| |
| void |
| DecimalFormatImpl::setMinimumGroupingDigits(int32_t newValue) { |
| fGrouping.fMinGrouping = newValue; |
| updateGrouping(); |
| } |
| |
| void |
| DecimalFormatImpl::setCurrencyUsage( |
| UCurrencyUsage currencyUsage, UErrorCode &status) { |
| fCurrencyUsage = currencyUsage; |
| updateFormatting(kFormattingCurrency, status); |
| } |
| |
| void |
| DecimalFormatImpl::setRoundingIncrement(double d) { |
| if (d > 0.0) { |
| fEffPrecision.fMantissa.fRoundingIncrement.set(d); |
| } else { |
| fEffPrecision.fMantissa.fRoundingIncrement.set(0.0); |
| } |
| } |
| |
| double |
| DecimalFormatImpl::getRoundingIncrement() const { |
| return fEffPrecision.fMantissa.fRoundingIncrement.getDouble(); |
| } |
| |
| int32_t |
| DecimalFormatImpl::getMultiplier() const { |
| if (fMultiplier.isZero()) { |
| return 1; |
| } |
| return (int32_t) fMultiplier.getDouble(); |
| } |
| |
| void |
| DecimalFormatImpl::setMultiplier(int32_t m) { |
| if (m == 0 || m == 1) { |
| fMultiplier.set(0); |
| } else { |
| fMultiplier.set(m); |
| } |
| } |
| |
| void |
| DecimalFormatImpl::setPositivePrefix(const UnicodeString &str) { |
| fPositivePrefixPattern.remove(); |
| fPositivePrefixPattern.addLiteral(str.getBuffer(), 0, str.length()); |
| UErrorCode status = U_ZERO_ERROR; |
| updateFormatting(kFormattingPosPrefix, status); |
| } |
| |
| void |
| DecimalFormatImpl::setPositiveSuffix(const UnicodeString &str) { |
| fPositiveSuffixPattern.remove(); |
| fPositiveSuffixPattern.addLiteral(str.getBuffer(), 0, str.length()); |
| UErrorCode status = U_ZERO_ERROR; |
| updateFormatting(kFormattingPosSuffix, status); |
| } |
| |
| void |
| DecimalFormatImpl::setNegativePrefix(const UnicodeString &str) { |
| fNegativePrefixPattern.remove(); |
| fNegativePrefixPattern.addLiteral(str.getBuffer(), 0, str.length()); |
| UErrorCode status = U_ZERO_ERROR; |
| updateFormatting(kFormattingNegPrefix, status); |
| } |
| |
| void |
| DecimalFormatImpl::setNegativeSuffix(const UnicodeString &str) { |
| fNegativeSuffixPattern.remove(); |
| fNegativeSuffixPattern.addLiteral(str.getBuffer(), 0, str.length()); |
| UErrorCode status = U_ZERO_ERROR; |
| updateFormatting(kFormattingNegSuffix, status); |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::getPositivePrefix(UnicodeString &result) const { |
| result = fAffixes.fPositivePrefix.getOtherVariant().toString(); |
| return result; |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::getPositiveSuffix(UnicodeString &result) const { |
| result = fAffixes.fPositiveSuffix.getOtherVariant().toString(); |
| return result; |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::getNegativePrefix(UnicodeString &result) const { |
| result = fAffixes.fNegativePrefix.getOtherVariant().toString(); |
| return result; |
| } |
| |
| UnicodeString & |
| DecimalFormatImpl::getNegativeSuffix(UnicodeString &result) const { |
| result = fAffixes.fNegativeSuffix.getOtherVariant().toString(); |
| return result; |
| } |
| |
| void |
| DecimalFormatImpl::adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt) { |
| if (symbolsToAdopt == NULL) { |
| return; |
| } |
| delete fSymbols; |
| fSymbols = symbolsToAdopt; |
| UErrorCode status = U_ZERO_ERROR; |
| updateFormatting(kFormattingSymbols, status); |
| } |
| |
| void |
| DecimalFormatImpl::applyPatternFavorCurrencyPrecision( |
| const UnicodeString &pattern, UErrorCode &status) { |
| UParseError perror; |
| applyPattern(pattern, FALSE, perror, status); |
| updateForApplyPatternFavorCurrencyPrecision(status); |
| } |
| |
| void |
| DecimalFormatImpl::applyPattern( |
| const UnicodeString &pattern, UErrorCode &status) { |
| UParseError perror; |
| applyPattern(pattern, FALSE, perror, status); |
| updateForApplyPattern(status); |
| } |
| |
| void |
| DecimalFormatImpl::applyPattern( |
| const UnicodeString &pattern, |
| UParseError &perror, UErrorCode &status) { |
| applyPattern(pattern, FALSE, perror, status); |
| updateForApplyPattern(status); |
| } |
| |
| void |
| DecimalFormatImpl::applyLocalizedPattern( |
| const UnicodeString &pattern, UErrorCode &status) { |
| UParseError perror; |
| applyPattern(pattern, TRUE, perror, status); |
| updateForApplyPattern(status); |
| } |
| |
| void |
| DecimalFormatImpl::applyLocalizedPattern( |
| const UnicodeString &pattern, |
| UParseError &perror, UErrorCode &status) { |
| applyPattern(pattern, TRUE, perror, status); |
| updateForApplyPattern(status); |
| } |
| |
| void |
| DecimalFormatImpl::applyPattern( |
| const UnicodeString &pattern, |
| UBool localized, UParseError &perror, UErrorCode &status) { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| DecimalFormatPatternParser patternParser; |
| if (localized) { |
| patternParser.useSymbols(*fSymbols); |
| } |
| DecimalFormatPattern out; |
| patternParser.applyPatternWithoutExpandAffix( |
| pattern, out, perror, status); |
| if (U_FAILURE(status)) { |
| return; |
| } |
| fUseScientific = out.fUseExponentialNotation; |
| fUseSigDigits = out.fUseSignificantDigits; |
| fSuper->NumberFormat::setMinimumIntegerDigits(out.fMinimumIntegerDigits); |
| fSuper->NumberFormat::setMaximumIntegerDigits(out.fMaximumIntegerDigits); |
| fSuper->NumberFormat::setMinimumFractionDigits(out.fMinimumFractionDigits); |
| fSuper->NumberFormat::setMaximumFractionDigits(out.fMaximumFractionDigits); |
| fMinSigDigits = out.fMinimumSignificantDigits; |
| fMaxSigDigits = out.fMaximumSignificantDigits; |
| fEffPrecision.fMinExponentDigits = out.fMinExponentDigits; |
| fOptions.fExponent.fAlwaysShowSign = out.fExponentSignAlwaysShown; |
| fSuper->NumberFormat::setGroupingUsed(out.fGroupingUsed); |
| fGrouping.fGrouping = out.fGroupingSize; |
| fGrouping.fGrouping2 = out.fGroupingSize2; |
| fOptions.fMantissa.fAlwaysShowDecimal = out.fDecimalSeparatorAlwaysShown; |
| if (out.fRoundingIncrementUsed) { |
| fEffPrecision.fMantissa.fRoundingIncrement = out.fRoundingIncrement; |
| } else { |
| fEffPrecision.fMantissa.fRoundingIncrement.clear(); |
| } |
| fAffixes.fPadChar = out.fPad; |
| fNegativePrefixPattern = out.fNegPrefixAffix; |
| fNegativeSuffixPattern = out.fNegSuffixAffix; |
| fPositivePrefixPattern = out.fPosPrefixAffix; |
| fPositiveSuffixPattern = out.fPosSuffixAffix; |
| |
| // Work around. Pattern parsing code and DecimalFormat code don't agree |
| // on the definition of field width, so we have to translate from |
| // pattern field width to decimal format field width here. |
| fAffixes.fWidth = out.fFormatWidth == 0 ? 0 : |
| out.fFormatWidth + fPositivePrefixPattern.countChar32() |
| + fPositiveSuffixPattern.countChar32(); |
| switch (out.fPadPosition) { |
| case DecimalFormatPattern::kPadBeforePrefix: |
| fAffixes.fPadPosition = DigitAffixesAndPadding::kPadBeforePrefix; |
| break; |
| case DecimalFormatPattern::kPadAfterPrefix: |
| fAffixes.fPadPosition = DigitAffixesAndPadding::kPadAfterPrefix; |
| break; |
| case DecimalFormatPattern::kPadBeforeSuffix: |
| fAffixes.fPadPosition = DigitAffixesAndPadding::kPadBeforeSuffix; |
| break; |
| case DecimalFormatPattern::kPadAfterSuffix: |
| fAffixes.fPadPosition = DigitAffixesAndPadding::kPadAfterSuffix; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void |
| DecimalFormatImpl::updatePrecision() { |
| if (fUseScientific) { |
| updatePrecisionForScientific(); |
| } else { |
| updatePrecisionForFixed(); |
| } |
| } |
| |
| static void updatePrecisionForScientificMinMax( |
| const DigitInterval &min, |
| const DigitInterval &max, |
| DigitInterval &resultMin, |
| DigitInterval &resultMax, |
| SignificantDigitInterval &resultSignificant) { |
| resultMin.setIntDigitCount(0); |
| resultMin.setFracDigitCount(0); |
| resultSignificant.clear(); |
| resultMax.clear(); |
| |
| int32_t maxIntDigitCount = max.getIntDigitCount(); |
| int32_t minIntDigitCount = min.getIntDigitCount(); |
| int32_t maxFracDigitCount = max.getFracDigitCount(); |
| int32_t minFracDigitCount = min.getFracDigitCount(); |
| |
| |
| // Not in spec: maxIntDigitCount > 8 assume |
| // maxIntDigitCount = minIntDigitCount. Current DecimalFormat API has |
| // no provision for unsetting maxIntDigitCount which would be useful for |
| // scientific notation. The best we can do is assume that if |
| // maxIntDigitCount is the default of 2000000000 or is "big enough" then |
| // user did not intend to explicitly set it. The 8 was derived emperically |
| // by extensive testing of legacy code. |
| if (maxIntDigitCount > 8) { |
| maxIntDigitCount = minIntDigitCount; |
| } |
| |
| // Per the spec, exponent grouping happens if maxIntDigitCount is more |
| // than 1 and more than minIntDigitCount. |
| UBool bExponentGrouping = maxIntDigitCount > 1 && minIntDigitCount < maxIntDigitCount; |
| if (bExponentGrouping) { |
| resultMax.setIntDigitCount(maxIntDigitCount); |
| |
| // For exponent grouping minIntDigits is always treated as 1 even |
| // if it wasn't set to 1! |
| resultMin.setIntDigitCount(1); |
| } else { |
| // Fixed digit count left of decimal. minIntDigitCount doesn't have |
| // to equal maxIntDigitCount i.e minIntDigitCount == 0 while |
| // maxIntDigitCount == 1. |
| int32_t fixedIntDigitCount = maxIntDigitCount; |
| |
| // If fixedIntDigitCount is 0 but |
| // min or max fraction count is 0 too then use 1. This way we can get |
| // unlimited precision for X.XXXEX |
| if (fixedIntDigitCount == 0 && (minFracDigitCount == 0 || maxFracDigitCount == 0)) { |
| fixedIntDigitCount = 1; |
| } |
| resultMax.setIntDigitCount(fixedIntDigitCount); |
| resultMin.setIntDigitCount(fixedIntDigitCount); |
| } |
| // Spec says this is how we compute significant digits. 0 means |
| // unlimited significant digits. |
| int32_t maxSigDigits = minIntDigitCount + maxFracDigitCount; |
| if (maxSigDigits > 0) { |
| int32_t minSigDigits = minIntDigitCount + minFracDigitCount; |
| resultSignificant.setMin(minSigDigits); |
| resultSignificant.setMax(maxSigDigits); |
| } |
| } |
| |
| void |
| DecimalFormatImpl::updatePrecisionForScientific() { |
| FixedPrecision *result = &fEffPrecision.fMantissa; |
| if (fUseSigDigits) { |
| result->fMax.setFracDigitCount(-1); |
| result->fMax.setIntDigitCount(1); |
| result->fMin.setFracDigitCount(0); |
| result->fMin.setIntDigitCount(1); |
| result->fSignificant.clear(); |
| extractSigDigits(result->fSignificant); |
| return; |
| } |
| DigitInterval max; |
| DigitInterval min; |
| extractMinMaxDigits(min, max); |
| updatePrecisionForScientificMinMax( |
| min, max, |
| result->fMin, result->fMax, result->fSignificant); |
| } |
| |
| void |
| DecimalFormatImpl::updatePrecisionForFixed() { |
| FixedPrecision *result = &fEffPrecision.fMantissa; |
| if (!fUseSigDigits) { |
| extractMinMaxDigits(result->fMin, result->fMax); |
| result->fSignificant.clear(); |
| } else { |
| extractSigDigits(result->fSignificant); |
| result->fMin.setIntDigitCount(1); |
| result->fMin.setFracDigitCount(0); |
| result->fMax.clear(); |
| } |
| } |
| |
| void |
| DecimalFormatImpl::extractMinMaxDigits( |
| DigitInterval &min, DigitInterval &max) const { |
| min.setIntDigitCount(fSuper->getMinimumIntegerDigits()); |
| max.setIntDigitCount(fSuper->getMaximumIntegerDigits()); |
| min.setFracDigitCount(fSuper->getMinimumFractionDigits()); |
| max.setFracDigitCount(fSuper->getMaximumFractionDigits()); |
| } |
| |
| void |
| DecimalFormatImpl::extractSigDigits( |
| SignificantDigitInterval &sig) const { |
| sig.setMin(fMinSigDigits < 0 ? 0 : fMinSigDigits); |
| sig.setMax(fMaxSigDigits < 0 ? 0 : fMaxSigDigits); |
| } |
| |
| void |
| DecimalFormatImpl::updateGrouping() { |
| if (fSuper->isGroupingUsed()) { |
| fEffGrouping = fGrouping; |
| } else { |
| fEffGrouping.clear(); |
| } |
| } |
| |
| void |
| DecimalFormatImpl::updateCurrency(UErrorCode &status) { |
| updateFormatting(kFormattingCurrency, TRUE, status); |
| } |
| |
| void |
| DecimalFormatImpl::updateFormatting( |
| int32_t changedFormattingFields, |
| UErrorCode &status) { |
| updateFormatting(changedFormattingFields, TRUE, status); |
| } |
| |
| void |
| DecimalFormatImpl::updateFormatting( |
| int32_t changedFormattingFields, |
| UBool updatePrecisionBasedOnCurrency, |
| UErrorCode &status) { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| // Each function updates one field. Order matters. For instance, |
| // updatePluralRules comes before updateCurrencyAffixInfo because the |
| // fRules field is needed to update the fCurrencyAffixInfo field. |
| updateFormattingUsesCurrency(changedFormattingFields); |
| updateFormattingFixedPointFormatter(changedFormattingFields); |
| updateFormattingAffixParser(changedFormattingFields); |
| updateFormattingPluralRules(changedFormattingFields, status); |
| updateFormattingCurrencyAffixInfo( |
| changedFormattingFields, |
| updatePrecisionBasedOnCurrency, |
| status); |
| updateFormattingLocalizedPositivePrefix( |
| changedFormattingFields, status); |
| updateFormattingLocalizedPositiveSuffix( |
| changedFormattingFields, status); |
| updateFormattingLocalizedNegativePrefix( |
| changedFormattingFields, status); |
| updateFormattingLocalizedNegativeSuffix( |
| changedFormattingFields, status); |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingUsesCurrency( |
| int32_t &changedFormattingFields) { |
| if ((changedFormattingFields & kFormattingAffixes) == 0) { |
| // If no affixes changed, don't need to do any work |
| return; |
| } |
| UBool newUsesCurrency = |
| fPositivePrefixPattern.usesCurrency() || |
| fPositiveSuffixPattern.usesCurrency() || |
| fNegativePrefixPattern.usesCurrency() || |
| fNegativeSuffixPattern.usesCurrency(); |
| if (fMonetary != newUsesCurrency) { |
| fMonetary = newUsesCurrency; |
| changedFormattingFields |= kFormattingUsesCurrency; |
| } |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingPluralRules( |
| int32_t &changedFormattingFields, UErrorCode &status) { |
| if ((changedFormattingFields & (kFormattingSymbols | kFormattingUsesCurrency)) == 0) { |
| // No work to do if both fSymbols and fMonetary |
| // fields are unchanged |
| return; |
| } |
| if (U_FAILURE(status)) { |
| return; |
| } |
| PluralRules *newRules = NULL; |
| if (fMonetary) { |
| newRules = PluralRules::forLocale(fSymbols->getLocale(), status); |
| if (U_FAILURE(status)) { |
| return; |
| } |
| } |
| // Its ok to say a field has changed when it really hasn't but not |
| // the other way around. Here we assume the field changed unless it |
| // was NULL before and is still NULL now |
| if (fRules != newRules) { |
| delete fRules; |
| fRules = newRules; |
| changedFormattingFields |= kFormattingPluralRules; |
| } |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingCurrencyAffixInfo( |
| int32_t &changedFormattingFields, |
| UBool updatePrecisionBasedOnCurrency, |
| UErrorCode &status) { |
| if ((changedFormattingFields & ( |
| kFormattingSymbols | kFormattingCurrency | |
| kFormattingUsesCurrency | kFormattingPluralRules)) == 0) { |
| // If all these fields are unchanged, no work to do. |
| return; |
| } |
| if (U_FAILURE(status)) { |
| return; |
| } |
| if (!fMonetary) { |
| if (fCurrencyAffixInfo.isDefault()) { |
| // In this case don't have to do any work |
| return; |
| } |
| fCurrencyAffixInfo.set(NULL, NULL, NULL, status); |
| if (U_FAILURE(status)) { |
| return; |
| } |
| changedFormattingFields |= kFormattingCurrencyAffixInfo; |
| } else { |
| const UChar *currency = fSuper->getCurrency(); |
| UChar localeCurr[4]; |
| if (currency[0] == 0) { |
| ucurr_forLocale(fSymbols->getLocale().getName(), localeCurr, UPRV_LENGTHOF(localeCurr), &status); |
| if (U_SUCCESS(status)) { |
| currency = localeCurr; |
| fSuper->NumberFormat::setCurrency(currency, status); |
| } else { |
| currency = NULL; |
| status = U_ZERO_ERROR; |
| } |
| } |
| fCurrencyAffixInfo.set( |
| fSymbols->getLocale().getName(), fRules, currency, status); |
| if (U_FAILURE(status)) { |
| return; |
| } |
| UBool customCurrencySymbol = FALSE; |
| // If DecimalFormatSymbols has custom currency symbol, prefer |
| // that over what we just read from the resource bundles |
| if (fSymbols->isCustomCurrencySymbol()) { |
| fCurrencyAffixInfo.setSymbol( |
| fSymbols->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol)); |
| customCurrencySymbol = TRUE; |
| } |
| if (fSymbols->isCustomIntlCurrencySymbol()) { |
| fCurrencyAffixInfo.setISO( |
| fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol)); |
| customCurrencySymbol = TRUE; |
| } |
| changedFormattingFields |= kFormattingCurrencyAffixInfo; |
| if (currency && !customCurrencySymbol && updatePrecisionBasedOnCurrency) { |
| FixedPrecision precision; |
| CurrencyAffixInfo::adjustPrecision( |
| currency, fCurrencyUsage, precision, status); |
| if (U_FAILURE(status)) { |
| return; |
| } |
| fSuper->NumberFormat::setMinimumFractionDigits( |
| precision.fMin.getFracDigitCount()); |
| fSuper->NumberFormat::setMaximumFractionDigits( |
| precision.fMax.getFracDigitCount()); |
| updatePrecision(); |
| fEffPrecision.fMantissa.fRoundingIncrement = |
| precision.fRoundingIncrement; |
| } |
| |
| } |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingFixedPointFormatter( |
| int32_t &changedFormattingFields) { |
| if ((changedFormattingFields & (kFormattingSymbols | kFormattingUsesCurrency)) == 0) { |
| // No work to do if fSymbols is unchanged |
| return; |
| } |
| if (fMonetary) { |
| fFormatter.setDecimalFormatSymbolsForMonetary(*fSymbols); |
| } else { |
| fFormatter.setDecimalFormatSymbols(*fSymbols); |
| } |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingAffixParser( |
| int32_t &changedFormattingFields) { |
| if ((changedFormattingFields & kFormattingSymbols) == 0) { |
| // No work to do if fSymbols is unchanged |
| return; |
| } |
| fAffixParser.setDecimalFormatSymbols(*fSymbols); |
| changedFormattingFields |= kFormattingAffixParser; |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingLocalizedPositivePrefix( |
| int32_t &changedFormattingFields, UErrorCode &status) { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| if ((changedFormattingFields & ( |
| kFormattingPosPrefix | kFormattingAffixParserWithCurrency)) == 0) { |
| // No work to do |
| return; |
| } |
| fAffixes.fPositivePrefix.remove(); |
| fAffixParser.parse( |
| fPositivePrefixPattern, |
| fCurrencyAffixInfo, |
| fAffixes.fPositivePrefix, |
| status); |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingLocalizedPositiveSuffix( |
| int32_t &changedFormattingFields, UErrorCode &status) { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| if ((changedFormattingFields & ( |
| kFormattingPosSuffix | kFormattingAffixParserWithCurrency)) == 0) { |
| // No work to do |
| return; |
| } |
| fAffixes.fPositiveSuffix.remove(); |
| fAffixParser.parse( |
| fPositiveSuffixPattern, |
| fCurrencyAffixInfo, |
| fAffixes.fPositiveSuffix, |
| status); |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingLocalizedNegativePrefix( |
| int32_t &changedFormattingFields, UErrorCode &status) { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| if ((changedFormattingFields & ( |
| kFormattingNegPrefix | kFormattingAffixParserWithCurrency)) == 0) { |
| // No work to do |
| return; |
| } |
| fAffixes.fNegativePrefix.remove(); |
| fAffixParser.parse( |
| fNegativePrefixPattern, |
| fCurrencyAffixInfo, |
| fAffixes.fNegativePrefix, |
| status); |
| } |
| |
| void |
| DecimalFormatImpl::updateFormattingLocalizedNegativeSuffix( |
| int32_t &changedFormattingFields, UErrorCode &status) { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| if ((changedFormattingFields & ( |
| kFormattingNegSuffix | kFormattingAffixParserWithCurrency)) == 0) { |
| // No work to do |
| return; |
| } |
| fAffixes.fNegativeSuffix.remove(); |
| fAffixParser.parse( |
| fNegativeSuffixPattern, |
| fCurrencyAffixInfo, |
| fAffixes.fNegativeSuffix, |
| status); |
| } |
| |
| void |
| DecimalFormatImpl::updateForApplyPatternFavorCurrencyPrecision( |
| UErrorCode &status) { |
| updateAll(kFormattingAll & ~kFormattingSymbols, TRUE, status); |
| } |
| |
| void |
| DecimalFormatImpl::updateForApplyPattern(UErrorCode &status) { |
| updateAll(kFormattingAll & ~kFormattingSymbols, FALSE, status); |
| } |
| |
| void |
| DecimalFormatImpl::updateAll(UErrorCode &status) { |
| updateAll(kFormattingAll, TRUE, status); |
| } |
| |
| void |
| DecimalFormatImpl::updateAll( |
| int32_t formattingFlags, |
| UBool updatePrecisionBasedOnCurrency, |
| UErrorCode &status) { |
| if (U_FAILURE(status)) { |
| return; |
| } |
| updatePrecision(); |
| updateGrouping(); |
| updateFormatting( |
| formattingFlags, updatePrecisionBasedOnCurrency, status); |
| setMultiplierScale(getPatternScale()); |
| } |
| |
| |
| static int32_t |
| getMinimumLengthToDescribeGrouping(const DigitGrouping &grouping) { |
| if (grouping.fGrouping <= 0) { |
| return 0; |
| } |
| if (grouping.fGrouping2 <= 0) { |
| return grouping.fGrouping + 1; |
| } |
| return grouping.fGrouping + grouping.fGrouping2 + 1; |
| } |
| |
| /** |
| * Given a grouping policy, calculates how many digits are needed left of |
| * the decimal point to achieve a desired length left of the |
| * decimal point. |
| * @param grouping the grouping policy |
| * @param desiredLength number of characters needed left of decimal point |
| * @param minLeftDigits at least this many digits is returned |
| * @param leftDigits the number of digits needed stored here |
| * which is >= minLeftDigits. |
| * @return true if a perfect fit or false if having leftDigits would exceed |
| * desiredLength |
| */ |
| static UBool |
| getLeftDigitsForLeftLength( |
| const DigitGrouping &grouping, |
| int32_t desiredLength, |
| int32_t minLeftDigits, |
| int32_t &leftDigits) { |
| leftDigits = minLeftDigits; |
| int32_t lengthSoFar = leftDigits + grouping.getSeparatorCount(leftDigits); |
| while (lengthSoFar < desiredLength) { |
| lengthSoFar += grouping.isSeparatorAt(leftDigits + 1, leftDigits) ? 2 : 1; |
| ++leftDigits; |
| } |
| return (lengthSoFar == desiredLength); |
| } |
| |
| int32_t |
| DecimalFormatImpl::computeExponentPatternLength() const { |
| if (fUseScientific) { |
| return 1 + (fOptions.fExponent.fAlwaysShowSign ? 1 : 0) + fEffPrecision.fMinExponentDigits; |
| } |
| return 0; |
| } |
| |
| int32_t |
| DecimalFormatImpl::countFractionDigitAndDecimalPatternLength( |
| int32_t fracDigitCount) const { |
| if (!fOptions.fMantissa.fAlwaysShowDecimal && fracDigitCount == 0) { |
| return 0; |
| } |
| return fracDigitCount + 1; |
| } |
| |
| UnicodeString& |
| DecimalFormatImpl::toNumberPattern( |
| UBool hasPadding, int32_t minimumLength, UnicodeString& result) const { |
| // Get a grouping policy like the one in this object that does not |
| // have minimum grouping since toPattern doesn't support it. |
| DigitGrouping grouping(fEffGrouping); |
| grouping.fMinGrouping = 0; |
| |
| // Only for fixed digits, these are the digits that get 0's. |
| DigitInterval minInterval; |
| |
| // Only for fixed digits, these are the digits that get #'s. |
| DigitInterval maxInterval; |
| |
| // Only for significant digits |
| int32_t sigMin; |
| int32_t sigMax; |
| |
| // These are all the digits to be displayed. For significant digits, |
| // this interval always starts at the 1's place an extends left. |
| DigitInterval fullInterval; |
| |
| // Digit range of rounding increment. If rounding increment is .025. |
| // then roundingIncrementLowerExp = -3 and roundingIncrementUpperExp = -1 |
| int32_t roundingIncrementLowerExp = 0; |
| int32_t roundingIncrementUpperExp = 0; |
| |
| if (fUseSigDigits) { |
| SignificantDigitInterval sigInterval; |
| extractSigDigits(sigInterval); |
| sigMax = sigInterval.getMax(); |
| sigMin = sigInterval.getMin(); |
| fullInterval.setFracDigitCount(0); |
| fullInterval.setIntDigitCount(sigMax); |
| } else { |
| extractMinMaxDigits(minInterval, maxInterval); |
| if (fUseScientific) { |
| if (maxInterval.getIntDigitCount() > kMaxScientificIntegerDigits) { |
| maxInterval.setIntDigitCount(1); |
| minInterval.shrinkToFitWithin(maxInterval); |
| } |
| } else if (hasPadding) { |
| // Make max int digits match min int digits for now, we |
| // compute necessary padding later. |
| maxInterval.setIntDigitCount(minInterval.getIntDigitCount()); |
| } else { |
| // For some reason toPattern adds at least one leading '#' |
| maxInterval.setIntDigitCount(minInterval.getIntDigitCount() + 1); |
| } |
| if (!fEffPrecision.fMantissa.fRoundingIncrement.isZero()) { |
| roundingIncrementLowerExp = |
| fEffPrecision.fMantissa.fRoundingIncrement.getLowerExponent(); |
| roundingIncrementUpperExp = |
| fEffPrecision.fMantissa.fRoundingIncrement.getUpperExponent(); |
| // We have to include the rounding increment in what we display |
| maxInterval.expandToContainDigit(roundingIncrementLowerExp); |
| maxInterval.expandToContainDigit(roundingIncrementUpperExp - 1); |
| } |
| fullInterval = maxInterval; |
| } |
| // We have to include enough digits to show grouping strategy |
| int32_t minLengthToDescribeGrouping = |
| getMinimumLengthToDescribeGrouping(grouping); |
| if (minLengthToDescribeGrouping > 0) { |
| fullInterval.expandToContainDigit( |
| getMinimumLengthToDescribeGrouping(grouping) - 1); |
| } |
| |
| // If we have a minimum length, we have to add digits to the left to |
| // depict padding. |
| if (hasPadding) { |
| // For non scientific notation, |
| // minimumLengthForMantissa = minimumLength |
| int32_t minimumLengthForMantissa = |
| minimumLength - computeExponentPatternLength(); |
| int32_t mininumLengthForMantissaIntPart = |
| minimumLengthForMantissa |
| - countFractionDigitAndDecimalPatternLength( |
| fullInterval.getFracDigitCount()); |
| // Because of grouping, we may need fewer than expected digits to |
| // achieve the length we need. |
| int32_t digitsNeeded; |
| if (getLeftDigitsForLeftLength( |
| grouping, |
| mininumLengthForMantissaIntPart, |
| fullInterval.getIntDigitCount(), |
| digitsNeeded)) { |
| |
| // In this case, we achieved the exact length that we want. |
| fullInterval.setIntDigitCount(digitsNeeded); |
| } else if (digitsNeeded > fullInterval.getIntDigitCount()) { |
| |
| // Having digitsNeeded digits goes over desired length which |
| // means that to have desired length would mean starting on a |
| // grouping sepearator e.g ,###,### so add a '#' and use one |
| // less digit. This trick gives ####,### but that is the best |
| // we can do. |
| result.append(kPatternDigit); |
| fullInterval.setIntDigitCount(digitsNeeded - 1); |
| } |
| } |
| int32_t maxDigitPos = fullInterval.getMostSignificantExclusive(); |
| int32_t minDigitPos = fullInterval.getLeastSignificantInclusive(); |
| for (int32_t i = maxDigitPos - 1; i >= minDigitPos; --i) { |
| if (!fOptions.fMantissa.fAlwaysShowDecimal && i == -1) { |
| result.append(kPatternDecimalSeparator); |
| } |
| if (fUseSigDigits) { |
| // Use digit symbol |
| if (i >= sigMax || i < sigMax - sigMin) { |
| result.append(kPatternDigit); |
| } else { |
| result.append(kPatternSignificantDigit); |
| } |
| } else { |
| if (i < roundingIncrementUpperExp && i >= roundingIncrementLowerExp) { |
| result.append(fEffPrecision.fMantissa.fRoundingIncrement.getDigitByExponent(i) + kPatternZeroDigit); |
| } else if (minInterval.contains(i)) { |
| result.append(kPatternZeroDigit); |
| } else { |
| result.append(kPatternDigit); |
| } |
| } |
| if (grouping.isSeparatorAt(i + 1, i)) { |
| result.append(kPatternGroupingSeparator); |
| } |
| if (fOptions.fMantissa.fAlwaysShowDecimal && i == 0) { |
| result.append(kPatternDecimalSeparator); |
| } |
| } |
| if (fUseScientific) { |
| result.append(kPatternExponent); |
| if (fOptions.fExponent.fAlwaysShowSign) { |
| result.append(kPatternPlus); |
| } |
| for (int32_t i = 0; i < 1 || i < fEffPrecision.fMinExponentDigits; ++i) { |
| result.append(kPatternZeroDigit); |
| } |
| } |
| return result; |
| } |
| |
| UnicodeString& |
| DecimalFormatImpl::toPattern(UnicodeString& result) const { |
| result.remove(); |
| UnicodeString padSpec; |
| if (fAffixes.fWidth > 0) { |
| padSpec.append(kPatternPadEscape); |
| padSpec.append(fAffixes.fPadChar); |
| } |
| if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) { |
| result.append(padSpec); |
| } |
| fPositivePrefixPattern.toUserString(result); |
| if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) { |
| result.append(padSpec); |
| } |
| toNumberPattern( |
| fAffixes.fWidth > 0, |
| fAffixes.fWidth - fPositivePrefixPattern.countChar32() - fPositiveSuffixPattern.countChar32(), |
| result); |
| if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) { |
| result.append(padSpec); |
| } |
| fPositiveSuffixPattern.toUserString(result); |
| if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) { |
| result.append(padSpec); |
| } |
| AffixPattern withNegative; |
| withNegative.add(AffixPattern::kNegative); |
| withNegative.append(fPositivePrefixPattern); |
| if (!fPositiveSuffixPattern.equals(fNegativeSuffixPattern) || |
| !withNegative.equals(fNegativePrefixPattern)) { |
| result.append(kPatternSeparator); |
| if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) { |
| result.append(padSpec); |
| } |
| fNegativePrefixPattern.toUserString(result); |
| if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) { |
| result.append(padSpec); |
| } |
| toNumberPattern( |
| fAffixes.fWidth > 0, |
| fAffixes.fWidth - fNegativePrefixPattern.countChar32() - fNegativeSuffixPattern.countChar32(), |
| result); |
| if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) { |
| result.append(padSpec); |
| } |
| fNegativeSuffixPattern.toUserString(result); |
| if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) { |
| result.append(padSpec); |
| } |
| } |
| return result; |
| } |
| |
| int32_t |
| DecimalFormatImpl::getOldFormatWidth() const { |
| if (fAffixes.fWidth == 0) { |
| return 0; |
| } |
| return fAffixes.fWidth - fPositiveSuffixPattern.countChar32() - fPositivePrefixPattern.countChar32(); |
| } |
| |
| const UnicodeString & |
| DecimalFormatImpl::getConstSymbol( |
| DecimalFormatSymbols::ENumberFormatSymbol symbol) const { |
| return fSymbols->getConstSymbol(symbol); |
| } |
| |
| UBool |
| DecimalFormatImpl::isParseFastpath() const { |
| AffixPattern negative; |
| negative.add(AffixPattern::kNegative); |
| |
| return fAffixes.fWidth == 0 && |
| fPositivePrefixPattern.countChar32() == 0 && |
| fNegativePrefixPattern.equals(negative) && |
| fPositiveSuffixPattern.countChar32() == 0 && |
| fNegativeSuffixPattern.countChar32() == 0; |
| } |
| |
| |
| U_NAMESPACE_END |
| |
| #endif /* #if !UCONFIG_NO_FORMATTING */ |
| |