/*
*******************************************************************************
-* Copyright (C) 1997-2014, International Business Machines Corporation and *
+* Copyright (C) 1997-2015, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
#include "dcfmtimp.h"
#include "plurrule_impl.h"
#include "decimalformatpattern.h"
+#include "fmtableimp.h"
/*
* On certain platforms, round is a macro defined in math.h
fAffixesForCurrency = NULL;
fPluralAffixesForCurrency = NULL;
fCurrencyPluralInfo = NULL;
+ fCurrencyUsage = UCURR_USAGE_STANDARD;
#if UCONFIG_HAVE_PARSEALLINPUT
fParseAllInput = UNUM_MAYBE;
#endif
// save the unique currency plural patterns of this locale.
Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPattern;
const UHashElement* element = NULL;
- int32_t pos = -1;
+ int32_t pos = UHASH_FIRST;
Hashtable pluralPatternSet;
while ((element = pluralPtn->nextElement(pos)) != NULL) {
const UHashTok valueTok = element->value;
fMaxSignificantDigits = rhs.fMaxSignificantDigits;
fUseSignificantDigits = rhs.fUseSignificantDigits;
fFormatPattern = rhs.fFormatPattern;
+ fCurrencyUsage = rhs.fCurrencyUsage;
fStyle = rhs.fStyle;
_clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo);
deleteHashForAffixPattern();
((fCurrencyPluralInfo == other->fCurrencyPluralInfo &&
fCurrencyPluralInfo == NULL) ||
(fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL &&
- *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo)))
+ *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo))) &&
+
+ fCurrencyUsage == other->fCurrencyUsage
// depending on other settings we may also need to compare
// fCurrencyChoice (mostly deprecated?),
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 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);
- }
+ if (type == Formattable::kInt64 && number.getInt64() <= MAX_INT64_IN_DOUBLE &&
+ number.getInt64() >= -MAX_INT64_IN_DOUBLE) {
+ 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.
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.
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) {
+ if(fUseExponentialNotation) {
debug("No format fastpath: fUseExponentialNotation");
} else if(fFormatWidth!=0) {
debug("No format fastpath: fFormatWidth!=0");
debug("No format fastpath: fCurrencySignCount != fgCurrencySignCountZero");
} else if(fRoundingIncrement!=0) {
debug("No format fastpath: fRoundingIncrement!=0");
+ } else if (fGroupingSize!=0 && isGroupingUsed()) {
+ debug("Maybe format fastpath: fGroupingSize!=0 and grouping is used");
+#ifdef FMT_DEBUG
+ printf("groupingsize=%d\n", fGroupingSize);
+#endif
+
+ if (getMinimumIntegerDigits() <= fGroupingSize) {
+ data.fFastFormatStatus = kFastpathMAYBE;
+ }
+ } else if(fGroupingSize2!=0 && isGroupingUsed()) {
+ debug("No format fastpath: fGroupingSize2!=0");
} else {
data.fFastFormatStatus = kFastpathYES;
debug("format:kFastpathYES!");
printf("fastpath? [%d]\n", number);
#endif
- if( data.fFastFormatStatus==kFastpathYES) {
+ if( data.fFastFormatStatus==kFastpathYES ||
+ data.fFastFormatStatus==kFastpathMAYBE) {
+ int32_t noGroupingThreshold = 0;
#define kZero 0x0030
const int32_t MAX_IDX = MAX_DIGITS+2;
int32_t destIdx = MAX_IDX;
outputStr[--destIdx] = 0; // term
+ if (data.fFastFormatStatus==kFastpathMAYBE) {
+ noGroupingThreshold = destIdx - fGroupingSize;
+ }
int64_t n = number;
if (number < 1) {
// Negative numbers are slightly larger than positive
}
// get any remaining digits
while (n > 0) {
+ if (destIdx == noGroupingThreshold) {
+ goto slowPath;
+ }
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 prefixLen = */ appendAffix(appendTo, static_cast<double>(number), handler, number<0, TRUE);
+
+ // This will be at least 0 even if it was set to a negative number.
int32_t maxIntDig = getMaximumIntegerDigits();
int32_t destlength = length<=maxIntDig?length:maxIntDig; // dest length pinned to max int digits
status = U_ILLEGAL_ARGUMENT_ERROR;
}
- int32_t prependZero = getMinimumIntegerDigits() - destlength;
+ int32_t minDigits = getMinimumIntegerDigits();
+
+ // We always want at least one digit, even if it is just a 0.
+ int32_t prependZero = (minDigits < 1 ? 1 : minDigits) - 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);
destlength);
handler.addAttribute(kIntegerField, intBegin, appendTo.length());
- /*int32_t suffixLen =*/ appendAffix(appendTo, number, handler, number<0, FALSE);
+ /*int32_t suffixLen =*/ appendAffix(appendTo, static_cast<double>(number), handler, number<0, FALSE);
//outputStr[length]=0;
return appendTo;
} // end fastpath
#endif
+ slowPath:
// Else the slow way - via DigitList
DigitList digits;
parse(text, parseResult, pos, curbuf);
if (pos.getIndex() != start) {
UErrorCode ec = U_ZERO_ERROR;
- LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curbuf, ec));
+ LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curbuf, ec), ec);
if (U_FAILURE(ec)) {
pos.setIndex(start); // indicate failure
} else {
}
// Then, parse against affix patterns.
// Those are currency patterns and currency plural patterns.
- int32_t pos = -1;
+ int32_t pos = UHASH_FIRST;
const UHashElement* element = NULL;
while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
const UHashTok valueTok = element->value;
}
}
+ // if we didn't see a decimal and it is required, check to see if the pattern had one
+ if(!sawDecimal && isDecimalPatternMatchRequired())
+ {
+ if(fFormatPattern.indexOf(DecimalFormatSymbols::kDecimalSeparatorSymbol) != 0)
+ {
+ parsePosition.setIndex(oldStart);
+ parsePosition.setErrorIndex(position);
+ debug("decimal point match required fail!");
+ return FALSE;
+ }
+ }
+
if (backup != -1)
{
position = backup;
parsePosition.setErrorIndex(position);
return FALSE;
}
+
+ // check if we missed a required decimal point
+ if(fastParseOk && isDecimalPatternMatchRequired())
+ {
+ if(fFormatPattern.indexOf(DecimalFormatSymbols::kDecimalSeparatorSymbol) != 0)
+ {
+ parsePosition.setIndex(oldStart);
+ parsePosition.setErrorIndex(position);
+ debug("decimal point match required fail!");
+ return FALSE;
+ }
+ }
+
+
return TRUE;
}
int32_t
DecimalFormat::getGroupingSize() const
{
- return fGroupingSize;
+ return isGroupingUsed() ? fGroupingSize : 0;
}
//------------------------------------------------------------------------------
#endif
}
+//------------------------------------------------------------------------------
+// Checks if decimal point pattern match is required
+UBool
+DecimalFormat::isDecimalPatternMatchRequired(void) const
+{
+ return fBoolFlags.contains(UNUM_PARSE_DECIMAL_MARK_REQUIRED);
+}
+
+//------------------------------------------------------------------------------
+// Checks if decimal point pattern match is required
+
+void
+DecimalFormat::setDecimalPatternMatchRequired(UBool newValue)
+{
+ fBoolFlags.set(UNUM_PARSE_DECIMAL_MARK_REQUIRED, newValue);
+}
+
+
//------------------------------------------------------------------------------
// Emits the pattern of this DecimalFormat instance.
double rounding = 0.0;
int32_t frac = 0;
if (fCurrencySignCount != fgCurrencySignCountZero && isCurr) {
- rounding = ucurr_getRoundingIncrement(theCurrency, &ec);
- frac = ucurr_getDefaultFractionDigits(theCurrency, &ec);
+ rounding = ucurr_getRoundingIncrementForUsage(theCurrency, fCurrencyUsage, &ec);
+ frac = ucurr_getDefaultFractionDigitsForUsage(theCurrency, fCurrencyUsage, &ec);
}
NumberFormat::setCurrency(theCurrency, ec);
#endif
}
+void DecimalFormat::setCurrencyUsage(UCurrencyUsage newContext, UErrorCode* ec){
+ fCurrencyUsage = newContext;
+
+ const UChar* theCurrency = getCurrency();
+
+ // We set rounding/digit based on currency context
+ if(theCurrency){
+ double rounding = ucurr_getRoundingIncrementForUsage(theCurrency, fCurrencyUsage, ec);
+ int32_t frac = ucurr_getDefaultFractionDigitsForUsage(theCurrency, fCurrencyUsage, ec);
+
+ if (U_SUCCESS(*ec)) {
+ setRoundingIncrement(rounding);
+ setMinimumFractionDigits(frac);
+ setMaximumFractionDigits(frac);
+ }
+ }
+}
+
+UCurrencyUsage DecimalFormat::getCurrencyUsage() const {
+ return fCurrencyUsage;
+}
+
// Deprecated variant with no UErrorCode parameter
void DecimalFormat::setCurrency(const UChar* theCurrency) {
UErrorCode ec = U_ZERO_ERROR;
if ( table == NULL ) {
return;
}
- int32_t pos = -1;
+ int32_t pos = UHASH_FIRST;
const UHashElement* element = NULL;
while ( (element = table->nextElement(pos)) != NULL ) {
const UHashTok valueTok = element->value;
if ( fAffixPatternsForCurrency == NULL ) {
return;
}
- int32_t pos = -1;
+ int32_t pos = UHASH_FIRST;
const UHashElement* element = NULL;
while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
const UHashTok valueTok = element->value;
if ( U_FAILURE(status) ) {
return;
}
- int32_t pos = -1;
+ int32_t pos = UHASH_FIRST;
const UHashElement* element = NULL;
if ( source ) {
while ( (element = source->nextElement(pos)) != NULL ) {
/* These are stored in fBoolFlags */
case UNUM_PARSE_NO_EXPONENT:
case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+ case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
if(!fBoolFlags.isValidValue(newValue)) {
status = U_ILLEGAL_ARGUMENT_ERROR;
} else {
fScale = newValue;
break;
+ case UNUM_CURRENCY_USAGE:
+ setCurrencyUsage((UCurrencyUsage)newValue, &status);
+
default:
status = U_UNSUPPORTED_ERROR;
break;
/* These are stored in fBoolFlags */
case UNUM_PARSE_NO_EXPONENT:
case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+ case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
return fBoolFlags.get(attr);
case UNUM_SCALE:
return fScale;
+ case UNUM_CURRENCY_USAGE:
+ return fCurrencyUsage;
+
default:
status = U_UNSUPPORTED_ERROR;
break;
if ( U_FAILURE(status) ) {
return;
}
- int32_t pos = -1;
+ int32_t pos = UHASH_FIRST;
const UHashElement* element = NULL;
if ( source ) {
while ( (element = source->nextElement(pos)) != NULL ) {