/*
*******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and *
+* Copyright (C) 1997-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
#include <math.h>
#include "hash.h"
#include "decfmtst.h"
+#include "dcfmtimp.h"
+#include "plurrule_impl.h"
+#include "decimalformatpattern.h"
+
+/*
+ * On certain platforms, round is a macro defined in math.h
+ * This undefine is to avoid conflict between the macro and
+ * the function defined below.
+ */
+#ifdef round
+#undef round
+#endif
U_NAMESPACE_BEGIN
+#ifdef FMT_DEBUG
+#include <stdio.h>
+static void _debugout(const char *f, int l, const UnicodeString& s) {
+ char buf[2000];
+ s.extract((int32_t) 0, s.length(), buf, "utf-8");
+ printf("%s:%d: %s\n", f,l, buf);
+}
+#define debugout(x) _debugout(__FILE__,__LINE__,x)
+#define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
+static const UnicodeString dbg_null("<NULL>","");
+#define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null))
+#else
+#define debugout(x)
+#define debug(x)
+#endif
+
+
+
+/* == Fastpath calculation. ==
+ */
+#if UCONFIG_FORMAT_FASTPATHS_49
+inline DecimalFormatInternal& internalData(uint8_t *reserved) {
+ return *reinterpret_cast<DecimalFormatInternal*>(reserved);
+}
+inline const DecimalFormatInternal& internalData(const uint8_t *reserved) {
+ return *reinterpret_cast<const DecimalFormatInternal*>(reserved);
+}
+#else
+#endif
+
/* For currency parsing purose,
* Need to remember all prefix patterns and suffix patterns of
* every currency format pattern,
posSuffixPatternForCurrency = posSuffix;
patternType = type;
}
+#ifdef FMT_DEBUG
+ void dump() const {
+ debugout( UnicodeString("AffixPatternsForCurrency( -=\"") +
+ negPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
+ negSuffixPatternForCurrency + (UnicodeString)"\" +=\"" +
+ posPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
+ posSuffixPatternForCurrency + (UnicodeString)"\" )");
+ }
+#endif
};
/* affix for currency formatting when the currency sign in the pattern
posPrefixForCurrency = posPrefix;
posSuffixForCurrency = posSuffix;
}
+#ifdef FMT_DEBUG
+ void dump() const {
+ debugout( UnicodeString("AffixesForCurrency( -=\"") +
+ negPrefixForCurrency + (UnicodeString)"\"/\"" +
+ negSuffixForCurrency + (UnicodeString)"\" +=\"" +
+ posPrefixForCurrency + (UnicodeString)"\"/\"" +
+ posSuffixForCurrency + (UnicodeString)"\" )");
+ }
+#endif
};
U_CDECL_BEGIN
U_CDECL_END
-//#define FMT_DEBUG
-
-#ifdef FMT_DEBUG
-#include <stdio.h>
-static void debugout(UnicodeString s) {
- char buf[2000];
- s.extract((int32_t) 0, s.length(), buf);
- printf("%s\n", buf);
-}
-#define debug(x) printf("%s\n", x);
-#else
-#define debugout(x)
-#define debug(x)
-#endif
-
// *****************************************************************************
static const char fgPatterns[]="patterns";
static const char fgDecimalFormat[]="decimalFormat";
static const char fgCurrencyFormat[]="currencyFormat";
+
static const UChar fgTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; }
inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; }
+static void copyString(const UnicodeString& src, UBool isBogus, UnicodeString *& dest, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (isBogus) {
+ delete dest;
+ dest = NULL;
+ } else {
+ if (dest != NULL) {
+ *dest = src;
+ } else {
+ dest = new UnicodeString(src);
+ if (dest == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+ }
+}
+
+
//------------------------------------------------------------------------------
// Constructs a DecimalFormat instance in the default locale.
// Common DecimalFormat initialization.
// Put all fields of an uninitialized object into a known state.
// Common code, shared by all constructors.
+// Can not fail. Leave the object in good enough shape that the destructor
+// or assignment operator can run successfully.
void
DecimalFormat::init() {
fPosPrefixPattern = 0;
fNegSuffixPattern = 0;
fCurrencyChoice = 0;
fMultiplier = NULL;
+ fScale = 0;
fGroupingSize = 0;
fGroupingSize2 = 0;
fDecimalSeparatorAlwaysShown = FALSE;
fUseExponentialNotation = FALSE;
fMinExponentDigits = 0;
fExponentSignAlwaysShown = FALSE;
+ fBoolFlags.clear();
fRoundingIncrement = 0;
fRoundingMode = kRoundHalfEven;
fPad = 0;
fFormatWidth = 0;
fPadPosition = kPadBeforePrefix;
fStyle = UNUM_DECIMAL;
- fCurrencySignCount = 0;
+ fCurrencySignCount = fgCurrencySignCountZero;
fAffixPatternsForCurrency = NULL;
fAffixesForCurrency = NULL;
fPluralAffixesForCurrency = NULL;
fCurrencyPluralInfo = NULL;
+#if UCONFIG_HAVE_PARSEALLINPUT
+ fParseAllInput = UNUM_MAYBE;
+#endif
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+ DecimalFormatInternal &data = internalData(fReserved);
+ data.fFastFormatStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
+ data.fFastParseStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
+#endif
+ fStaticSets = NULL;
}
//------------------------------------------------------------------------------
// created instance owns the symbols.
void
-DecimalFormat::construct(UErrorCode& status,
+DecimalFormat::construct(UErrorCode& status,
UParseError& parseErr,
const UnicodeString* pattern,
DecimalFormatSymbols* symbolsToAdopt)
if (fSymbols == NULL)
{
fSymbols = new DecimalFormatSymbols(Locale::getDefault(), status);
- /* test for NULL */
if (fSymbols == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
}
+ fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
UErrorCode nsStatus = U_ZERO_ERROR;
NumberingSystem *ns = NumberingSystem::createInstance(nsStatus);
if (U_FAILURE(nsStatus)) {
// If it was a currency format, apply the appropriate rounding by
// resetting the currency. NOTE: this copies fCurrency on top of itself.
- if (fCurrencySignCount > fgCurrencySignCountZero) {
+ if (fCurrencySignCount != fgCurrencySignCountZero) {
setCurrencyInternally(getCurrency(), status);
}
+#if UCONFIG_FORMAT_FASTPATHS_49
+ DecimalFormatInternal &data = internalData(fReserved);
+ data.fFastFormatStatus = kFastpathNO; // allow it to be calculated
+ data.fFastParseStatus = kFastpathNO; // allow it to be calculated
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
// assignment operator
-static void _copy_us_ptr(UnicodeString** pdest, const UnicodeString* source) {
+template <class T>
+static void _copy_ptr(T** pdest, const T* source) {
if (source == NULL) {
delete *pdest;
*pdest = NULL;
} else if (*pdest == NULL) {
- *pdest = new UnicodeString(*source);
+ *pdest = new T(*source);
} else {
- **pdest = *source;
+ **pdest = *source;
+ }
+}
+
+template <class T>
+static void _clone_ptr(T** pdest, const T* source) {
+ delete *pdest;
+ if (source == NULL) {
+ *pdest = NULL;
+ } else {
+ *pdest = static_cast<T*>(source->clone());
}
}
DecimalFormat::operator=(const DecimalFormat& rhs)
{
if(this != &rhs) {
+ UErrorCode status = U_ZERO_ERROR;
NumberFormat::operator=(rhs);
+ fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
fPositivePrefix = rhs.fPositivePrefix;
fPositiveSuffix = rhs.fPositiveSuffix;
fNegativePrefix = rhs.fNegativePrefix;
fNegativeSuffix = rhs.fNegativeSuffix;
- _copy_us_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern);
- _copy_us_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern);
- _copy_us_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern);
- _copy_us_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern);
- if (rhs.fCurrencyChoice == 0) {
- delete fCurrencyChoice;
- fCurrencyChoice = 0;
- } else {
- fCurrencyChoice = (ChoiceFormat*) rhs.fCurrencyChoice->clone();
- }
+ _copy_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern);
+ _copy_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern);
+ _copy_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern);
+ _copy_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern);
+ _clone_ptr(&fCurrencyChoice, rhs.fCurrencyChoice);
setRoundingIncrement(rhs.getRoundingIncrement());
fRoundingMode = rhs.fRoundingMode;
setMultiplier(rhs.getMultiplier());
fGroupingSize = rhs.fGroupingSize;
fGroupingSize2 = rhs.fGroupingSize2;
fDecimalSeparatorAlwaysShown = rhs.fDecimalSeparatorAlwaysShown;
- if(fSymbols == NULL) {
- fSymbols = new DecimalFormatSymbols(*rhs.fSymbols);
- } else {
- *fSymbols = *rhs.fSymbols;
- }
+ _copy_ptr(&fSymbols, rhs.fSymbols);
fUseExponentialNotation = rhs.fUseExponentialNotation;
fExponentSignAlwaysShown = rhs.fExponentSignAlwaysShown;
+ fBoolFlags = rhs.fBoolFlags;
/*Bertrand A. D. Update 98.03.17*/
fCurrencySignCount = rhs.fCurrencySignCount;
/*end of Update*/
fUseSignificantDigits = rhs.fUseSignificantDigits;
fFormatPattern = rhs.fFormatPattern;
fStyle = rhs.fStyle;
- fCurrencySignCount = rhs.fCurrencySignCount;
- if (rhs.fCurrencyPluralInfo) {
- delete fCurrencyPluralInfo;
- fCurrencyPluralInfo = rhs.fCurrencyPluralInfo->clone();
- }
+ _clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo);
+ deleteHashForAffixPattern();
if (rhs.fAffixPatternsForCurrency) {
UErrorCode status = U_ZERO_ERROR;
- deleteHashForAffixPattern();
fAffixPatternsForCurrency = initHashForAffixPattern(status);
copyHashForAffixPattern(rhs.fAffixPatternsForCurrency,
fAffixPatternsForCurrency, status);
}
+ deleteHashForAffix(fAffixesForCurrency);
if (rhs.fAffixesForCurrency) {
UErrorCode status = U_ZERO_ERROR;
- deleteHashForAffix(fAffixesForCurrency);
fAffixesForCurrency = initHashForAffixPattern(status);
copyHashForAffix(rhs.fAffixesForCurrency, fAffixesForCurrency, status);
}
+ deleteHashForAffix(fPluralAffixesForCurrency);
if (rhs.fPluralAffixesForCurrency) {
UErrorCode status = U_ZERO_ERROR;
- deleteHashForAffix(fPluralAffixesForCurrency);
fPluralAffixesForCurrency = initHashForAffixPattern(status);
copyHashForAffix(rhs.fPluralAffixesForCurrency, fPluralAffixesForCurrency, status);
}
+#if UCONFIG_FORMAT_FASTPATHS_49
+ DecimalFormatInternal &data = internalData(fReserved);
+ const DecimalFormatInternal &rhsData = internalData(rhs.fReserved);
+ data = rhsData;
+#endif
}
return *this;
}
if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
debug("Rounding Increment !=");
}
+ if (fRoundingMode != other->fRoundingMode) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ printf("Rounding Mode %d != %d", (int)fRoundingMode, (int)other->fRoundingMode);
+ }
if (getMultiplier() != other->getMultiplier()) {
if (first) { printf("[ "); first = FALSE; }
printf("Multiplier %ld != %ld", getMultiplier(), other->getMultiplier());
}
if (fDecimalSeparatorAlwaysShown != other->fDecimalSeparatorAlwaysShown) {
if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
- printf("Dec Sep Always %d != %d", fDecimalSeparatorAlwaysShown, other->fDecimalSeparatorAlwaysShown);
+ printf("fDecimalSeparatorAlwaysShown %d != %d", fDecimalSeparatorAlwaysShown, other->fDecimalSeparatorAlwaysShown);
}
if (fUseExponentialNotation != other->fUseExponentialNotation) {
if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
- debug("Use Exp !=");
+ debug("fUseExponentialNotation !=");
+ }
+ if (fUseExponentialNotation &&
+ fMinExponentDigits != other->fMinExponentDigits) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fMinExponentDigits !=");
}
- if (!(!fUseExponentialNotation ||
- fMinExponentDigits != other->fMinExponentDigits)) {
+ if (fUseExponentialNotation &&
+ fExponentSignAlwaysShown != other->fExponentSignAlwaysShown) {
if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
- debug("Exp Digits !=");
+ debug("fExponentSignAlwaysShown !=");
+ }
+ if (fBoolFlags.getAll() != other->fBoolFlags.getAll()) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fBoolFlags !=");
}
if (*fSymbols != *(other->fSymbols)) {
if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
}
// TODO Add debug stuff for significant digits here
if (fUseSignificantDigits != other->fUseSignificantDigits) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
debug("fUseSignificantDigits !=");
}
if (fUseSignificantDigits &&
fMinSignificantDigits != other->fMinSignificantDigits) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
debug("fMinSignificantDigits !=");
}
if (fUseSignificantDigits &&
fMaxSignificantDigits != other->fMaxSignificantDigits) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
debug("fMaxSignificantDigits !=");
}
+ if (fFormatWidth != other->fFormatWidth) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fFormatWidth !=");
+ }
+ if (fPad != other->fPad) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fPad !=");
+ }
+ if (fPadPosition != other->fPadPosition) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fPadPosition !=");
+ }
+ if (fStyle == UNUM_CURRENCY_PLURAL &&
+ fStyle != other->fStyle)
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fStyle !=");
+ }
+ if (fStyle == UNUM_CURRENCY_PLURAL &&
+ fFormatPattern != other->fFormatPattern) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fFormatPattern !=");
+ }
if (!first) { printf(" ]"); }
if (fCurrencySignCount != other->fCurrencySignCount) {
}
#endif
- return (NumberFormat::operator==(that) &&
- ((fCurrencySignCount == fgCurrencySignCountInPluralFormat) ?
- (fAffixPatternsForCurrency->equals(*other->fAffixPatternsForCurrency)) :
- (((fPosPrefixPattern == other->fPosPrefixPattern && // both null
- fPositivePrefix == other->fPositivePrefix)
- || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 &&
- *fPosPrefixPattern == *other->fPosPrefixPattern)) &&
- ((fPosSuffixPattern == other->fPosSuffixPattern && // both null
- fPositiveSuffix == other->fPositiveSuffix)
- || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 &&
- *fPosSuffixPattern == *other->fPosSuffixPattern)) &&
- ((fNegPrefixPattern == other->fNegPrefixPattern && // both null
- fNegativePrefix == other->fNegativePrefix)
- || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 &&
- *fNegPrefixPattern == *other->fNegPrefixPattern)) &&
- ((fNegSuffixPattern == other->fNegSuffixPattern && // both null
- fNegativeSuffix == other->fNegativeSuffix)
- || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 &&
- *fNegSuffixPattern == *other->fNegSuffixPattern)))) &&
- ((fRoundingIncrement == other->fRoundingIncrement) // both null
- || (fRoundingIncrement != NULL &&
- other->fRoundingIncrement != NULL &&
- *fRoundingIncrement == *other->fRoundingIncrement)) &&
+ return (
+ NumberFormat::operator==(that) &&
+
+ ((fCurrencySignCount == fgCurrencySignCountInPluralFormat) ?
+ (fAffixPatternsForCurrency->equals(*other->fAffixPatternsForCurrency)) :
+ (((fPosPrefixPattern == other->fPosPrefixPattern && // both null
+ fPositivePrefix == other->fPositivePrefix)
+ || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 &&
+ *fPosPrefixPattern == *other->fPosPrefixPattern)) &&
+ ((fPosSuffixPattern == other->fPosSuffixPattern && // both null
+ fPositiveSuffix == other->fPositiveSuffix)
+ || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 &&
+ *fPosSuffixPattern == *other->fPosSuffixPattern)) &&
+ ((fNegPrefixPattern == other->fNegPrefixPattern && // both null
+ fNegativePrefix == other->fNegativePrefix)
+ || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 &&
+ *fNegPrefixPattern == *other->fNegPrefixPattern)) &&
+ ((fNegSuffixPattern == other->fNegSuffixPattern && // both null
+ fNegativeSuffix == other->fNegativeSuffix)
+ || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 &&
+ *fNegSuffixPattern == *other->fNegSuffixPattern)))) &&
+
+ ((fRoundingIncrement == other->fRoundingIncrement) // both null
+ || (fRoundingIncrement != NULL &&
+ other->fRoundingIncrement != NULL &&
+ *fRoundingIncrement == *other->fRoundingIncrement)) &&
+
+ fRoundingMode == other->fRoundingMode &&
getMultiplier() == other->getMultiplier() &&
fGroupingSize == other->fGroupingSize &&
fGroupingSize2 == other->fGroupingSize2 &&
fDecimalSeparatorAlwaysShown == other->fDecimalSeparatorAlwaysShown &&
fUseExponentialNotation == other->fUseExponentialNotation &&
+
(!fUseExponentialNotation ||
- fMinExponentDigits == other->fMinExponentDigits) &&
+ (fMinExponentDigits == other->fMinExponentDigits && fExponentSignAlwaysShown == other->fExponentSignAlwaysShown)) &&
+
+ fBoolFlags.getAll() == other->fBoolFlags.getAll() &&
*fSymbols == *(other->fSymbols) &&
fUseSignificantDigits == other->fUseSignificantDigits &&
+
(!fUseSignificantDigits ||
- (fMinSignificantDigits == other->fMinSignificantDigits &&
- fMaxSignificantDigits == other->fMaxSignificantDigits)) &&
+ (fMinSignificantDigits == other->fMinSignificantDigits && fMaxSignificantDigits == other->fMaxSignificantDigits)) &&
+
+ fFormatWidth == other->fFormatWidth &&
+ fPad == other->fPad &&
+ fPadPosition == other->fPadPosition &&
+
+ (fStyle != UNUM_CURRENCY_PLURAL ||
+ (fStyle == other->fStyle && fFormatPattern == other->fFormatPattern)) &&
+
fCurrencySignCount == other->fCurrencySignCount &&
+
((fCurrencyPluralInfo == other->fCurrencyPluralInfo &&
fCurrencyPluralInfo == NULL) ||
(fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL &&
- *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo))));
+ *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo)))
+
+ // depending on other settings we may also need to compare
+ // fCurrencyChoice (mostly deprecated?),
+ // fAffixesForCurrency & fPluralAffixesForCurrency (only relevant in some cases)
+ );
}
//------------------------------------------------------------------------------
return new DecimalFormat(*this);
}
+
+FixedDecimal
+DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const {
+ FixedDecimal result;
+
+ if (U_FAILURE(status)) {
+ return result;
+ }
+
+ if (uprv_isNaN(number) || uprv_isPositiveInfinity(fabs(number))) {
+ // For NaN and Infinity the state of the formatter is ignored.
+ result.init(number);
+ return result;
+ }
+
+ if (fMultiplier == NULL && fScale == 0 && fRoundingIncrement == 0 && areSignificantDigitsUsed() == FALSE &&
+ result.quickInit(number) && result.visibleDecimalDigitCount <= getMaximumFractionDigits()) {
+ // Fast Path. Construction of an exact FixedDecimal directly from the double, without passing
+ // through a DigitList, was successful, and the formatter is doing nothing tricky with rounding.
+ // printf("getFixedDecimal(%g): taking fast path.\n", number);
+ result.adjustForMinFractionDigits(getMinimumFractionDigits());
+ } else {
+ // Slow path. Create a DigitList, and have this formatter round it according to the
+ // requirements of the format, and fill the fixedDecimal from that.
+ DigitList digits;
+ digits.set(number);
+ result = getFixedDecimal(digits, status);
+ }
+ return result;
+}
+
+// MSVC optimizer bug?
+// turn off optimization as it causes different behavior in the int64->double->int64 conversion
+#if defined (_MSC_VER)
+#pragma optimize ( "", off )
+#endif
+FixedDecimal
+DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return FixedDecimal();
+ }
+ if (!number.isNumeric()) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FixedDecimal();
+ }
+
+ DigitList *dl = number.getDigitList();
+ if (dl != NULL) {
+ DigitList clonedDL(*dl);
+ return getFixedDecimal(clonedDL, status);
+ }
+
+ Formattable::Type type = number.getType();
+ if (type == Formattable::kDouble || type == Formattable::kLong) {
+ return getFixedDecimal(number.getDouble(status), status);
+ }
+
+ if (type == Formattable::kInt64) {
+ // "volatile" here is a workaround to avoid optimization issues.
+ volatile double fdv = number.getDouble(status);
+ // Note: conversion of int64_t -> double rounds with some compilers to
+ // values beyond what can be represented as a 64 bit int. Subsequent
+ // testing or conversion with int64_t produces bad results.
+ // So filter the problematic values, route them to DigitList.
+ if (fdv != (double)U_INT64_MAX && fdv != (double)U_INT64_MIN &&
+ number.getInt64() == (int64_t)fdv) {
+ return getFixedDecimal(number.getDouble(status), status);
+ }
+ }
+
+ // The only case left is type==int64_t, with a value with more digits than a double can represent.
+ // Any formattable originating as a big decimal will have had a pre-existing digit list.
+ // Any originating as a double or int32 will have been handled as a double.
+
+ U_ASSERT(type == Formattable::kInt64);
+ DigitList digits;
+ digits.set(number.getInt64());
+ return getFixedDecimal(digits, status);
+}
+// end workaround MSVC optimizer bug
+#if defined (_MSC_VER)
+#pragma optimize ( "", on )
+#endif
+
+
+// Create a fixed decimal from a DigitList.
+// The digit list may be modified.
+// Internal function only.
+FixedDecimal
+DecimalFormat::getFixedDecimal(DigitList &number, UErrorCode &status) const {
+ // Round the number according to the requirements of this Format.
+ FixedDecimal result;
+ _round(number, number, result.isNegative, status);
+
+ // The int64_t fields in FixedDecimal can easily overflow.
+ // In deciding what to discard in this event, consider that fixedDecimal
+ // is being used only with PluralRules, and those rules mostly look at least significant
+ // few digits of the integer part, and whether the fraction part is zero or not.
+ //
+ // So, in case of overflow when filling in the fields of the FixedDecimal object,
+ // for the integer part, discard the most significant digits.
+ // for the fraction part, discard the least significant digits,
+ // don't truncate the fraction value to zero.
+ // For simplicity, the int64_t fields are limited to 18 decimal digits, even
+ // though they could hold most (but not all) 19 digit values.
+
+ // Integer Digits.
+ int32_t di = number.getDecimalAt()-18; // Take at most 18 digits.
+ if (di < 0) {
+ di = 0;
+ }
+ result.intValue = 0;
+ for (; di<number.getDecimalAt(); di++) {
+ result.intValue = result.intValue * 10 + (number.getDigit(di) & 0x0f);
+ }
+ if (result.intValue == 0 && number.getDecimalAt()-18 > 0) {
+ // The number is something like 100000000000000000000000.
+ // More than 18 digits integer digits, but the least significant 18 are all zero.
+ // We don't want to return zero as the int part, but want to keep zeros
+ // for several of the least significant digits.
+ result.intValue = 100000000000000000LL;
+ }
+
+ // Fraction digits.
+ result.decimalDigits = result.decimalDigitsWithoutTrailingZeros = result.visibleDecimalDigitCount = 0;
+ for (di = number.getDecimalAt(); di < number.getCount(); di++) {
+ result.visibleDecimalDigitCount++;
+ if (result.decimalDigits < 100000000000000000LL) {
+ // 9223372036854775807 Largest 64 bit signed integer
+ int32_t digitVal = number.getDigit(di) & 0x0f; // getDigit() returns a char, '0'-'9'.
+ result.decimalDigits = result.decimalDigits * 10 + digitVal;
+ if (digitVal > 0) {
+ result.decimalDigitsWithoutTrailingZeros = result.decimalDigits;
+ }
+ }
+ }
+
+ result.hasIntegerValue = (result.decimalDigits == 0);
+
+ // Trailing fraction zeros. The format specification may require more trailing
+ // zeros than the numeric value. Add any such on now.
+
+ int32_t minFractionDigits;
+ if (areSignificantDigitsUsed()) {
+ minFractionDigits = getMinimumSignificantDigits() - number.getDecimalAt();
+ if (minFractionDigits < 0) {
+ minFractionDigits = 0;
+ }
+ } else {
+ minFractionDigits = getMinimumFractionDigits();
+ }
+ result.adjustForMinFractionDigits(minFractionDigits);
+
+ return result;
+}
+
+
//------------------------------------------------------------------------------
UnicodeString&
return format((int64_t)number, appendTo, fieldPosition);
}
+UnicodeString&
+DecimalFormat::format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const
+{
+ return format((int64_t)number, appendTo, fieldPosition, status);
+}
+
UnicodeString&
DecimalFormat::format(int32_t number,
UnicodeString& appendTo,
return format((int64_t)number, appendTo, posIter, status);
}
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+void DecimalFormat::handleChanged() {
+ DecimalFormatInternal &data = internalData(fReserved);
+
+ if(data.fFastFormatStatus == kFastpathUNKNOWN || data.fFastParseStatus == kFastpathUNKNOWN) {
+ return; // still constructing. Wait.
+ }
+
+ data.fFastParseStatus = data.fFastFormatStatus = kFastpathNO;
+
+#if UCONFIG_HAVE_PARSEALLINPUT
+ if(fParseAllInput == UNUM_NO) {
+ debug("No Parse fastpath: fParseAllInput==UNUM_NO");
+ } else
+#endif
+ if (fFormatWidth!=0) {
+ debug("No Parse fastpath: fFormatWidth");
+ } else if(fPositivePrefix.length()>0) {
+ debug("No Parse fastpath: positive prefix");
+ } else if(fPositiveSuffix.length()>0) {
+ debug("No Parse fastpath: positive suffix");
+ } else if(fNegativePrefix.length()>1
+ || ((fNegativePrefix.length()==1) && (fNegativePrefix.charAt(0)!=0x002D))) {
+ debug("No Parse fastpath: negative prefix that isn't '-'");
+ } else if(fNegativeSuffix.length()>0) {
+ debug("No Parse fastpath: negative suffix");
+ } else {
+ data.fFastParseStatus = kFastpathYES;
+ debug("parse fastpath: YES");
+ }
+
+ if (fGroupingSize!=0 && isGroupingUsed()) {
+ debug("No format fastpath: fGroupingSize!=0 and grouping is used");
+#ifdef FMT_DEBUG
+ printf("groupingsize=%d\n", fGroupingSize);
+#endif
+ } else if(fGroupingSize2!=0 && isGroupingUsed()) {
+ debug("No format fastpath: fGroupingSize2!=0");
+ } else if(fUseExponentialNotation) {
+ debug("No format fastpath: fUseExponentialNotation");
+ } else if(fFormatWidth!=0) {
+ debug("No format fastpath: fFormatWidth!=0");
+ } else if(fMinSignificantDigits!=1) {
+ debug("No format fastpath: fMinSignificantDigits!=1");
+ } else if(fMultiplier!=NULL) {
+ debug("No format fastpath: fMultiplier!=NULL");
+ } else if(fScale!=0) {
+ debug("No format fastpath: fScale!=0");
+ } else if(0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)) {
+ debug("No format fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)");
+ } else if(fDecimalSeparatorAlwaysShown) {
+ debug("No format fastpath: fDecimalSeparatorAlwaysShown");
+ } else if(getMinimumFractionDigits()>0) {
+ debug("No format fastpath: fMinFractionDigits>0");
+ } else if(fCurrencySignCount != fgCurrencySignCountZero) {
+ debug("No format fastpath: fCurrencySignCount != fgCurrencySignCountZero");
+ } else if(fRoundingIncrement!=0) {
+ debug("No format fastpath: fRoundingIncrement!=0");
+ } else {
+ data.fFastFormatStatus = kFastpathYES;
+ debug("format:kFastpathYES!");
+ }
+
+
+}
+#endif
//------------------------------------------------------------------------------
UnicodeString&
UnicodeString& appendTo,
FieldPosition& fieldPosition) const
{
+ UErrorCode status = U_ZERO_ERROR; /* ignored */
FieldPositionOnlyHandler handler(fieldPosition);
- return _format(number, appendTo, handler);
+ return _format(number, appendTo, handler, status);
+}
+
+UnicodeString&
+DecimalFormat::format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const
+{
+ FieldPositionOnlyHandler handler(fieldPosition);
+ return _format(number, appendTo, handler, status);
}
UnicodeString&
UErrorCode& status) const
{
FieldPositionIteratorHandler handler(posIter, status);
- return _format(number, appendTo, handler);
+ return _format(number, appendTo, handler, status);
}
UnicodeString&
DecimalFormat::_format(int64_t number,
UnicodeString& appendTo,
- FieldPositionHandler& handler) const
+ FieldPositionHandler& handler,
+ UErrorCode &status) const
{
- UErrorCode status = U_ZERO_ERROR;
+ // Bottleneck function for formatting int64_t
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+ // const UnicodeString *posPrefix = fPosPrefixPattern;
+ // const UnicodeString *posSuffix = fPosSuffixPattern;
+ // const UnicodeString *negSuffix = fNegSuffixPattern;
+
+ const DecimalFormatInternal &data = internalData(fReserved);
+
+#ifdef FMT_DEBUG
+ data.dump();
+ printf("fastpath? [%d]\n", number);
+#endif
+
+ if( data.fFastFormatStatus==kFastpathYES) {
+
+#define kZero 0x0030
+ const int32_t MAX_IDX = MAX_DIGITS+2;
+ UChar outputStr[MAX_IDX];
+ int32_t destIdx = MAX_IDX;
+ outputStr[--destIdx] = 0; // term
+
+ int64_t n = number;
+ if (number < 1) {
+ // Negative numbers are slightly larger than positive
+ // output the first digit (or the leading zero)
+ outputStr[--destIdx] = (-(n % 10) + kZero);
+ n /= -10;
+ }
+ // get any remaining digits
+ while (n > 0) {
+ outputStr[--destIdx] = (n % 10) + kZero;
+ n /= 10;
+ }
+
+
+ // Slide the number to the start of the output str
+ U_ASSERT(destIdx >= 0);
+ int32_t length = MAX_IDX - destIdx -1;
+ /*int32_t prefixLen = */ appendAffix(appendTo, number, handler, number<0, TRUE);
+ int32_t maxIntDig = getMaximumIntegerDigits();
+ int32_t destlength = length<=maxIntDig?length:maxIntDig; // dest length pinned to max int digits
+
+ if(length>maxIntDig && fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ int32_t prependZero = getMinimumIntegerDigits() - destlength;
+
+#ifdef FMT_DEBUG
+ printf("prependZero=%d, length=%d, minintdig=%d maxintdig=%d destlength=%d skip=%d\n", prependZero, length, getMinimumIntegerDigits(), maxIntDig, destlength, length-destlength);
+#endif
+ int32_t intBegin = appendTo.length();
+
+ while((prependZero--)>0) {
+ appendTo.append((UChar)0x0030); // '0'
+ }
+
+ appendTo.append(outputStr+destIdx+
+ (length-destlength), // skip any leading digits
+ destlength);
+ handler.addAttribute(kIntegerField, intBegin, appendTo.length());
+
+ /*int32_t suffixLen =*/ appendAffix(appendTo, number, handler, number<0, FALSE);
+
+ //outputStr[length]=0;
+
+#ifdef FMT_DEBUG
+ printf("Writing [%s] length [%d] max %d for [%d]\n", outputStr+destIdx, length, MAX_IDX, number);
+#endif
+
+#undef kZero
+
+ return appendTo;
+ } // end fastpath
+#endif
+
+ // Else the slow way - via DigitList
DigitList digits;
digits.set(number);
return _format(digits, appendTo, handler, status);
DecimalFormat::format( double number,
UnicodeString& appendTo,
FieldPosition& fieldPosition) const
+{
+ UErrorCode status = U_ZERO_ERROR; /* ignored */
+ FieldPositionOnlyHandler handler(fieldPosition);
+ return _format(number, appendTo, handler, status);
+}
+
+UnicodeString&
+DecimalFormat::format( double number,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const
{
FieldPositionOnlyHandler handler(fieldPosition);
- return _format(number, appendTo, handler);
+ return _format(number, appendTo, handler, status);
}
UnicodeString&
UErrorCode& status) const
{
FieldPositionIteratorHandler handler(posIter, status);
- return _format(number, appendTo, handler);
+ return _format(number, appendTo, handler, status);
}
UnicodeString&
DecimalFormat::_format( double number,
UnicodeString& appendTo,
- FieldPositionHandler& handler) const
+ FieldPositionHandler& handler,
+ UErrorCode &status) const
{
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
// Special case for NaN, sets the begin and end index to be the
// the string length of localized name of NaN.
// TODO: let NaNs go through DigitList.
return appendTo;
}
- UErrorCode status = U_ZERO_ERROR;
DigitList digits;
digits.set(number);
_format(digits, appendTo, handler, status);
FieldPositionIterator *posIter,
UErrorCode &status) const
{
+#if UCONFIG_FORMAT_FASTPATHS_49
+ // don't bother if the int64 path is not optimized
+ int32_t len = number.length();
+
+ if(len>0&&len<10) { /* 10 or more digits may not be an int64 */
+ const char *data = number.data();
+ int64_t num = 0;
+ UBool neg = FALSE;
+ UBool ok = TRUE;
+
+ int32_t start = 0;
+
+ if(data[start]=='+') {
+ start++;
+ } else if(data[start]=='-') {
+ neg=TRUE;
+ start++;
+ }
+
+ int32_t place = 1; /* 1, 10, ... */
+ for(int32_t i=len-1;i>=start;i--) {
+ if(data[i]>='0'&&data[i]<='9') {
+ num+=place*(int64_t)(data[i]-'0');
+ } else {
+ ok=FALSE;
+ break;
+ }
+ place *= 10;
+ }
+
+ if(ok) {
+ if(neg) {
+ num = -num;// add minus bit
+ }
+ // format as int64_t
+ return format(num, toAppendTo, posIter, status);
+ }
+ // else fall through
+ }
+#endif
+
DigitList dnum;
dnum.set(number, status);
if (U_FAILURE(status)) {
return appendTo;
}
+DigitList&
+DecimalFormat::_round(const DigitList &number, DigitList &adjustedNum, UBool& isNegative, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return adjustedNum;
+ }
+ // note: number and adjustedNum may refer to the same DigitList, in cases where a copy
+ // is not needed by the caller.
-UnicodeString&
-DecimalFormat::_format(const DigitList &number,
- UnicodeString& appendTo,
- FieldPositionHandler& handler,
- UErrorCode &status) const
-{
- // Special case for NaN, sets the begin and end index to be the
- // the string length of localized name of NaN.
- if (number.isNaN())
- {
- int begin = appendTo.length();
- appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
-
- handler.addAttribute(kIntegerField, begin, appendTo.length());
-
- addPadding(appendTo, handler, 0, 0);
- return appendTo;
+ adjustedNum = number;
+ isNegative = false;
+ if (number.isNaN()) {
+ return adjustedNum;
}
// Do this BEFORE checking to see if value is infinite or negative! Sets the
// localized name of Infinite and the positive/negative localized
// signs.
- DigitList adjustedNum(number); // Copy, so we do not alter the original.
adjustedNum.setRoundingMode(fRoundingMode);
if (fMultiplier != NULL) {
adjustedNum.mult(*fMultiplier, status);
+ if (U_FAILURE(status)) {
+ return adjustedNum;
+ }
}
- /*
+ if (fScale != 0) {
+ DigitList ten;
+ ten.set((int32_t)10);
+ if (fScale > 0) {
+ for (int32_t i = fScale ; i > 0 ; i--) {
+ adjustedNum.mult(ten, status);
+ if (U_FAILURE(status)) {
+ return adjustedNum;
+ }
+ }
+ } else {
+ for (int32_t i = fScale ; i < 0 ; i++) {
+ adjustedNum.div(ten, status);
+ if (U_FAILURE(status)) {
+ return adjustedNum;
+ }
+ }
+ }
+ }
+
+ /*
* Note: sign is important for zero as well as non-zero numbers.
* Proper detection of -0.0 is needed to deal with the
* issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
*/
- UBool isNegative = !adjustedNum.isPositive();
+ isNegative = !adjustedNum.isPositive();
// Apply rounding after multiplier
-
+
adjustedNum.fContext.status &= ~DEC_Inexact;
if (fRoundingIncrement != NULL) {
adjustedNum.div(*fRoundingIncrement, status);
adjustedNum.toIntegralValue();
adjustedNum.mult(*fRoundingIncrement, status);
adjustedNum.trim();
+ if (U_FAILURE(status)) {
+ return adjustedNum;
+ }
}
if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
status = U_FORMAT_INEXACT_ERROR;
- return appendTo;
+ return adjustedNum;
}
-
- // Special case for INFINITE,
if (adjustedNum.isInfinite()) {
- int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, TRUE);
-
- int begin = appendTo.length();
- appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
-
- handler.addAttribute(kIntegerField, begin, appendTo.length());
-
- int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, FALSE);
-
- addPadding(appendTo, handler, prefixLen, suffixLen);
- return appendTo;
+ return adjustedNum;
}
if (fUseExponentialNotation || areSignificantDigitsUsed()) {
int32_t sigDigits = precision();
if (sigDigits > 0) {
adjustedNum.round(sigDigits);
+ // Travis Keep (21/2/2014): Calling round on a digitList does not necessarily
+ // preserve the sign of that digit list. Preserving the sign is especially
+ // important when formatting -0.0 for instance. Not preserving the sign seems
+ // like a bug because I cannot think of any case where the sign would actually
+ // have to change when rounding. For now, we preserve the sign by setting the
+ // positive attribute directly.
+ adjustedNum.setPositive(!isNegative);
}
} else {
// Fixed point format. Round to a set number of fraction digits.
}
if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
status = U_FORMAT_INEXACT_ERROR;
- return appendTo;
+ return adjustedNum;
}
-
- return subformat(appendTo, handler, adjustedNum, FALSE);
+ return adjustedNum;
}
-
UnicodeString&
-DecimalFormat::format( const Formattable& obj,
+DecimalFormat::_format(const DigitList &number,
UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
+ FieldPositionHandler& handler,
+ UErrorCode &status) const
{
- return NumberFormat::format(obj, appendTo, fieldPosition, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+
+ // Special case for NaN, sets the begin and end index to be the
+ // the string length of localized name of NaN.
+ if (number.isNaN())
+ {
+ int begin = appendTo.length();
+ appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+
+ handler.addAttribute(kIntegerField, begin, appendTo.length());
+
+ addPadding(appendTo, handler, 0, 0);
+ return appendTo;
+ }
+
+ DigitList adjustedNum;
+ UBool isNegative;
+ _round(number, adjustedNum, isNegative, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+
+ // Special case for INFINITE,
+ if (adjustedNum.isInfinite()) {
+ int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, TRUE);
+
+ int begin = appendTo.length();
+ appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
+
+ handler.addAttribute(kIntegerField, begin, appendTo.length());
+
+ int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, FALSE);
+
+ addPadding(appendTo, handler, prefixLen, suffixLen);
+ return appendTo;
+ }
+ return subformat(appendTo, handler, adjustedNum, FALSE, status);
}
/**
DecimalFormat::subformat(UnicodeString& appendTo,
FieldPositionHandler& handler,
DigitList& digits,
- UBool isInteger) const
+ UBool isInteger,
+ UErrorCode& status) const
{
// char zero = '0';
// DigitList returns digits as '0' thru '9', so we will need to
localizedDigits[9] = getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
const UnicodeString *grouping ;
- if(fCurrencySignCount > fgCurrencySignCountZero) {
- grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
- }else{
+ if(fCurrencySignCount == fgCurrencySignCountZero) {
grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ }else{
+ grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
}
const UnicodeString *decimal;
- if(fCurrencySignCount > fgCurrencySignCountZero) {
- decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
- } else {
+ if(fCurrencySignCount == fgCurrencySignCountZero) {
decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ } else {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
}
UBool useSigDig = areSignificantDigitsUsed();
int32_t maxIntDig = getMaximumIntegerDigits();
if (count > maxIntDig && maxIntDig >= 0) {
count = maxIntDig;
digitIndex = digits.getDecimalAt() - count;
+ if(fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
}
int32_t sizeBeforeIntegerPart = appendTo.length();
}
}
+ // This handles the special case of formatting 0. For zero only, we count the
+ // zero to the left of the decimal point as one signficant digit. Ordinarily we
+ // do not count any leading 0's as significant. If the number we are formatting
+ // is not zero, then either sigCount or digits.getCount() will be non-zero.
+ if (sigCount == 0 && digits.getCount() == 0) {
+ sigCount = 1;
+ }
+
// TODO(dlf): this looks like it was a bug, we marked the int field as ending
// before the zero was generated.
// Record field information for caller.
//------------------------------------------------------------------------------
-void
-DecimalFormat::parse(const UnicodeString& text,
- Formattable& result,
- UErrorCode& status) const
-{
- NumberFormat::parse(text, result, status);
-}
-
void
DecimalFormat::parse(const UnicodeString& text,
Formattable& result,
ParsePosition& pos) const {
Formattable parseResult;
int32_t start = pos.getIndex();
- UChar curbuf[4];
+ UChar curbuf[4] = {};
parse(text, parseResult, pos, curbuf);
if (pos.getIndex() != start) {
UErrorCode ec = U_ZERO_ERROR;
// clear any old contents in the result. In particular, clears any DigitList
// that it may be holding.
result.setLong(0);
+ if (currency != NULL) {
+ for (int32_t ci=0; ci<4; ci++) {
+ currency[ci] = 0;
+ }
+ }
// Handle NaN as a special case:
// status is used to record whether a number is infinite.
UBool status[fgStatusLength];
- DigitList *digits = new DigitList;
+
+ DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer
if (digits == NULL) {
return; // no way to report error from here.
}
- if (fCurrencySignCount > fgCurrencySignCountZero) {
+ if (fCurrencySignCount != fgCurrencySignCountZero) {
if (!parseForCurrency(text, parsePosition, *digits,
status, currency)) {
- delete digits;
- return;
+ return;
}
} else {
if (!subparse(text,
fPosPrefixPattern, fPosSuffixPattern,
FALSE, UCURR_SYMBOL_NAME,
parsePosition, *digits, status, currency)) {
+ debug("!subparse(...) - rewind");
parsePosition.setIndex(startIdx);
- delete digits;
return;
}
}
if (status[fgStatusInfinite]) {
double inf = uprv_getInfinity();
result.setDouble(digits->isPositive() ? inf : -inf);
- delete digits; // TODO: set the dl to infinity, and let it fall into the code below.
+ // TODO: set the dl to infinity, and let it fall into the code below.
}
else {
digits->div(*fMultiplier, ec);
}
+ if (fScale != 0) {
+ DigitList ten;
+ ten.set((int32_t)10);
+ if (fScale > 0) {
+ for (int32_t i = fScale; i > 0; i--) {
+ UErrorCode ec = U_ZERO_ERROR;
+ digits->div(ten,ec);
+ }
+ } else {
+ for (int32_t i = fScale; i < 0; i++) {
+ UErrorCode ec = U_ZERO_ERROR;
+ digits->mult(ten,ec);
+ }
+ }
+ }
+
// Negative zero special case:
// if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
// if not parsing integerOnly, leave as -0, which a double can represent.
UBool tmpStatus[fgStatusLength];
ParsePosition tmpPos(origPos);
DigitList tmpDigitList;
+
+#ifdef FMT_DEBUG
+ debug("trying affix for currency..");
+ affixPtn->dump();
+#endif
+
UBool result = subparse(text,
&affixPtn->negPrefixPatternForCurrency,
&affixPtn->negSuffixPatternForCurrency,
// and the parse stops at "\u00A4".
// We will just use simple affix comparison (look for exact match)
// to pass it.
+ //
+ // TODO: We should parse against simple affix first when
+ // output currency is not requested. After the complex currency
+ // parsing implementation was introduced, the default currency
+ // instance parsing slowed down because of the new code flow.
+ // I filed #10312 - Yoshito
UBool tmpStatus_2[fgStatusLength];
ParsePosition tmpPos_2(origPos);
DigitList tmpDigitList_2;
- // set currencySignCount to 0 so that compareAffix function will
- // fall to compareSimpleAffix path, not compareComplexAffix path.
- // ?? TODO: is it right? need "false"?
+
+ // Disable complex currency parsing and try it again.
UBool result = subparse(text,
&fNegativePrefix, &fNegativeSuffix,
&fPositivePrefix, &fPositiveSuffix,
- FALSE, UCURR_SYMBOL_NAME,
+ FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME,
tmpPos_2, tmpDigitList_2, tmpStatus_2,
currency);
if (result) {
* @param negSuffix negative suffix.
* @param posPrefix positive prefix.
* @param posSuffix positive suffix.
- * @param currencyParsing whether it is currency parsing or not.
+ * @param complexCurrencyParsing whether it is complex currency parsing or not.
* @param type the currency type to parse against, LONG_NAME only or not.
* @param parsePosition The position at which to being parsing. Upon
* return, the first unparsed character.
const UnicodeString* negSuffix,
const UnicodeString* posPrefix,
const UnicodeString* posSuffix,
- UBool currencyParsing,
+ UBool complexCurrencyParsing,
int8_t type,
ParsePosition& parsePosition,
DigitList& digits, UBool* status,
int32_t position = parsePosition.getIndex();
int32_t oldStart = position;
+ int32_t textLength = text.length(); // One less pointer to follow
UBool strictParse = !isLenient();
+ UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
+ const UnicodeString *groupingString = &getConstSymbol(fCurrencySignCount == fgCurrencySignCountZero ?
+ DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
+ UChar32 groupingChar = groupingString->char32At(0);
+ int32_t groupingStringLength = groupingString->length();
+ int32_t groupingCharLength = U16_LENGTH(groupingChar);
+ UBool groupingUsed = isGroupingUsed();
+#ifdef FMT_DEBUG
+ UChar dbgbuf[300];
+ UnicodeString s(dbgbuf,0,300);;
+ s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " );
+#define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "=")); if(x->isEmpty()) { s.append(UnicodeString("<empty>")); } else { s.append(*x); } s.append(UnicodeString(" ")); } else { s.append(UnicodeString(#x "=NULL ")); }
+ DBGAPPD(negPrefix);
+ DBGAPPD(negSuffix);
+ DBGAPPD(posPrefix);
+ DBGAPPD(posSuffix);
+ debugout(s);
+ printf("currencyParsing=%d, fFormatWidth=%d, isParseIntegerOnly=%c text.length=%d negPrefLen=%d\n", currencyParsing, fFormatWidth, (isParseIntegerOnly())?'Y':'N', text.length(), negPrefix!=NULL?negPrefix->length():-1);
+#endif
+
+ UBool fastParseOk = false; /* TRUE iff fast parse is OK */
+ // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */
+ const DecimalFormatInternal &data = internalData(fReserved);
+ if((data.fFastParseStatus==kFastpathYES) &&
+ fCurrencySignCount == fgCurrencySignCountZero &&
+ // (negPrefix!=NULL&&negPrefix->isEmpty()) ||
+ text.length()>0 &&
+ text.length()<32 &&
+ (posPrefix==NULL||posPrefix->isEmpty()) &&
+ (posSuffix==NULL||posSuffix->isEmpty()) &&
+ // (negPrefix==NULL||negPrefix->isEmpty()) &&
+ // (negSuffix==NULL||(negSuffix->isEmpty()) ) &&
+ TRUE) { // optimized path
+ int j=position;
+ int l=text.length();
+ int digitCount=0;
+ UChar32 ch = text.char32At(j);
+ const UnicodeString *decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ UChar32 decimalChar = 0;
+ UBool intOnly = FALSE;
+ UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0;
+
+ int32_t decimalCount = decimalString->countChar32(0,3);
+ if(isParseIntegerOnly()) {
+ decimalChar = 0; // not allowed
+ intOnly = TRUE; // Don't look for decimals.
+ } else if(decimalCount==1) {
+ decimalChar = decimalString->char32At(0); // Look for this decimal
+ } else if(decimalCount==0) {
+ decimalChar=0; // NO decimal set
+ } else {
+ j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation.
+ }
+
+#ifdef FMT_DEBUG
+ printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n",
+ decimalChar, groupingChar, ch,
+ (intOnly)?'y':'n',
+ (strictParse)?'y':'n');
+#endif
+ if(ch==0x002D) { // '-'
+ j=l+1;//=break - negative number.
+
+ /*
+ parsedNum.append('-',err);
+ j+=U16_LENGTH(ch);
+ if(j<l) ch = text.char32At(j);
+ */
+ } else {
+ parsedNum.append('+',err);
+ }
+ while(j<l) {
+ int32_t digit = ch - zero;
+ if(digit >=0 && digit <= 9) {
+ parsedNum.append((char)(digit + '0'), err);
+ if((digitCount>0) || digit!=0 || j==(l-1)) {
+ digitCount++;
+ }
+ } else if(ch == 0) { // break out
+ digitCount=-1;
+ break;
+ } else if(ch == decimalChar) {
+ parsedNum.append((char)('.'), err);
+ decimalChar=0; // no more decimals.
+ // fastParseHadDecimal=TRUE;
+ } else if(ch == lookForGroup) {
+ // ignore grouping char. No decimals, so it has to be an ignorable grouping sep
+ } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) {
+ // parsing integer only and can fall through
+ } else {
+ digitCount=-1; // fail - fall through to slow parse
+ break;
+ }
+ j+=U16_LENGTH(ch);
+ ch = text.char32At(j); // for next
+ }
+ if(
+ ((j==l)||intOnly) // end OR only parsing integer
+ && (digitCount>0)) { // and have at least one digit
+#ifdef FMT_DEBUG
+ printf("PP -> %d, good = [%s] digitcount=%d, fGroupingSize=%d fGroupingSize2=%d!\n", j, parsedNum.data(), digitCount, fGroupingSize, fGroupingSize2);
+#endif
+ fastParseOk=true; // Fast parse OK!
+#ifdef SKIP_OPT
+ debug("SKIP_OPT");
+ /* for testing, try it the slow way. also */
+ fastParseOk=false;
+ parsedNum.clear();
+#else
+ parsePosition.setIndex(position=j);
+ status[fgStatusInfinite]=false;
+#endif
+ } else {
+ // was not OK. reset, retry
+#ifdef FMT_DEBUG
+ printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount);
+#endif
+ parsedNum.clear();
+ }
+ } else {
+#ifdef FMT_DEBUG
+ printf("Could not fastpath parse. ");
+ printf("fFormatWidth=%d ", fFormatWidth);
+ printf("text.length()=%d ", text.length());
+ printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix);
+
+ printf("\n");
+#endif
+ }
+
+ if(!fastParseOk
+#if UCONFIG_HAVE_PARSEALLINPUT
+ && fParseAllInput!=UNUM_YES
+#endif
+ )
+ {
// Match padding before prefix
if (fFormatWidth > 0 && fPadPosition == kPadBeforePrefix) {
position = skipPadding(text, position);
}
// Match positive and negative prefixes; prefer longest match.
- int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, currencyParsing, type, currency);
- int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, currencyParsing, type, currency);
+ int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency);
+ int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, complexCurrencyParsing, type, currency);
if (posMatch >= 0 && negMatch >= 0) {
if (posMatch > negMatch) {
negMatch = -1;
// put only significant digits into the DigitList, and adjust the
// exponent as needed.
- UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
UBool strictFail = FALSE; // did we exit with a strict parse failure?
int32_t lastGroup = -1; // where did we last see a grouping separator?
int32_t gs2 = fGroupingSize2 == 0 ? fGroupingSize : fGroupingSize2;
const UnicodeString *decimalString;
- if (fCurrencySignCount > fgCurrencySignCountZero) {
+ if (fCurrencySignCount != fgCurrencySignCountZero) {
decimalString = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
} else {
decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
}
UChar32 decimalChar = decimalString->char32At(0);
+ int32_t decimalStringLength = decimalString->length();
+ int32_t decimalCharLength = U16_LENGTH(decimalChar);
- const UnicodeString *groupingString = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
- UChar32 groupingChar = groupingString->char32At(0);
UBool sawDecimal = FALSE;
UChar32 sawDecimalChar = 0xFFFF;
UBool sawGrouping = FALSE;
UBool sawDigit = FALSE;
int32_t backup = -1;
int32_t digit;
- int32_t textLength = text.length(); // One less pointer to follow
- int32_t decimalStringLength = decimalString->length();
- int32_t decimalCharLength = U16_LENGTH(decimalChar);
- int32_t groupingStringLength = groupingString->length();
- int32_t groupingCharLength = U16_LENGTH(groupingChar);
// equivalent grouping and decimal support
const UnicodeSet *decimalSet = NULL;
if (groupingCharLength == groupingStringLength) {
if (strictParse) {
- groupingSet = DecimalFormatStaticSets::gStaticSets->fStrictDefaultGroupingSeparators;
+ groupingSet = fStaticSets->fStrictDefaultGroupingSeparators;
} else {
- groupingSet = DecimalFormatStaticSets::gStaticSets->fDefaultGroupingSeparators;
+ groupingSet = fStaticSets->fDefaultGroupingSeparators;
}
}
else if (groupingStringLength > 0 &&
matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet,
decimalChar, decimalSet,
- ch) && isGroupingUsed())
+ ch) && groupingUsed)
{
if (sawDecimal) {
break;
// decimalSet is considered to consist of (ch,ch)
}
else {
- const UnicodeString *tmp;
- tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
- if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit
- {
- // Parse sign, if present
- int32_t pos = position + tmp->length();
- char exponentSign = '+';
- if (pos < textLength)
+ if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless..
+ isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways
+ const UnicodeString *tmp;
+ tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
+ // TODO: CASE
+ if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit
{
- tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
+ // Parse sign, if present
+ int32_t pos = position + tmp->length();
+ char exponentSign = '+';
+
+ if (pos < textLength)
{
- pos += tmp->length();
- }
- else {
- tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
if (!text.compare(pos, tmp->length(), *tmp))
{
- exponentSign = '-';
pos += tmp->length();
}
+ else {
+ tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ if (!text.compare(pos, tmp->length(), *tmp))
+ {
+ exponentSign = '-';
+ pos += tmp->length();
+ }
+ }
}
- }
- UBool sawExponentDigit = FALSE;
- while (pos < textLength) {
- ch = text[(int32_t)pos];
- digit = ch - zero;
+ UBool sawExponentDigit = FALSE;
+ while (pos < textLength) {
+ ch = text[(int32_t)pos];
+ digit = ch - zero;
- if (digit < 0 || digit > 9) {
- digit = u_charDigitValue(ch);
- }
- if (0 <= digit && digit <= 9) {
- if (!sawExponentDigit) {
- parsedNum.append('E', err);
- parsedNum.append(exponentSign, err);
- sawExponentDigit = TRUE;
+ if (digit < 0 || digit > 9) {
+ digit = u_charDigitValue(ch);
+ }
+ if (0 <= digit && digit <= 9) {
+ if (!sawExponentDigit) {
+ parsedNum.append('E', err);
+ parsedNum.append(exponentSign, err);
+ sawExponentDigit = TRUE;
+ }
+ ++pos;
+ parsedNum.append((char)(digit + '0'), err);
+ } else {
+ break;
}
- ++pos;
- parsedNum.append((char)(digit + '0'), err);
- } else {
- break;
}
- }
- if (sawExponentDigit) {
- position = pos; // Advance past the exponent
- }
+ if (sawExponentDigit) {
+ position = pos; // Advance past the exponent
+ }
- break; // Whether we fail or succeed, we exit this loop
- }
- else {
+ break; // Whether we fail or succeed, we exit this loop
+ } else {
+ break;
+ }
+ } else { // not parsing exponent
break;
- }
+ }
}
}
parsePosition.setIndex(oldStart);
parsePosition.setErrorIndex(position);
+ debug("strictFail!");
return FALSE;
}
// parse "$" with pattern "$#0.00". (return index 0 and error index
// 1).
if (!sawDigit && digitCount == 0) {
+#ifdef FMT_DEBUG
+ debug("none of text rec");
+ printf("position=%d\n",position);
+#endif
parsePosition.setIndex(oldStart);
parsePosition.setErrorIndex(oldStart);
return FALSE;
// Match positive and negative suffixes; prefer longest match.
if (posMatch >= 0 || (!strictParse && negMatch < 0)) {
- posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currencyParsing, type, currency);
+ posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency);
}
if (negMatch >= 0) {
- negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currencyParsing, type, currency);
+ negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency);
}
if (posSuffixMatch >= 0 && negSuffixMatch >= 0) {
if (posSuffixMatch > negSuffixMatch) {
// Fail if neither or both
if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) {
parsePosition.setErrorIndex(position);
+ debug("neither or both");
return FALSE;
}
parsePosition.setIndex(position);
parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-';
-
- if(parsePosition.getIndex() == oldStart)
+#ifdef FMT_DEBUG
+printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err));
+#endif
+ } /* end SLOW parse */
+ if(parsePosition.getIndex() == oldStart)
{
+#ifdef FMT_DEBUG
+ printf(" PP didnt move, err\n");
+#endif
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+#if UCONFIG_HAVE_PARSEALLINPUT
+ else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength)
+ {
+#ifdef FMT_DEBUG
+ printf(" PP didnt consume all (UNUM_YES), err\n");
+#endif
parsePosition.setErrorIndex(position);
return FALSE;
}
- digits.set(parsedNum.toStringPiece(), err);
+#endif
+ // uint32_t bits = (fastParseOk?kFastpathOk:0) |
+ // (fastParseHadDecimal?0:kNoDecimal);
+ //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits);
+ digits.set(parsedNum.toStringPiece(),
+ err,
+ 0//bits
+ );
if (U_FAILURE(err)) {
+#ifdef FMT_DEBUG
+ printf(" err setting %s\n", u_errorName(err));
+#endif
parsePosition.setErrorIndex(position);
return FALSE;
}
* @param isNegative
* @param isPrefix
* @param affixPat affix pattern used for currency affix comparison.
- * @param currencyParsing whether it is currency parsing or not
+ * @param complexCurrencyParsing whether it is currency parsing or not
* @param type the currency type to parse against, LONG_NAME only or not.
* @param currency return value for parsed currency, for generic
* currency parsing mode, or null for normal parsing. In generic
UBool isNegative,
UBool isPrefix,
const UnicodeString* affixPat,
- UBool currencyParsing,
+ UBool complexCurrencyParsing,
int8_t type,
UChar* currency) const
{
const UnicodeString *patternToCompare;
if (fCurrencyChoice != NULL || currency != NULL ||
- (fCurrencySignCount > fgCurrencySignCountZero && currencyParsing)) {
+ (fCurrencySignCount != fgCurrencySignCountZero && complexCurrencyParsing)) {
if (affixPat != NULL) {
return compareComplexAffix(*affixPat, text, pos, type, currency);
return compareSimpleAffix(*patternToCompare, text, pos, isLenient());
}
+UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const {
+ if (lhs == rhs) {
+ return TRUE;
+ }
+ U_ASSERT(fStaticSets != NULL); // should already be loaded
+ const UnicodeSet *minusSigns = fStaticSets->fMinusSigns;
+ const UnicodeSet *plusSigns = fStaticSets->fPlusSigns;
+ return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) ||
+ (plusSigns->contains(lhs) && plusSigns->contains(rhs));
+}
+
+// check for LRM 0x200E, RLM 0x200F, ALM 0x061C
+#define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C)
+
+#define TRIM_BUFLEN 32
+UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) {
+ UChar trimBuf[TRIM_BUFLEN];
+ int32_t affixLen = affix.length();
+ int32_t affixPos, trimLen = 0;
+
+ for (affixPos = 0; affixPos < affixLen; affixPos++) {
+ UChar c = affix.charAt(affixPos);
+ if (!IS_BIDI_MARK(c)) {
+ if (trimLen < TRIM_BUFLEN) {
+ trimBuf[trimLen++] = c;
+ } else {
+ trimLen = 0;
+ break;
+ }
+ }
+ }
+ return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix);
+}
+
/**
* Return the length matched by the given affix, or -1 if none.
* Runs of white space in the affix, match runs of white space in
int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
const UnicodeString& input,
int32_t pos,
- UBool lenient) {
- UErrorCode status = U_ZERO_ERROR;
+ UBool lenient) const {
int32_t start = pos;
- UChar32 affixChar = affix.char32At(0);
- int32_t affixLength = affix.length();
+ UnicodeString trimmedAffix;
+ // For more efficiency we should keep lazily-created trimmed affixes around in
+ // instance variables instead of trimming each time they are used (the next step)
+ trimMarksFromAffix(affix, trimmedAffix);
+ UChar32 affixChar = trimmedAffix.char32At(0);
+ int32_t affixLength = trimmedAffix.length();
int32_t inputLength = input.length();
int32_t affixCharLength = U16_LENGTH(affixChar);
UnicodeSet *affixSet;
+ UErrorCode status = U_ZERO_ERROR;
- DecimalFormatStaticSets::initSets(&status);
+ U_ASSERT(fStaticSets != NULL); // should already be loaded
+ if (U_FAILURE(status)) {
+ return -1;
+ }
if (!lenient) {
- affixSet = DecimalFormatStaticSets::gStaticSets->fStrictDashEquivalents;
-
- // If the affix is exactly one character long and that character
+ affixSet = fStaticSets->fStrictDashEquivalents;
+
+ // If the trimmedAffix is exactly one character long and that character
// is in the dash set and the very next input character is also
// in the dash set, return a match.
if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
- if (affixSet->contains(input.char32At(pos))) {
- return 1;
+ UChar32 ic = input.char32At(pos);
+ if (affixSet->contains(ic)) {
+ pos += U16_LENGTH(ic);
+ pos = skipBidiMarks(input, pos); // skip any trailing bidi marks
+ return pos - start;
}
}
for (int32_t i = 0; i < affixLength; ) {
- UChar32 c = affix.char32At(i);
+ UChar32 c = trimmedAffix.char32At(i);
int32_t len = U16_LENGTH(c);
if (PatternProps::isWhiteSpace(c)) {
// We may have a pattern like: \u200F \u0020
// match of the run of Pattern_White_Space in the pattern,
// then match any extra characters.
UBool literalMatch = FALSE;
- while (pos < inputLength &&
- input.char32At(pos) == c) {
- literalMatch = TRUE;
- i += len;
- pos += len;
- if (i == affixLength) {
- break;
- }
- c = affix.char32At(i);
- len = U16_LENGTH(c);
- if (!PatternProps::isWhiteSpace(c)) {
+ while (pos < inputLength) {
+ UChar32 ic = input.char32At(pos);
+ if (ic == c) {
+ literalMatch = TRUE;
+ i += len;
+ pos += len;
+ if (i == affixLength) {
+ break;
+ }
+ c = trimmedAffix.char32At(i);
+ len = U16_LENGTH(c);
+ if (!PatternProps::isWhiteSpace(c)) {
+ break;
+ }
+ } else if (IS_BIDI_MARK(ic)) {
+ pos ++; // just skip over this input text
+ } else {
break;
}
}
// Advance over run in pattern
- i = skipPatternWhiteSpace(affix, i);
+ i = skipPatternWhiteSpace(trimmedAffix, i);
// Advance over run in input text
// Must see at least one white space char in input,
// If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
// Otherwise, the previous lines may have skipped over text (such as U+00A0) that
- // is also in the affix.
- i = skipUWhiteSpace(affix, i);
+ // is also in the trimmedAffix.
+ i = skipUWhiteSpace(trimmedAffix, i);
} else {
- if (pos < inputLength &&
- input.char32At(pos) == c) {
- i += len;
- pos += len;
- } else {
+ UBool match = FALSE;
+ while (pos < inputLength) {
+ UChar32 ic = input.char32At(pos);
+ if (!match && ic == c) {
+ i += len;
+ pos += len;
+ match = TRUE;
+ } else if (IS_BIDI_MARK(ic)) {
+ pos++; // just skip over this input text
+ } else {
+ break;
+ }
+ }
+ if (!match) {
return -1;
}
}
}
} else {
UBool match = FALSE;
-
- affixSet = DecimalFormatStaticSets::gStaticSets->fDashEquivalents;
+
+ affixSet = fStaticSets->fDashEquivalents;
if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
- pos = skipUWhiteSpace(input, pos);
-
- if (affixSet->contains(input.char32At(pos))) {
- return pos - start + 1;
+ pos = skipUWhiteSpaceAndMarks(input, pos);
+ UChar32 ic = input.char32At(pos);
+
+ if (affixSet->contains(ic)) {
+ pos += U16_LENGTH(ic);
+ pos = skipBidiMarks(input, pos);
+ return pos - start;
}
}
for (int32_t i = 0; i < affixLength; )
{
- //i = skipRuleWhiteSpace(affix, i);
- i = skipUWhiteSpace(affix, i);
- pos = skipUWhiteSpace(input, pos);
+ //i = skipRuleWhiteSpace(trimmedAffix, i);
+ i = skipUWhiteSpace(trimmedAffix, i);
+ pos = skipUWhiteSpaceAndMarks(input, pos);
if (i >= affixLength || pos >= inputLength) {
break;
}
- UChar32 c = affix.char32At(i);
- int32_t len = U16_LENGTH(c);
+ UChar32 c = trimmedAffix.char32At(i);
+ UChar32 ic = input.char32At(pos);
- if (input.char32At(pos) != c) {
+ if (!equalWithSignCompatibility(ic, c)) {
return -1;
}
match = TRUE;
- i += len;
- pos += len;
+ i += U16_LENGTH(c);
+ pos += U16_LENGTH(ic);
+ pos = skipBidiMarks(input, pos);
}
if (affixLength > 0 && ! match) {
return pos;
}
+/**
+ * Skip over a run of zero or more isUWhiteSpace() characters or bidi marks at pos
+ * in text.
+ */
+int32_t DecimalFormat::skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos) {
+ while (pos < text.length()) {
+ UChar32 c = text.char32At(pos);
+ if (!u_isUWhiteSpace(c) && !IS_BIDI_MARK(c)) { // u_isUWhiteSpace doesn't include LRM,RLM,ALM
+ break;
+ }
+ pos += U16_LENGTH(c);
+ }
+ return pos;
+}
+
+/**
+ * Skip over a run of zero or more bidi marks at pos in text.
+ */
+int32_t DecimalFormat::skipBidiMarks(const UnicodeString& text, int32_t pos) {
+ while (pos < text.length()) {
+ UChar c = text.charAt(pos);
+ if (!IS_BIDI_MARK(c)) {
+ break;
+ }
+ pos++;
+ }
+ return pos;
+}
+
/**
* Return the length matched by the given affix, or -1 if none.
* @param affixPat pattern string
int32_t start = pos;
U_ASSERT(currency != NULL ||
(fCurrencyChoice != NULL && *getCurrency() != 0) ||
- fCurrencySignCount > fgCurrencySignCountZero);
+ fCurrencySignCount != fgCurrencySignCountZero);
for (int32_t i=0;
i<affixPat.length() && pos >= 0; ) {
UChar effectiveCurr[4];
getEffectiveCurrency(effectiveCurr, ec);
if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) {
- pos = -1;
- continue;
+ pos = -1;
+ continue;
}
}
pos = ppos.getIndex();
setCurrencyForSymbols();
}
expandAffixes(NULL);
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
// Setting the symbols is equlivalent to adopting a newly created localized
DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
{
adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
delete fCurrencyPluralInfo;
fCurrencyPluralInfo = toAdopt;
// re-set currency affix patterns and currency affixes.
- if (fCurrencySignCount > fgCurrencySignCountZero) {
+ if (fCurrencySignCount != fgCurrencySignCountZero) {
UErrorCode status = U_ZERO_ERROR;
if (fAffixPatternsForCurrency) {
deleteHashForAffixPattern();
}
}
}
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
void
DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info)
{
adoptCurrencyPluralInfo(info.clone());
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
}
ec = U_ZERO_ERROR; // reset local error code!
setCurrencyInternally(c, ec);
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
fPositivePrefix = newValue;
delete fPosPrefixPattern;
fPosPrefixPattern = 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
fNegativePrefix = newValue;
delete fNegPrefixPattern;
fNegPrefixPattern = 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
fPositiveSuffix = newValue;
delete fPosSuffixPattern;
fPosSuffixPattern = 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
fNegativeSuffix = newValue;
delete fNegSuffixPattern;
fNegSuffixPattern = 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
fMultiplier->set(newValue);
}
}
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
// or fRoundingIncrement could not be created.
delete fRoundingIncrement;
fRoundingIncrement = NULL;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
*/
void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
fRoundingMode = roundingMode;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
*/
void DecimalFormat::setFormatWidth(int32_t width) {
fFormatWidth = (width > 0) ? width : 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
UnicodeString DecimalFormat::getPadCharacterString() const {
else {
fPad = kDefaultPad;
}
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
*/
void DecimalFormat::setPadPosition(EPadPosition padPos) {
fPadPosition = padPos;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
* @see #isExponentSignAlwaysShown
* @see #setExponentSignAlwaysShown
*/
-UBool DecimalFormat::isScientificNotation() {
+UBool DecimalFormat::isScientificNotation() const {
return fUseExponentialNotation;
}
*/
void DecimalFormat::setScientificNotation(UBool useScientific) {
fUseExponentialNotation = useScientific;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
*/
void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
fMinExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1);
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
* @see #getMinimumExponentDigits
* @see #setExponentSignAlwaysShown
*/
-UBool DecimalFormat::isExponentSignAlwaysShown() {
+UBool DecimalFormat::isExponentSignAlwaysShown() const {
return fExponentSignAlwaysShown;
}
*/
void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
fExponentSignAlwaysShown = expSignAlways;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
int32_t
DecimalFormat::getGroupingSize() const
{
- return fGroupingSize;
+ return isGroupingUsed() ? fGroupingSize : 0;
}
//------------------------------------------------------------------------------
DecimalFormat::setGroupingSize(int32_t newValue)
{
fGroupingSize = newValue;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
DecimalFormat::setSecondaryGroupingSize(int32_t newValue)
{
fGroupingSize2 = newValue;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue)
{
fDecimalSeparatorAlwaysShown = newValue;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
}
#ifdef FMT_DEBUG
UnicodeString s;
- s.append("[")
- .append(*fPosPrefixPattern).append("|").append(*fPosSuffixPattern)
- .append(";") .append(*fNegPrefixPattern).append("|").append(*fNegSuffixPattern)
- .append("]->[")
- .append(fPositivePrefix).append("|").append(fPositiveSuffix)
- .append(";") .append(fNegativePrefix).append("|").append(fNegativeSuffix)
- .append("]\n");
+ s.append(UnicodeString("["))
+ .append(DEREFSTR(fPosPrefixPattern)).append((UnicodeString)"|").append(DEREFSTR(fPosSuffixPattern))
+ .append((UnicodeString)";") .append(DEREFSTR(fNegPrefixPattern)).append((UnicodeString)"|").append(DEREFSTR(fNegSuffixPattern))
+ .append((UnicodeString)"]->[")
+ .append(fPositivePrefix).append((UnicodeString)"|").append(fPositiveSuffix)
+ .append((UnicodeString)";") .append(fNegativePrefix).append((UnicodeString)"|").append(fNegativeSuffix)
+ .append((UnicodeString)"]\n");
debugout(s);
#endif
}
const UnicodeString* affix;
if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) {
- UnicodeString pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number);
+ // TODO: get an accurate count of visible fraction digits.
+ UnicodeString pluralCount;
+ int32_t minFractionDigits = this->getMinimumFractionDigits();
+ if (minFractionDigits > 0) {
+ FixedDecimal ni(number, this->getMinimumFractionDigits());
+ pluralCount = fCurrencyPluralInfo->getPluralRules()->select(ni);
+ } else {
+ pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number);
+ }
AffixesForCurrency* oneSet;
if (fStyle == UNUM_CURRENCY_PLURAL) {
oneSet = (AffixesForCurrency*)fPluralAffixesForCurrency->get(pluralCount);
{
return;
}
- // Clear error struct
- parseError.offset = -1;
- parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
-
- // Set the significant pattern symbols
- UChar32 zeroDigit = kPatternZeroDigit; // '0'
- UChar32 sigDigit = kPatternSignificantDigit; // '@'
- UnicodeString groupingSeparator ((UChar)kPatternGroupingSeparator);
- UnicodeString decimalSeparator ((UChar)kPatternDecimalSeparator);
- UnicodeString percent ((UChar)kPatternPercent);
- UnicodeString perMill ((UChar)kPatternPerMill);
- UnicodeString digit ((UChar)kPatternDigit); // '#'
- UnicodeString separator ((UChar)kPatternSeparator);
- UnicodeString exponent ((UChar)kPatternExponent);
- UnicodeString plus ((UChar)kPatternPlus);
- UnicodeString minus ((UChar)kPatternMinus);
- UnicodeString padEscape ((UChar)kPatternPadEscape);
- // Substitute with the localized symbols if necessary
+ DecimalFormatPatternParser patternParser;
if (localized) {
- zeroDigit = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
- sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
- groupingSeparator. remove().append(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
- decimalSeparator. remove().append(getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
- percent. remove().append(getConstSymbol(DecimalFormatSymbols::kPercentSymbol));
- perMill. remove().append(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol));
- digit. remove().append(getConstSymbol(DecimalFormatSymbols::kDigitSymbol));
- separator. remove().append(getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol));
- exponent. remove().append(getConstSymbol(DecimalFormatSymbols::kExponentialSymbol));
- plus. remove().append(getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol));
- minus. remove().append(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol));
- padEscape. remove().append(getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol));
- }
- UChar nineDigit = (UChar)(zeroDigit + 9);
- int32_t digitLen = digit.length();
- int32_t groupSepLen = groupingSeparator.length();
- int32_t decimalSepLen = decimalSeparator.length();
-
- int32_t pos = 0;
- int32_t patLen = pattern.length();
- // Part 0 is the positive pattern. Part 1, if present, is the negative
- // pattern.
- for (int32_t part=0; part<2 && pos<patLen; ++part) {
- // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
- // 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is
- // between the prefix and suffix, and consists of pattern
- // characters. In the prefix and suffix, percent, perMill, and
- // currency symbols are recognized and translated.
- int32_t subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0;
-
- // It's important that we don't change any fields of this object
- // prematurely. We set the following variables for the multiplier,
- // grouping, etc., and then only change the actual object fields if
- // everything parses correctly. This also lets us register
- // the data from part 0 and ignore the part 1, except for the
- // prefix and suffix.
- UnicodeString prefix;
- UnicodeString suffix;
- int32_t decimalPos = -1;
- int32_t multiplier = 1;
- int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
- int8_t groupingCount = -1;
- int8_t groupingCount2 = -1;
- int32_t padPos = -1;
- UChar32 padChar = 0;
- int32_t roundingPos = -1;
- DigitList roundingInc;
- int8_t expDigits = -1;
- UBool expSignAlways = FALSE;
-
- // The affix is either the prefix or the suffix.
- UnicodeString* affix = &prefix;
-
- int32_t start = pos;
- UBool isPartDone = FALSE;
- UChar32 ch;
-
- for (; !isPartDone && pos < patLen; ) {
- // Todo: account for surrogate pairs
- ch = pattern.char32At(pos);
- switch (subpart) {
- case 0: // Pattern proper subpart (between prefix & suffix)
- // Process the digits, decimal, and grouping characters. We
- // record five pieces of information. We expect the digits
- // to occur in the pattern ####00.00####, and we record the
- // number of left digits, zero (central) digits, and right
- // digits. The position of the last grouping character is
- // recorded (should be somewhere within the first two blocks
- // of characters), as is the position of the decimal point,
- // if any (should be in the zero digits). If there is no
- // decimal point, then there should be no right digits.
- if (pattern.compare(pos, digitLen, digit) == 0) {
- if (zeroDigitCount > 0 || sigDigitCount > 0) {
- ++digitRightCount;
- } else {
- ++digitLeftCount;
- }
- if (groupingCount >= 0 && decimalPos < 0) {
- ++groupingCount;
- }
- pos += digitLen;
- } else if ((ch >= zeroDigit && ch <= nineDigit) ||
- ch == sigDigit) {
- if (digitRightCount > 0) {
- // Unexpected '0'
- debug("Unexpected '0'")
- status = U_UNEXPECTED_TOKEN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- if (ch == sigDigit) {
- ++sigDigitCount;
- } else {
- if (ch != zeroDigit && roundingPos < 0) {
- roundingPos = digitLeftCount + zeroDigitCount;
- }
- if (roundingPos >= 0) {
- roundingInc.append((char)(ch - zeroDigit + '0'));
- }
- ++zeroDigitCount;
- }
- if (groupingCount >= 0 && decimalPos < 0) {
- ++groupingCount;
- }
- pos += U16_LENGTH(ch);
- } else if (pattern.compare(pos, groupSepLen, groupingSeparator) == 0) {
- if (decimalPos >= 0) {
- // Grouping separator after decimal
- debug("Grouping separator after decimal")
- status = U_UNEXPECTED_TOKEN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- groupingCount2 = groupingCount;
- groupingCount = 0;
- pos += groupSepLen;
- } else if (pattern.compare(pos, decimalSepLen, decimalSeparator) == 0) {
- if (decimalPos >= 0) {
- // Multiple decimal separators
- debug("Multiple decimal separators")
- status = U_MULTIPLE_DECIMAL_SEPARATORS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- // Intentionally incorporate the digitRightCount,
- // even though it is illegal for this to be > 0
- // at this point. We check pattern syntax below.
- decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
- pos += decimalSepLen;
- } else {
- if (pattern.compare(pos, exponent.length(), exponent) == 0) {
- if (expDigits >= 0) {
- // Multiple exponential symbols
- debug("Multiple exponential symbols")
- status = U_MULTIPLE_EXPONENTIAL_SYMBOLS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- if (groupingCount >= 0) {
- // Grouping separator in exponential pattern
- debug("Grouping separator in exponential pattern")
- status = U_MALFORMED_EXPONENTIAL_PATTERN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- pos += exponent.length();
- // Check for positive prefix
- if (pos < patLen
- && pattern.compare(pos, plus.length(), plus) == 0) {
- expSignAlways = TRUE;
- pos += plus.length();
- }
- // Use lookahead to parse out the exponential part of the
- // pattern, then jump into suffix subpart.
- expDigits = 0;
- while (pos < patLen &&
- pattern.char32At(pos) == zeroDigit) {
- ++expDigits;
- pos += U16_LENGTH(zeroDigit);
- }
-
- // 1. Require at least one mantissa pattern digit
- // 2. Disallow "#+ @" in mantissa
- // 3. Require at least one exponent pattern digit
- if (((digitLeftCount + zeroDigitCount) < 1 &&
- (sigDigitCount + digitRightCount) < 1) ||
- (sigDigitCount > 0 && digitLeftCount > 0) ||
- expDigits < 1) {
- // Malformed exponential pattern
- debug("Malformed exponential pattern")
- status = U_MALFORMED_EXPONENTIAL_PATTERN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- }
- // Transition to suffix subpart
- subpart = 2; // suffix subpart
- affix = &suffix;
- sub0Limit = pos;
- continue;
- }
- break;
- case 1: // Prefix subpart
- case 2: // Suffix subpart
- // Process the prefix / suffix characters
- // Process unquoted characters seen in prefix or suffix
- // subpart.
-
- // Several syntax characters implicitly begins the
- // next subpart if we are in the prefix; otherwise
- // they are illegal if unquoted.
- if (!pattern.compare(pos, digitLen, digit) ||
- !pattern.compare(pos, groupSepLen, groupingSeparator) ||
- !pattern.compare(pos, decimalSepLen, decimalSeparator) ||
- (ch >= zeroDigit && ch <= nineDigit) ||
- ch == sigDigit) {
- if (subpart == 1) { // prefix subpart
- subpart = 0; // pattern proper subpart
- sub0Start = pos; // Reprocess this character
- continue;
- } else {
- status = U_UNQUOTED_SPECIAL;
- syntaxError(pattern,pos,parseError);
- return;
- }
- } else if (ch == kCurrencySign) {
- affix->append(kQuote); // Encode currency
- // Use lookahead to determine if the currency sign is
- // doubled or not.
- U_ASSERT(U16_LENGTH(kCurrencySign) == 1);
- if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) {
- affix->append(kCurrencySign);
- ++pos; // Skip over the doubled character
- if ((pos+1) < pattern.length() &&
- pattern[pos+1] == kCurrencySign) {
- affix->append(kCurrencySign);
- ++pos; // Skip over the doubled character
- fCurrencySignCount = fgCurrencySignCountInPluralFormat;
- } else {
- fCurrencySignCount = fgCurrencySignCountInISOFormat;
- }
- } else {
- fCurrencySignCount = fgCurrencySignCountInSymbolFormat;
- }
- // Fall through to append(ch)
- } else if (ch == kQuote) {
- // A quote outside quotes indicates either the opening
- // quote or two quotes, which is a quote literal. That is,
- // we have the first quote in 'do' or o''clock.
- U_ASSERT(U16_LENGTH(kQuote) == 1);
- ++pos;
- if (pos < pattern.length() && pattern[pos] == kQuote) {
- affix->append(kQuote); // Encode quote
- // Fall through to append(ch)
- } else {
- subpart += 2; // open quote
- continue;
- }
- } else if (pattern.compare(pos, separator.length(), separator) == 0) {
- // Don't allow separators in the prefix, and don't allow
- // separators in the second pattern (part == 1).
- if (subpart == 1 || part == 1) {
- // Unexpected separator
- debug("Unexpected separator")
- status = U_UNEXPECTED_TOKEN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- sub2Limit = pos;
- isPartDone = TRUE; // Go to next part
- pos += separator.length();
- break;
- } else if (pattern.compare(pos, percent.length(), percent) == 0) {
- // Next handle characters which are appended directly.
- if (multiplier != 1) {
- // Too many percent/perMill characters
- debug("Too many percent characters")
- status = U_MULTIPLE_PERCENT_SYMBOLS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- affix->append(kQuote); // Encode percent/perMill
- affix->append(kPatternPercent); // Use unlocalized pattern char
- multiplier = 100;
- pos += percent.length();
- break;
- } else if (pattern.compare(pos, perMill.length(), perMill) == 0) {
- // Next handle characters which are appended directly.
- if (multiplier != 1) {
- // Too many percent/perMill characters
- debug("Too many perMill characters")
- status = U_MULTIPLE_PERMILL_SYMBOLS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- affix->append(kQuote); // Encode percent/perMill
- affix->append(kPatternPerMill); // Use unlocalized pattern char
- multiplier = 1000;
- pos += perMill.length();
- break;
- } else if (pattern.compare(pos, padEscape.length(), padEscape) == 0) {
- if (padPos >= 0 || // Multiple pad specifiers
- (pos+1) == pattern.length()) { // Nothing after padEscape
- debug("Multiple pad specifiers")
- status = U_MULTIPLE_PAD_SPECIFIERS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- padPos = pos;
- pos += padEscape.length();
- padChar = pattern.char32At(pos);
- pos += U16_LENGTH(padChar);
- break;
- } else if (pattern.compare(pos, minus.length(), minus) == 0) {
- affix->append(kQuote); // Encode minus
- affix->append(kPatternMinus);
- pos += minus.length();
- break;
- } else if (pattern.compare(pos, plus.length(), plus) == 0) {
- affix->append(kQuote); // Encode plus
- affix->append(kPatternPlus);
- pos += plus.length();
- break;
- }
- // Unquoted, non-special characters fall through to here, as
- // well as other code which needs to append something to the
- // affix.
- affix->append(ch);
- pos += U16_LENGTH(ch);
- break;
- case 3: // Prefix subpart, in quote
- case 4: // Suffix subpart, in quote
- // A quote within quotes indicates either the closing
- // quote or two quotes, which is a quote literal. That is,
- // we have the second quote in 'do' or 'don''t'.
- if (ch == kQuote) {
- ++pos;
- if (pos < pattern.length() && pattern[pos] == kQuote) {
- affix->append(kQuote); // Encode quote
- // Fall through to append(ch)
- } else {
- subpart -= 2; // close quote
- continue;
- }
- }
- affix->append(ch);
- pos += U16_LENGTH(ch);
- break;
- }
- }
-
- if (sub0Limit == 0) {
- sub0Limit = pattern.length();
- }
-
- if (sub2Limit == 0) {
- sub2Limit = pattern.length();
- }
-
- /* Handle patterns with no '0' pattern character. These patterns
- * are legal, but must be recodified to make sense. "##.###" ->
- * "#0.###". ".###" -> ".0##".
- *
- * We allow patterns of the form "####" to produce a zeroDigitCount
- * of zero (got that?); although this seems like it might make it
- * possible for format() to produce empty strings, format() checks
- * for this condition and outputs a zero digit in this situation.
- * Having a zeroDigitCount of zero yields a minimum integer digits
- * of zero, which allows proper round-trip patterns. We don't want
- * "#" to become "#0" when toPattern() is called (even though that's
- * what it really is, semantically).
- */
- if (zeroDigitCount == 0 && sigDigitCount == 0 &&
- digitLeftCount > 0 && decimalPos >= 0) {
- // Handle "###.###" and "###." and ".###"
- int n = decimalPos;
- if (n == 0)
- ++n; // Handle ".###"
- digitRightCount = digitLeftCount - n;
- digitLeftCount = n - 1;
- zeroDigitCount = 1;
- }
-
- // Do syntax checking on the digits, decimal points, and quotes.
- if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
- (decimalPos >= 0 &&
- (sigDigitCount > 0 ||
- decimalPos < digitLeftCount ||
- decimalPos > (digitLeftCount + zeroDigitCount))) ||
- groupingCount == 0 || groupingCount2 == 0 ||
- (sigDigitCount > 0 && zeroDigitCount > 0) ||
- subpart > 2)
- { // subpart > 2 == unmatched quote
- debug("Syntax error")
- status = U_PATTERN_SYNTAX_ERROR;
- syntaxError(pattern,pos,parseError);
- return;
- }
-
- // Make sure pad is at legal position before or after affix.
- if (padPos >= 0) {
- if (padPos == start) {
- padPos = kPadBeforePrefix;
- } else if (padPos+2 == sub0Start) {
- padPos = kPadAfterPrefix;
- } else if (padPos == sub0Limit) {
- padPos = kPadBeforeSuffix;
- } else if (padPos+2 == sub2Limit) {
- padPos = kPadAfterSuffix;
- } else {
- // Illegal pad position
- debug("Illegal pad position")
- status = U_ILLEGAL_PAD_POSITION;
- syntaxError(pattern,pos,parseError);
- return;
- }
- }
-
- if (part == 0) {
- delete fPosPrefixPattern;
- delete fPosSuffixPattern;
- delete fNegPrefixPattern;
- delete fNegSuffixPattern;
- fPosPrefixPattern = new UnicodeString(prefix);
- /* test for NULL */
- if (fPosPrefixPattern == 0) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fPosSuffixPattern = new UnicodeString(suffix);
- /* test for NULL */
- if (fPosSuffixPattern == 0) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete fPosPrefixPattern;
- return;
- }
- fNegPrefixPattern = 0;
- fNegSuffixPattern = 0;
-
- fUseExponentialNotation = (expDigits >= 0);
- if (fUseExponentialNotation) {
- fMinExponentDigits = expDigits;
- }
- fExponentSignAlwaysShown = expSignAlways;
- int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
- // The effectiveDecimalPos is the position the decimal is at or
- // would be at if there is no decimal. Note that if
- // decimalPos<0, then digitTotalCount == digitLeftCount +
- // zeroDigitCount.
- int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
- UBool isSigDig = (sigDigitCount > 0);
- setSignificantDigitsUsed(isSigDig);
- if (isSigDig) {
- setMinimumSignificantDigits(sigDigitCount);
- setMaximumSignificantDigits(sigDigitCount + digitRightCount);
- } else {
- int32_t minInt = effectiveDecimalPos - digitLeftCount;
- setMinimumIntegerDigits(minInt);
- setMaximumIntegerDigits(fUseExponentialNotation
- ? digitLeftCount + getMinimumIntegerDigits()
- : kDoubleIntegerDigits);
- setMaximumFractionDigits(decimalPos >= 0
- ? (digitTotalCount - decimalPos) : 0);
- setMinimumFractionDigits(decimalPos >= 0
- ? (digitLeftCount + zeroDigitCount - decimalPos) : 0);
- }
- setGroupingUsed(groupingCount > 0);
- fGroupingSize = (groupingCount > 0) ? groupingCount : 0;
- fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
- ? groupingCount2 : 0;
- setMultiplier(multiplier);
- setDecimalSeparatorAlwaysShown(decimalPos == 0
- || decimalPos == digitTotalCount);
- if (padPos >= 0) {
- fPadPosition = (EPadPosition) padPos;
- // To compute the format width, first set up sub0Limit -
- // sub0Start. Add in prefix/suffix length later.
-
- // fFormatWidth = prefix.length() + suffix.length() +
- // sub0Limit - sub0Start;
- fFormatWidth = sub0Limit - sub0Start;
- fPad = padChar;
- } else {
- fFormatWidth = 0;
- }
- if (roundingPos >= 0) {
- roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos);
- if (fRoundingIncrement != NULL) {
- *fRoundingIncrement = roundingInc;
- } else {
- fRoundingIncrement = new DigitList(roundingInc);
- /* test for NULL */
- if (fRoundingIncrement == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete fPosPrefixPattern;
- delete fPosSuffixPattern;
- return;
- }
- }
- fRoundingMode = kRoundHalfEven;
- } else {
- setRoundingIncrement(0.0);
- }
- } else {
- fNegPrefixPattern = new UnicodeString(prefix);
- /* test for NULL */
- if (fNegPrefixPattern == 0) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fNegSuffixPattern = new UnicodeString(suffix);
- /* test for NULL */
- if (fNegSuffixPattern == 0) {
- delete fNegPrefixPattern;
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- }
+ patternParser.useSymbols(*fSymbols);
}
-
- if (pattern.length() == 0) {
- delete fNegPrefixPattern;
- delete fNegSuffixPattern;
- fNegPrefixPattern = NULL;
- fNegSuffixPattern = NULL;
- if (fPosPrefixPattern != NULL) {
- fPosPrefixPattern->remove();
- } else {
- fPosPrefixPattern = new UnicodeString();
- /* test for NULL */
- if (fPosPrefixPattern == 0) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- }
- if (fPosSuffixPattern != NULL) {
- fPosSuffixPattern->remove();
+ fFormatPattern = pattern;
+ DecimalFormatPattern out;
+ patternParser.applyPatternWithoutExpandAffix(
+ pattern,
+ out,
+ parseError,
+ status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ setMinimumIntegerDigits(out.fMinimumIntegerDigits);
+ setMaximumIntegerDigits(out.fMaximumIntegerDigits);
+ setMinimumFractionDigits(out.fMinimumFractionDigits);
+ setMaximumFractionDigits(out.fMaximumFractionDigits);
+ setSignificantDigitsUsed(out.fUseSignificantDigits);
+ if (out.fUseSignificantDigits) {
+ setMinimumSignificantDigits(out.fMinimumSignificantDigits);
+ setMaximumSignificantDigits(out.fMaximumSignificantDigits);
+ }
+ fUseExponentialNotation = out.fUseExponentialNotation;
+ if (out.fUseExponentialNotation) {
+ fMinExponentDigits = out.fMinExponentDigits;
+ }
+ fExponentSignAlwaysShown = out.fExponentSignAlwaysShown;
+ fCurrencySignCount = out.fCurrencySignCount;
+ setGroupingUsed(out.fGroupingUsed);
+ if (out.fGroupingUsed) {
+ fGroupingSize = out.fGroupingSize;
+ fGroupingSize2 = out.fGroupingSize2;
+ }
+ setMultiplier(out.fMultiplier);
+ fDecimalSeparatorAlwaysShown = out.fDecimalSeparatorAlwaysShown;
+ fFormatWidth = out.fFormatWidth;
+ if (out.fRoundingIncrementUsed) {
+ if (fRoundingIncrement != NULL) {
+ *fRoundingIncrement = out.fRoundingIncrement;
} else {
- fPosSuffixPattern = new UnicodeString();
+ fRoundingIncrement = new DigitList(out.fRoundingIncrement);
/* test for NULL */
- if (fPosSuffixPattern == 0) {
- delete fPosPrefixPattern;
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
+ if (fRoundingIncrement == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
}
}
-
- setMinimumIntegerDigits(0);
- setMaximumIntegerDigits(kDoubleIntegerDigits);
- setMinimumFractionDigits(0);
- setMaximumFractionDigits(kDoubleFractionDigits);
-
- fUseExponentialNotation = FALSE;
- fCurrencySignCount = 0;
- setGroupingUsed(FALSE);
- fGroupingSize = 0;
- fGroupingSize2 = 0;
- setMultiplier(1);
- setDecimalSeparatorAlwaysShown(FALSE);
- fFormatWidth = 0;
+ } else {
setRoundingIncrement(0.0);
}
-
- // If there was no negative pattern, or if the negative pattern is
- // identical to the positive pattern, then prepend the minus sign to the
- // positive pattern to form the negative pattern.
- if (fNegPrefixPattern == NULL ||
- (*fNegPrefixPattern == *fPosPrefixPattern
- && *fNegSuffixPattern == *fPosSuffixPattern)) {
- _copy_us_ptr(&fNegSuffixPattern, fPosSuffixPattern);
- if (fNegPrefixPattern == NULL) {
- fNegPrefixPattern = new UnicodeString();
- /* test for NULL */
- if (fNegPrefixPattern == 0) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- } else {
- fNegPrefixPattern->remove();
- }
- fNegPrefixPattern->append(kQuote).append(kPatternMinus)
- .append(*fPosPrefixPattern);
+ fPad = out.fPad;
+ switch (out.fPadPosition) {
+ case DecimalFormatPattern::kPadBeforePrefix:
+ fPadPosition = kPadBeforePrefix;
+ break;
+ case DecimalFormatPattern::kPadAfterPrefix:
+ fPadPosition = kPadAfterPrefix;
+ break;
+ case DecimalFormatPattern::kPadBeforeSuffix:
+ fPadPosition = kPadBeforeSuffix;
+ break;
+ case DecimalFormatPattern::kPadAfterSuffix:
+ fPadPosition = kPadAfterSuffix;
+ break;
}
-#ifdef FMT_DEBUG
- UnicodeString s;
- s.append("\"").append(pattern).append("\"->");
- debugout(s);
-#endif
-
- // save the pattern
- fFormatPattern = pattern;
+ copyString(out.fNegPrefixPattern, out.fNegPatternsBogus, fNegPrefixPattern, status);
+ copyString(out.fNegSuffixPattern, out.fNegPatternsBogus, fNegSuffixPattern, status);
+ copyString(out.fPosPrefixPattern, out.fPosPatternsBogus, fPosPrefixPattern, status);
+ copyString(out.fPosSuffixPattern, out.fPosPatternsBogus, fPosSuffixPattern, status);
}
}
applyPatternWithoutExpandAffix(pattern, localized, parseError, status);
expandAffixAdjustWidth(NULL);
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
UErrorCode& status) {
applyPatternWithoutExpandAffix(pattern, localized, parseError, status);
expandAffixAdjustWidth(&pluralCount);
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
* Sets the maximum number of digits allowed in the integer portion of a
- * number. This override limits the integer digit count to 309.
+ * number.
* @see NumberFormat#setMaximumIntegerDigits
*/
void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
- NumberFormat::setMaximumIntegerDigits(_min(newValue, kDoubleIntegerDigits));
+ NumberFormat::setMaximumIntegerDigits(_min(newValue, gDefaultMaxIntegerDigits));
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
*/
void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
NumberFormat::setMinimumIntegerDigits(_min(newValue, kDoubleIntegerDigits));
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
*/
void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
NumberFormat::setMaximumFractionDigits(_min(newValue, kDoubleFractionDigits));
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
/**
*/
void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
NumberFormat::setMinimumFractionDigits(_min(newValue, kDoubleFractionDigits));
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
int32_t DecimalFormat::getMinimumSignificantDigits() const {
int32_t max = _max(fMaxSignificantDigits, min);
fMinSignificantDigits = min;
fMaxSignificantDigits = max;
+ fUseSignificantDigits = TRUE;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
void DecimalFormat::setMaximumSignificantDigits(int32_t max) {
int32_t min = _min(fMinSignificantDigits, max);
fMinSignificantDigits = min;
fMaxSignificantDigits = max;
+ fUseSignificantDigits = TRUE;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
UBool DecimalFormat::areSignificantDigitsUsed() const {
void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
fUseSignificantDigits = useSignificantDigits;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
void DecimalFormat::setCurrencyInternally(const UChar* theCurrency,
double rounding = 0.0;
int32_t frac = 0;
- if (fCurrencySignCount > fgCurrencySignCountZero && isCurr) {
+ if (fCurrencySignCount != fgCurrencySignCountZero && isCurr) {
rounding = ucurr_getRoundingIncrement(theCurrency, &ec);
frac = ucurr_getDefaultFractionDigits(theCurrency, &ec);
}
NumberFormat::setCurrency(theCurrency, ec);
if (U_FAILURE(ec)) return;
- if (fCurrencySignCount > fgCurrencySignCountZero) {
+ if (fCurrencySignCount != fgCurrencySignCountZero) {
// NULL or empty currency is *legal* and indicates no currency.
if (isCurr) {
setRoundingIncrement(rounding);
}
expandAffixes(NULL);
}
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
}
// set the currency after apply pattern to get the correct rounding/fraction
setCurrencyInternally(theCurrency, ec);
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
// Deprecated variant with no UErrorCode parameter
void DecimalFormat::setCurrency(const UChar* theCurrency) {
UErrorCode ec = U_ZERO_ERROR;
setCurrency(theCurrency, ec);
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
}
}
+// this is only overridden to call handleChanged() for fastpath purposes.
+void
+DecimalFormat::setGroupingUsed(UBool newValue) {
+ NumberFormat::setGroupingUsed(newValue);
+ handleChanged();
+}
+
+// this is only overridden to call handleChanged() for fastpath purposes.
+void
+DecimalFormat::setParseIntegerOnly(UBool newValue) {
+ NumberFormat::setParseIntegerOnly(newValue);
+ handleChanged();
+}
+
+// this is only overridden to call handleChanged() for fastpath purposes.
+// setContext doesn't affect the fastPath right now, but this is called for completeness
+void
+DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) {
+ NumberFormat::setContext(value, status);
+ handleChanged();
+}
+
+
+DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr,
+ int32_t newValue,
+ UErrorCode &status) {
+ if(U_FAILURE(status)) return *this;
+
+ switch(attr) {
+ case UNUM_LENIENT_PARSE:
+ setLenient(newValue!=0);
+ break;
+
+ case UNUM_PARSE_INT_ONLY:
+ setParseIntegerOnly(newValue!=0);
+ break;
+
+ case UNUM_GROUPING_USED:
+ setGroupingUsed(newValue!=0);
+ break;
+
+ case UNUM_DECIMAL_ALWAYS_SHOWN:
+ setDecimalSeparatorAlwaysShown(newValue!=0);
+ break;
+
+ case UNUM_MAX_INTEGER_DIGITS:
+ setMaximumIntegerDigits(newValue);
+ break;
+
+ case UNUM_MIN_INTEGER_DIGITS:
+ setMinimumIntegerDigits(newValue);
+ break;
+
+ case UNUM_INTEGER_DIGITS:
+ setMinimumIntegerDigits(newValue);
+ setMaximumIntegerDigits(newValue);
+ break;
+
+ case UNUM_MAX_FRACTION_DIGITS:
+ setMaximumFractionDigits(newValue);
+ break;
+
+ case UNUM_MIN_FRACTION_DIGITS:
+ setMinimumFractionDigits(newValue);
+ break;
+
+ case UNUM_FRACTION_DIGITS:
+ setMinimumFractionDigits(newValue);
+ setMaximumFractionDigits(newValue);
+ break;
+
+ case UNUM_SIGNIFICANT_DIGITS_USED:
+ setSignificantDigitsUsed(newValue!=0);
+ break;
+
+ case UNUM_MAX_SIGNIFICANT_DIGITS:
+ setMaximumSignificantDigits(newValue);
+ break;
+
+ case UNUM_MIN_SIGNIFICANT_DIGITS:
+ setMinimumSignificantDigits(newValue);
+ break;
+
+ case UNUM_MULTIPLIER:
+ setMultiplier(newValue);
+ break;
+
+ case UNUM_GROUPING_SIZE:
+ setGroupingSize(newValue);
+ break;
+
+ case UNUM_ROUNDING_MODE:
+ setRoundingMode((DecimalFormat::ERoundingMode)newValue);
+ break;
+
+ case UNUM_FORMAT_WIDTH:
+ setFormatWidth(newValue);
+ break;
+
+ case UNUM_PADDING_POSITION:
+ /** The position at which padding will take place. */
+ setPadPosition((DecimalFormat::EPadPosition)newValue);
+ break;
+
+ case UNUM_SECONDARY_GROUPING_SIZE:
+ setSecondaryGroupingSize(newValue);
+ break;
+
+#if UCONFIG_HAVE_PARSEALLINPUT
+ case UNUM_PARSE_ALL_INPUT:
+ setParseAllInput((UNumberFormatAttributeValue)newValue);
+ break;
+#endif
+
+ /* These are stored in fBoolFlags */
+ case UNUM_PARSE_NO_EXPONENT:
+ case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+ if(!fBoolFlags.isValidValue(newValue)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ fBoolFlags.set(attr, newValue);
+ }
+ break;
+
+ case UNUM_SCALE:
+ fScale = newValue;
+ break;
+
+ default:
+ status = U_UNSUPPORTED_ERROR;
+ break;
+ }
+ return *this;
+}
+
+int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr,
+ UErrorCode &status ) const {
+ if(U_FAILURE(status)) return -1;
+ switch(attr) {
+ case UNUM_LENIENT_PARSE:
+ return isLenient();
+
+ case UNUM_PARSE_INT_ONLY:
+ return isParseIntegerOnly();
+
+ case UNUM_GROUPING_USED:
+ return isGroupingUsed();
+
+ case UNUM_DECIMAL_ALWAYS_SHOWN:
+ return isDecimalSeparatorAlwaysShown();
+
+ case UNUM_MAX_INTEGER_DIGITS:
+ return getMaximumIntegerDigits();
+
+ case UNUM_MIN_INTEGER_DIGITS:
+ return getMinimumIntegerDigits();
+
+ case UNUM_INTEGER_DIGITS:
+ // TBD: what should this return?
+ return getMinimumIntegerDigits();
+
+ case UNUM_MAX_FRACTION_DIGITS:
+ return getMaximumFractionDigits();
+
+ case UNUM_MIN_FRACTION_DIGITS:
+ return getMinimumFractionDigits();
+
+ case UNUM_FRACTION_DIGITS:
+ // TBD: what should this return?
+ return getMinimumFractionDigits();
+
+ case UNUM_SIGNIFICANT_DIGITS_USED:
+ return areSignificantDigitsUsed();
+
+ case UNUM_MAX_SIGNIFICANT_DIGITS:
+ return getMaximumSignificantDigits();
+
+ case UNUM_MIN_SIGNIFICANT_DIGITS:
+ return getMinimumSignificantDigits();
+
+ case UNUM_MULTIPLIER:
+ return getMultiplier();
+
+ case UNUM_GROUPING_SIZE:
+ return getGroupingSize();
+
+ case UNUM_ROUNDING_MODE:
+ return getRoundingMode();
+
+ case UNUM_FORMAT_WIDTH:
+ return getFormatWidth();
+
+ case UNUM_PADDING_POSITION:
+ return getPadPosition();
+
+ case UNUM_SECONDARY_GROUPING_SIZE:
+ return getSecondaryGroupingSize();
+
+ /* These are stored in fBoolFlags */
+ case UNUM_PARSE_NO_EXPONENT:
+ case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+ return fBoolFlags.get(attr);
+
+ case UNUM_SCALE:
+ return fScale;
+
+ default:
+ status = U_UNSUPPORTED_ERROR;
+ break;
+ }
+
+ return -1; /* undefined */
+}
+#if UCONFIG_HAVE_PARSEALLINPUT
+void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
+ fParseAllInput = value;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
+}
+#endif
void
DecimalFormat::copyHashForAffix(const Hashtable* source,