// © 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: decimfmtimpl.cpp */ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include #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((int32_t)0); } else { fMultiplier.set((int32_t)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 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 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( 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((int32_t)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((UChar)(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 */