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