| 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 */
|
| +
|
|
|