summaryrefslogtreecommitdiffstats
path: root/intl/icu/source/i18n/decimfmtimpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'intl/icu/source/i18n/decimfmtimpl.cpp')
-rw-r--r--intl/icu/source/i18n/decimfmtimpl.cpp1596
1 files changed, 1596 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/decimfmtimpl.cpp b/intl/icu/source/i18n/decimfmtimpl.cpp
new file mode 100644
index 000000000..1bf742d14
--- /dev/null
+++ b/intl/icu/source/i18n/decimfmtimpl.cpp
@@ -0,0 +1,1596 @@
+// Copyright (C) 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+ * Copyright (C) 2015, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ * file name: 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((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<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(
+ 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 */
+