Index: source/i18n/decimfmtimpl.cpp |
diff --git a/source/i18n/decimfmtimpl.cpp b/source/i18n/decimfmtimpl.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8493ecd03772f54748094433f81d084b6e94a519 |
--- /dev/null |
+++ b/source/i18n/decimfmtimpl.cpp |
@@ -0,0 +1,1594 @@ |
+/* |
+ * 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 <math.h> |
+#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 */ |
+ |