/*
******************************************************************************
*
-* Copyright (C) 2002-2011, International Business Machines
+* Copyright (C) 2002-2012, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
* Used to prevent changing out the heap functions after allocations have been made */
static UBool gHeapInUse;
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+#include <stdio.h>
+static int n=0;
+static long b=0;
+#endif
+
+
U_CAPI void * U_EXPORT2
uprv_malloc(size_t s) {
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+#if 1
+ putchar('>');
+ fflush(stdout);
+#else
+ fprintf(stderr,"MALLOC\t#%d\t%ul bytes\t%ul total\n", ++n,s,(b+=s)); fflush(stderr);
+#endif
+#endif
if (s > 0) {
gHeapInUse = TRUE;
if (pAlloc) {
U_CAPI void * U_EXPORT2
uprv_realloc(void * buffer, size_t size) {
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+ putchar('~');
+ fflush(stdout);
+#endif
if (buffer == zeroMem) {
return uprv_malloc(size);
} else if (size == 0) {
U_CAPI void U_EXPORT2
uprv_free(void *buffer) {
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+ putchar('<');
+ fflush(stdout);
+#endif
if (buffer != zeroMem) {
if (pFree) {
(*pFree)(pContext, buffer);
/*
******************************************************************************
*
-* Copyright (C) 1997-2011, International Business Machines
+* Copyright (C) 1997-2012, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
#include "unicode/utypes.h"
#include "unicode/localpointer.h"
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+#include <stdio.h>
+#endif
+
#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
template<typename T, int32_t stackCapacity>
inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
if(newCapacity>0) {
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+ ::fprintf(::stderr,"MaybeStacArray (resize) alloc %d * %lu\n", newCapacity,sizeof(T));
+#endif
T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
if(p!=NULL) {
if(length>0) {
length=capacity;
}
p=(T *)uprv_malloc(length*sizeof(T));
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+ ::fprintf(::stderr,"MaybeStacArray (orphan) alloc %d * %lu\n", length,sizeof(T));
+#endif
if(p==NULL) {
return NULL;
}
inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
int32_t length) {
if(newCapacity>=0) {
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+ ::fprintf(::stderr,"MaybeStackHeaderAndArray alloc %d + %d * %ul\n", sizeof(H),newCapacity,sizeof(T));
+#endif
H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
if(p!=NULL) {
if(length<0) {
} else if(length>capacity) {
length=capacity;
}
+#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
+ ::fprintf(::stderr,"MaybeStackHeaderAndArray (orphan) alloc %ul + %d * %lu\n", sizeof(H),length,sizeof(T));
+#endif
p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
if(p==NULL) {
return NULL;
# define UCONFIG_NO_SERVICE 0
#endif
+/**
+ * \def UCONFIG_INTERNAL_DIGITLIST
+ * This switch turns on the fast but binary-incompatible Formattable class with an internal DigitList
+ *
+ * @internal
+ */
+#ifndef UCONFIG_INTERNAL_DIGITLIST
+# define UCONFIG_INTERNAL_DIGITLIST 0
+#endif
+
+
+
+
+/**
+ * \def UCONFIG_HAVE_PARSEALLINPUT
+ * This switch turns on the "parse all input" attribute. Binary incompatible.
+ *
+ * @internal
+ */
+#ifndef UCONFIG_HAVE_PARSEALLINPUT
+# define UCONFIG_HAVE_PARSEALLINPUT 0
+#endif
+
+
+/**
+ * \def UCONFIG_HAVE_PARSEALLINPUT
+ * This switch turns on other formatting fastpaths. Binary incompatible in object DecimalFormat and DecimalFormatSymbols
+ *
+ * @internal
+ */
+#ifndef UCONFIG_FORMAT_FASTPATHS_49
+# define UCONFIG_FORMAT_FASTPATHS_49 0
+#endif
+
#endif
--- /dev/null
+/*
+********************************************************************************
+* Copyright (C) 2012, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************/
+
+#ifndef DCFMTIMP_H
+#define DCFMTIMP_H
+
+#include "unicode/utypes.h"
+
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+
+U_NAMESPACE_BEGIN
+
+enum EDecimalFormatFastpathStatus {
+ kFastpathNO = 0,
+ kFastpathYES = 1,
+ kFastpathUNKNOWN = 2, /* not yet set */
+};
+
+/**
+ * Must be smaller than DecimalFormat::fReserved
+ */
+struct DecimalFormatInternal {
+ uint8_t fFastpathStatus;
+
+#ifdef FMT_DEBUG
+ void dump() const {
+ printf("DecimalFormatInternal: fFastpathStatus=%c\n",
+ "NY?"[(int)fFastpathStatus&3]);
+ }
+#endif
+};
+
+
+
+U_NAMESPACE_END
+
+#endif
+
+#endif
#include <math.h>
#include "hash.h"
#include "decfmtst.h"
-
+#include "dcfmtimp.h"
U_NAMESPACE_BEGIN
+/* == 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,
#ifdef FMT_DEBUG
#include <stdio.h>
-static void debugout(UnicodeString s) {
+static void _debugout(const char *f, int l, const UnicodeString& s) {
char buf[2000];
s.extract((int32_t) 0, s.length(), buf);
- printf("%s\n", buf);
+ printf("%s:%d: %s\n", f,l, buf);
}
-#define debug(x) printf("%s\n", x);
+#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)
// Constructs a DecimalFormat instance in the default locale.
DecimalFormat::DecimalFormat(UErrorCode& status) {
- init();
+ init(status);
UParseError parseError;
construct(status, parseError);
}
DecimalFormat::DecimalFormat(const UnicodeString& pattern,
UErrorCode& status) {
- init();
+ init(status);
UParseError parseError;
construct(status, parseError, &pattern);
}
DecimalFormat::DecimalFormat(const UnicodeString& pattern,
DecimalFormatSymbols* symbolsToAdopt,
UErrorCode& status) {
- init();
+ init(status);
UParseError parseError;
if (symbolsToAdopt == NULL)
status = U_ILLEGAL_ARGUMENT_ERROR;
DecimalFormatSymbols* symbolsToAdopt,
UParseError& parseErr,
UErrorCode& status) {
- init();
+ init(status);
if (symbolsToAdopt == NULL)
status = U_ILLEGAL_ARGUMENT_ERROR;
construct(status,parseErr, &pattern, symbolsToAdopt);
DecimalFormat::DecimalFormat(const UnicodeString& pattern,
const DecimalFormatSymbols& symbols,
UErrorCode& status) {
- init();
+ init(status);
UParseError parseError;
construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols));
}
DecimalFormatSymbols* symbolsToAdopt,
UNumberFormatStyle style,
UErrorCode& status) {
- init();
+ init(status);
fStyle = style;
UParseError parseError;
construct(status, parseError, &pattern, symbolsToAdopt);
// Put all fields of an uninitialized object into a known state.
// Common code, shared by all constructors.
void
-DecimalFormat::init() {
+DecimalFormat::init(UErrorCode &status) {
fPosPrefixPattern = 0;
fPosSuffixPattern = 0;
fNegPrefixPattern = 0;
fAffixesForCurrency = NULL;
fPluralAffixesForCurrency = NULL;
fCurrencyPluralInfo = NULL;
+#if UCONFIG_HAVE_PARSEALLINPUT
+ fParseAllInput = UNUM_MAYBE;
+#endif
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+ DecimalFormatInternal &data = internalData(fReserved);
+ data.fFastpathStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
+#endif
+ // only do this once per obj.
+ DecimalFormatStaticSets::initSets(&status);
}
//------------------------------------------------------------------------------
if (fCurrencySignCount > fgCurrencySignCountZero) {
setCurrencyInternally(getCurrency(), status);
}
+#if UCONFIG_FORMAT_FASTPATHS_49
+ DecimalFormatInternal &data = internalData(fReserved);
+ data.fFastpathStatus = kFastpathNO; // allow it to be calculated
+ handleChanged();
+#endif
}
DecimalFormat::DecimalFormat(const DecimalFormat &source) :
NumberFormat(source) {
- init();
+ UErrorCode status = U_ZERO_ERROR;
+ init(status); // if this fails, 'source' isn't initialized properly either.
*this = source;
}
copyHashForAffix(rhs.fPluralAffixesForCurrency, fPluralAffixesForCurrency, status);
}
}
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
return *this;
}
return format((int64_t)number, appendTo, posIter, status);
}
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+void DecimalFormat::handleChanged() {
+ DecimalFormatInternal &data = internalData(fReserved);
+
+ if(data.fFastpathStatus == kFastpathUNKNOWN) {
+ return; // still constructing. Wait.
+ }
+
+ data.fFastpathStatus = kFastpathNO;
+
+ if (fGroupingSize!=0) {
+ debug("No fastpath: fGroupingSize!=0"); // TODO: revisit, should handle ex. up to 999 if groupingsize is 3.
+ } else if(fGroupingSize2!=0) {
+ debug("No fastpath: fGroupingSize2!=0");
+ } else if(fUseExponentialNotation) {
+ debug("No fastpath: fUseExponentialNotation");
+ } else if(fFormatWidth!=0) {
+ debug("No fastpath: fFormatWidth!=0");
+ } else if(fMinSignificantDigits!=1) {
+ debug("No fastpath: fMinSignificantDigits!=1");
+ } else if(fMultiplier!=NULL) {
+ debug("No fastpath: fMultiplier!=NULL");
+ } else if(0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)) {
+ debug("No fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)");
+ } else if(fDecimalSeparatorAlwaysShown) {
+ debug("No fastpath: fDecimalSeparatorAlwaysShown");
+ } else if(getMinimumFractionDigits()>0) {
+ debug("No fastpath: fMinFractionDigits>0");
+ } else if(fCurrencySignCount > fgCurrencySignCountZero) {
+ debug("No fastpath: fCurrencySignCount > fgCurrencySignCountZero");
+ } else {
+ data.fFastpathStatus = kFastpathYES;
+ debug("kFastpathYES!");
+ }
+}
+#endif
//------------------------------------------------------------------------------
UnicodeString&
UnicodeString& appendTo,
FieldPosition& fieldPosition) const
{
- FieldPositionOnlyHandler handler(fieldPosition);
- return _format(number, appendTo, handler);
+ FieldPositionOnlyHandler handler(fieldPosition);
+ return _format(number, appendTo, handler);
}
UnicodeString&
UnicodeString& appendTo,
FieldPositionHandler& handler) const
{
+ // Bottleneck function for formatting int64_t
UErrorCode status = U_ZERO_ERROR;
+
+#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.fFastpathStatus==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 < 0) { // Negative numbers are slightly larger than a postive
+ //outputStr[--destIdx] = (char)(-(n % 10) + kZero);
+ n *= -1;
+ }
+ do {
+ outputStr[--destIdx] = (n % 10) + kZero;
+ n /= 10;
+ } while (n > 0);
+
+
+ // Slide the number to the start of the output str
+ U_ASSERT(destIdx >= 0);
+ int32_t length = MAX_IDX - destIdx -1;
+ //uprv_memmove(outputStr, outputStr+MAX_IDX-length, length);
+ int32_t prefixLen = appendAffix(appendTo, number, handler, number<0, TRUE);
+
+ int32_t maxIntDig = getMaximumIntegerDigits();
+ int32_t prependZero = getMinimumIntegerDigits() - length;
+
+#ifdef FMT_DEBUG
+ printf("prependZero=%d, length=%d, minintdig=%d\n", prependZero, length, getMinimumIntegerDigits());
+#endif
+ int32_t intBegin = appendTo.length();
+
+ while((prependZero--)>0) {
+ appendTo.append(0x0030); // '0'
+ }
+
+ appendTo.append(outputStr+destIdx, length);
+ 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);
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)) {
// status is used to record whether a number is infinite.
UBool status[fgStatusLength];
+
+#if UCONFIG_INTERNAL_DIGITLIST
+ DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer
+#else
DigitList *digits = new DigitList;
+#endif
if (digits == NULL) {
return; // no way to report error from here.
}
if (fCurrencySignCount > fgCurrencySignCountZero) {
if (!parseForCurrency(text, parsePosition, *digits,
status, currency)) {
- delete digits;
- return;
+#if !UCONFIG_INTERNAL_DIGITLIST
+ delete digits;
+#endif
+ return;
}
} else {
if (!subparse(text,
fPosPrefixPattern, fPosSuffixPattern,
FALSE, UCURR_SYMBOL_NAME,
parsePosition, *digits, status, currency)) {
+ debug("!subparse(...) - rewind");
parsePosition.setIndex(startIdx);
+#if !UCONFIG_INTERNAL_DIGITLIST
delete digits;
+#endif
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.
+#if !UCONFIG_INTERNAL_DIGITLIST
+ delete digits;
+#endif
+ // TODO: set the dl to infinity, and let it fall into the code below.
}
else {
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);
+#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(" ")); }
+ DBGAPPD(negPrefix);
+ DBGAPPD(negSuffix);
+ DBGAPPD(posPrefix);
+ DBGAPPD(posSuffix);
+ debugout(s);
+ printf("currencyParsing=%d, fFormatWidth=%d, text.length=%d negPrefLen=%d\n", currencyParsing, fFormatWidth, 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. */
+
+ if(!currencyParsing &&
+
+ ( (
+#if UCONFIG_HAVE_PARSEALLINPUT
+ fParseAllInput == UNUM_YES ) ||
+ ( fParseAllInput == UNUM_MAYBE &&
+#endif
+ fFormatWidth==0 &&
+ // (negPrefix!=NULL&&negPrefix->isEmpty()) ||
+ text.length()>0 &&
+ text.length()<20 &&
+ (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;
+ int32_t decimalCount = decimalString->countChar32(0,3);
+ if(isParseIntegerOnly()) {
+ decimalChar = 0; // not allowed
+ } else if(decimalCount==1) {
+ decimalChar = decimalString->char32At(0);
+ } else if(decimalCount==0) {
+ decimalChar=0;
+ } else {
+ j=l+1;//=break
+ }
+
+ if(ch=='-') {
+ /* for now- no negs. */
+ j=l+1;//=break
+
+ /*
+ 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 == decimalChar) {
+ parsedNum.append((char)('.'), err);
+ decimalChar=0; // no more decimals.
+ fastParseHadDecimal=TRUE;
+ } else {
+ digitCount=-1; // fail
+ break;
+ }
+ j+=U16_LENGTH(ch);
+ ch = text.char32At(j); // for next
+ }
+ if(j==l && (digitCount>0)) {
+#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();
+ }
+ }
+
+ if(!fastParseOk
+#if UCONFIG_HAVE_PARSEALLINPUT
+ && fParseAllInput!=UNUM_YES
+#endif
+ )
+ {
// Match padding before prefix
if (fFormatWidth > 0 && fPadPosition == kPadBeforePrefix) {
position = skipPadding(text, position);
// 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?
} else {
decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
}
- UChar32 decimalChar = decimalString->char32At(0);
-
const UnicodeString *groupingString = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ UChar32 decimalChar = decimalString->char32At(0);
UChar32 groupingChar = groupingString->char32At(0);
+ int32_t decimalStringLength = decimalString->length();
+ int32_t decimalCharLength = U16_LENGTH(decimalChar);
+ int32_t groupingStringLength = groupingString->length();
+ int32_t groupingCharLength = U16_LENGTH(groupingChar);
+
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;
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;
// 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;
+ }
+#endif
digits.set(parsedNum.toStringPiece(), err);
if (U_FAILURE(err)) {
+#ifdef FMT_DEBUG
+ printf(" err setting %s\n", u_errorName(err));
+#endif
parsePosition.setErrorIndex(position);
return FALSE;
}
int32_t affixCharLength = U16_LENGTH(affixChar);
UnicodeSet *affixSet;
- DecimalFormatStaticSets::initSets(&status);
-
if (!lenient) {
affixSet = DecimalFormatStaticSets::gStaticSets->fStrictDashEquivalents;
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
}
}
}
}
+#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
}
/**
*/
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
}
/**
*/
void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
fExponentSignAlwaysShown = expSignAlways;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
//------------------------------------------------------------------------------
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
}
}
#ifdef FMT_DEBUG
UnicodeString s;
- s.append("\"").append(pattern).append("\"->");
+ s.append((UnicodeString)"\"").append(pattern).append((UnicodeString)"\"->");
debugout(s);
#endif
}
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
}
*/
void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
NumberFormat::setMaximumIntegerDigits(_min(newValue, kDoubleIntegerDigits));
+#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;
+#if UCONFIG_FORMAT_FASTPATHS_49
+ handleChanged();
+#endif
}
void DecimalFormat::setMaximumSignificantDigits(int32_t max) {
int32_t min = _min(fMinSignificantDigits, max);
fMinSignificantDigits = min;
fMaxSignificantDigits = max;
+#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,
}
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 {
}
}
-
+#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,
//static const char I64_MIN_REP[] = "9223372036854775808";
+static const uint8_t DIGIT_HAVE_NONE=0;
+static const uint8_t DIGIT_HAVE_DOUBLE=1;
+static const uint8_t DIGIT_HAVE_INT64=2;
+
U_NAMESPACE_BEGIN
// -------------------------------------
fDecNumber = fStorage.getAlias();
uprv_decNumberZero(fDecNumber);
- fDouble = 0.0;
- fHaveDouble = TRUE;
+ internalSetDouble(0.0);
}
// -------------------------------------
// Avoid potential races with that happening with other.fDouble
// while we are doing the assignment.
Mutex mutex;
- fDouble = other.fDouble;
- fHaveDouble = other.fHaveDouble;
+
+ if(other.fHave==kDouble) {
+ fUnion.fDouble = other.fUnion.fDouble;
+ } else if(other.fHave==kInt64) {
+ fUnion.fInt64 = other.fUnion.fInt64;
+ }
+ fHave = other.fHave;
}
}
return *this;
{
uprv_decNumberZero(fDecNumber);
uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
- fDouble = 0.0;
- fHaveDouble = TRUE;
+ internalSetDouble(0.0);
}
} else {
fDecNumber->bits |= DECNEG;
}
- fHaveDouble = FALSE;
+ internalClear();
}
// -------------------------------------
adjustedDigits = 0;
}
fDecNumber->exponent = d - adjustedDigits;
- fHaveDouble = FALSE;
+ internalClear();
}
int32_t
fDecNumber->lsu[0] = 0;
}
fDecNumber->digits = c;
- fHaveDouble = FALSE;
+ internalClear();
}
int32_t
U_ASSERT(v>='0' && v<='9');
v &= 0x0f;
fDecNumber->lsu[count-i-1] = v;
- fHaveDouble = FALSE;
+ internalClear();
}
char
fDecNumber->exponent--;
}
}
- fHaveDouble = FALSE;
+ internalClear();
}
// -------------------------------------
char decimalSeparator;
{
Mutex mutex;
- if (fHaveDouble) {
- return fDouble;
+ if (fHave == kDouble) {
+ return fUnion.fDouble;
+ } else if(fHave == kInt64) {
+ return (double)fUnion.fInt64;
}
decimalSeparator = gDecimal;
}
tDouble = std::numeric_limits<double>::max();
}
if (!isPositive()) {
- tDouble = -fDouble;
+ tDouble = -tDouble; //this was incorrectly "-fDouble" originally.
}
} else {
MaybeStackArray<char, MAX_DBL_DIGITS+18> s;
{
Mutex mutex;
DigitList *nonConstThis = const_cast<DigitList *>(this);
- nonConstThis->fDouble = tDouble;
- nonConstThis->fHaveDouble = TRUE;
+ nonConstThis->internalSetDouble(tDouble);
gDecimal = decimalSeparator;
}
return tDouble;
* Return zero if the number cannot be represented.
*/
int64_t DigitList::getInt64() /*const*/ {
+ if(fHave==kInt64) {
+ return fUnion.fInt64;
+ }
// Truncate if non-integer.
// Return 0 if out of range.
// Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits)
DigitList::set(int32_t source)
{
set((int64_t)source);
- fDouble = source;
- fHaveDouble = TRUE;
+ internalSetDouble(source);
}
// -------------------------------------
U_ASSERT(uprv_strlen(str) < sizeof(str));
uprv_decNumberFromString(fDecNumber, str, &fContext);
- fDouble = (double)source;
- fHaveDouble = TRUE;
+ internalSetDouble(source);
+}
+
+/**
+ * @param maximumDigits The maximum digits to be generated. If zero,
+ * there is no maximum -- generate all digits.
+ */
+void
+DigitList::setInteger(int64_t source)
+{
+ fDecNumber=NULL;
+ internalSetInt64(source);
}
if ((fContext.status & DEC_Conversion_syntax) != 0) {
status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
}
- fHaveDouble = FALSE;
+ internalClear();
}
/**
// Create a decNumber from the string.
uprv_decNumberFromString(fDecNumber, rep, &fContext);
uprv_decNumberTrim(fDecNumber);
- fDouble = source;
- fHaveDouble = TRUE;
+ internalSetDouble(source);
}
// -------------------------------------
ensureCapacity(requiredDigits, status);
}
uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
- fHaveDouble = FALSE;
+ internalClear();
}
// -------------------------------------
return;
}
uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
- fHaveDouble = FALSE;
+ internalClear();
}
// -------------------------------------
uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext);
fContext.digits = savedDigits;
uprv_decNumberTrim(fDecNumber);
- fHaveDouble = FALSE;
+ internalClear();
}
uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext);
trim();
- fHaveDouble = FALSE;
+ internalClear();
}
// -------------------------------------
}
+
+void * U_EXPORT2 DigitList::operator new(size_t size, void *stack, EStackMode mode) U_NO_THROW {
+ return stack;
+}
+
+
U_NAMESPACE_END
#endif // #if !UCONFIG_NO_FORMATTING
/*
******************************************************************************
*
-* Copyright (C) 1997-2011, International Business Machines
+* Copyright (C) 1997-2012, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
#endif
+enum EStackMode { kOnStack };
+
/**
* Digit List is actually a Decimal Floating Point number.
* The original implementation has been replaced by a thin wrapper onto a
*/
void set(int64_t source);
+ /**
+ * Utility routine to set the value of the digit list from an int64.
+ * Does not set the decnumber unless requested later
+ * If a non-zero maximumDigits is specified, no more than that number of
+ * significant digits will be produced.
+ * @param source The value to be set
+ */
+ void setInteger(int64_t source);
+
/**
* Utility routine to set the value of the digit list from a decimal number
* string.
* This is an optimization for the formatting implementation, which may
* ask for the double value multiple times.
*/
- double fDouble;
- UBool fHaveDouble;
+ union DoubleOrInt64 {
+ double fDouble;
+ int64_t fInt64;
+ } fUnion;
+ enum EHave {
+ kNone=0,
+ kDouble,
+ kInt64
+ } fHave;
UBool shouldRoundUp(int32_t maximumDigits) const;
+
+ public:
+
+ using UMemory::operator new;
+
+ /**
+ * Placement new for stack usage
+ * @internal
+ */
+ static void * U_EXPORT2 operator new(size_t size, void *onStack, EStackMode mode) U_NO_THROW;
+
+ private:
+ inline void internalSetDouble(double d) {
+ fHave = kDouble;
+ fUnion.fDouble=d;
+ }
+ inline void internalSetInt64(int64_t d) {
+ fHave = kInt64;
+ fUnion.fInt64=d;
+ }
+ inline void internalClear() {
+ fHave = kNone;
+ }
};
/*
*******************************************************************************
-* Copyright (C) 1997-2011, International Business Machines Corporation and *
+* Copyright (C) 1997-2012, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
+struct FmtStackData {
+ DigitList stackDecimalNum; // 128
+ //CharString stackDecimalStr; // 64
+ // -----
+ // 192 total
+};
+
+
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
// NOTE: As of 3.0, there are limitations to the UObject API. It does
UErrorCode status = U_ZERO_ERROR;
if (source.fDecimalNum != NULL) {
- fDecimalNum = new DigitList(*source.fDecimalNum);
+ fDecimalNum = new DigitList(*source.fDecimalNum); // TODO: use internal digit list
}
if (source.fDecimalStr != NULL) {
fDecimalStr = new CharString(*source.fDecimalStr, status);
fType = kLong;
fValue.fInt64 = 0;
+
delete fDecimalStr;
fDecimalStr = NULL;
+
+#if UCONFIG_INTERNAL_DIGITLIST
+ FmtStackData *stackData = (FmtStackData*)fStackData;
+ if(fDecimalNum != &(stackData->stackDecimalNum)) {
+ delete fDecimalNum;
+ } else {
+ fDecimalNum->~DigitList(); // destruct, don't deallocate
+ }
+#else
delete fDecimalNum;
+#endif
fDecimalNum = NULL;
}
// from parsing, or from the user setting a decimal number, fDecimalNum
// would already be set.
//
- fDecimalNum = new DigitList;
+ fDecimalNum = new DigitList; // TODO: use internal digit list
if (fDecimalNum == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return "";
}
+#if UCONFIG_INTERNAL_DIGITLIST
+DigitList *
+Formattable::getInternalDigitList() {
+ FmtStackData *stackData = (FmtStackData*)fStackData;
+ if(fDecimalNum != &(stackData->stackDecimalNum)) {
+ delete fDecimalNum;
+ fDecimalNum = new (&(stackData->stackDecimalNum), kOnStack) DigitList();
+ } else {
+ fDecimalNum->clear();
+ }
+ return fDecimalNum;
+}
+#endif
// ---------------------------------------
void
Formattable::adoptDigitList(DigitList *dl) {
- dispose();
+ if(fDecimalNum==dl) {
+ fDecimalNum = NULL; // don't delete
+ }
+ dispose();
+
+ fDecimalNum = dl;
- fDecimalNum = dl;
+ if(dl==NULL) { // allow adoptDigitList(NULL) to clear
+ return;
+ }
// Set the value into the Union of simple type values.
// Cannot use the set() functions because they would delete the fDecimalNum value,
// The decNumber library requires nul-terminated input. StringPiece input
// is not guaranteed nul-terminated. Too bad.
// CharString automatically adds the nul.
- DigitList *dnum = new DigitList();
+ DigitList *dnum = new DigitList(); // TODO: use getInternalDigitList
if (dnum == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
#ifdef FMT_DEBUG
#include <stdio.h>
-static void debugout(UnicodeString s) {
+static inline void debugout(UnicodeString s) {
char buf[2000];
s.extract((int32_t) 0, s.length(), buf);
printf("%s", buf);
#include "unicode/stringpiece.h"
#include "unicode/curramt.h"
+/**
+ * \def UNUM_DECIMFORMAT_INTERNAL_SIZE
+ * @internal
+ */
+#if UCONFIG_FORMAT_FASTPATHS_49
+#define UNUM_DECIMALFORMAT_INTERNAL_SIZE 16
+#endif
+
U_NAMESPACE_BEGIN
class DigitList;
DecimalFormatSymbols* symbolsToAdopt,
UNumberFormatStyle style,
UErrorCode& status);
+
+
+#if UCONFIG_HAVE_PARSEALLINPUT
+ /**
+ * @internal
+ */
+ void setParseAllInput(UNumberFormatAttributeValue value);
+#endif
+
#endif /* U_HIDE_INTERNAL_API */
/**
* Initialize all fields of a new DecimalFormatter.
* Common code for use by constructors.
*/
- void init();
+ void init(UErrorCode& status);
/**
* Do real work of constructing a new DecimalFormat.
// Information needed for DecimalFormat to format/parse currency plural.
CurrencyPluralInfo* fCurrencyPluralInfo;
+#if UCONFIG_HAVE_PARSEALLINPUT
+ UNumberFormatAttributeValue fParseAllInput;
+#endif
+
+
protected:
/**
* @stable ICU 2.8
*/
static const int32_t kMaxScientificIntegerDigits;
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+ private:
+ /**
+ * Internal state.
+ * @internal
+ */
+ uint8_t fReserved[UNUM_DECIMALFORMAT_INTERNAL_SIZE];
+
+
+ /**
+ * Called whenever any state changes. Recomputes whether fastpath is OK to use.
+ */
+ void handleChanged();
+#endif
};
inline UnicodeString&
/*
********************************************************************************
-* Copyright (C) 1997-2011, International Business Machines
+* Copyright (C) 1997-2012, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************************
*
*/
DigitList *getDigitList() const { return fDecimalNum;}
+#if UCONFIG_INTERNAL_DIGITLIST
+ /**
+ * @internal
+ */
+ DigitList *getInternalDigitList();
+#endif
+
+
/**
* Adopt, and set value from, a DigitList
* Internal Function, do not use.
} fValue;
CharString *fDecimalStr;
+
DigitList *fDecimalNum;
+#if UCONFIG_INTERNAL_DIGITLIST
+ char fStackData[128]; // must be big enough for DigitList
+#endif
+
Type fType;
UnicodeString fBogus; // Bogus string when it's needed.
};
U_STABLE int32_t U_EXPORT2
unum_countAvailable(void);
+#if UCONFIG_HAVE_PARSEALLINPUT
+/**
+ * @internal
+ */
+typedef enum UNumberFormatAttributeValue {
+ /** @internal */
+ UNUM_NO = 0,
+ /** @internal */
+ UNUM_YES = 1,
+ /** @internal */
+ UNUM_MAYBE = 2
+} UNumberFormatAttributeValue;
+#endif
+
/** The possible UNumberFormat numeric attributes @stable ICU 2.0 */
typedef enum UNumberFormatAttribute {
/** Parse integers only */
* @stable ICU 3.0
*/
UNUM_LENIENT_PARSE
+
+#if UCONFIG_HAVE_PARSEALLINPUT
+ /** Consume all input. (may use fastpath). Set to UNUM_YES (require fastpath), UNUM_NO (skip fastpath), or UNUM_MAYBE (heuristic).
+ * @internal
+ */
+ ,UNUM_PARSE_ALL_INPUT
+#endif
+
} UNumberFormatAttribute;
/**
df->setSecondaryGroupingSize(newValue);
break;
+#if UCONFIG_HAVE_PARSEALLINPUT
+ case UNUM_PARSE_ALL_INPUT:
+ df->setParseAllInput((UNumberFormatAttributeValue)newValue);
+ break;
+#endif
+
default:
/* Shouldn't get here anyway */
break;
unum_close(nf);
}
-static void TestNBSPPatternRtNum(const char *testcase, UNumberFormat *nf, double myNumber) {
+static void TestNBSPPatternRtNum(const char *testcase, int line, UNumberFormat *nf, double myNumber) {
UErrorCode status = U_ZERO_ERROR;
UChar myString[20];
char tmpbuf[200];
double aNumber = -1.0;
unum_formatDouble(nf, myNumber, myString, 20, NULL, &status);
- log_verbose("%s: formatted %.2f into %s\n", testcase, myNumber, u_austrcpy(tmpbuf, myString));
+ log_verbose("%s:%d: formatted %.2f into %s\n", testcase, line, myNumber, u_austrcpy(tmpbuf, myString));
if(U_FAILURE(status)) {
- log_err("%s: failed format of %.2g with %s\n", testcase, myNumber, u_errorName(status));
+ log_err("%s:%d: failed format of %.2g with %s\n", testcase, line, myNumber, u_errorName(status));
return;
}
aNumber = unum_parse(nf, myString, -1, NULL, &status);
if(U_FAILURE(status)) {
- log_err("%s: failed parse with %s\n", testcase, u_errorName(status));
+ log_err("%s:%d: failed parse with %s\n", testcase, line, u_errorName(status));
return;
}
if(uprv_fabs(aNumber-myNumber)>.001) {
- log_err("FAIL: %s: formatted %.2f, parsed into %.2f\n", testcase, myNumber, aNumber);
+ log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
} else {
- log_verbose("PASS: %s: formatted %.2f, parsed into %.2f\n", testcase, myNumber, aNumber);
+ log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
}
}
static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) {
- TestNBSPPatternRtNum(testcase, nf, 12345.);
- TestNBSPPatternRtNum(testcase, nf, -12345.);
+ TestNBSPPatternRtNum(testcase, __LINE__, nf, 12345.);
+ TestNBSPPatternRtNum(testcase, __LINE__, nf, -12345.);
}
static void TestNBSPInPattern(void) {
testcase="ar_AE UNUM_CURRENCY";
nf = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status);
if(U_FAILURE(status) || nf == NULL) {
- log_data_err("%s: unum_open failed with %s (Are you missing data?)\n", testcase, u_errorName(status));
+ log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, testcase, u_errorName(status));
return;
}
TestNBSPPatternRT(testcase, nf);
CASE(52,TestAvailableNumberingSystems);
CASE(53,TestRoundingPattern);
CASE(54,Test9087);
+ CASE(55,TestFormatFastpaths);
default: name = ""; break;
}
}
unum_close(fmt);
}
+
+#include "dcfmtimp.h"
+
+void NumberFormatTest::TestFormatFastpaths() {
+#if UCONFIG_FORMAT_FASTPATHS_49
+ logln("Sizeof DecimalFormat = %d, Sizeof DecimalFormatInternal=%d, UNUM_DECIMALFORMAT_INTERNAL_SIZE=%d\n",
+ sizeof(DecimalFormat), sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE);
+ if(UNUM_DECIMALFORMAT_INTERNAL_SIZE < sizeof(DecimalFormatInternal)) {
+ errln("Error: sizeof(DecimalFormatInternal)=%d but UNUM_DECIMALFORMAT_INTERNAL_SIZE is only %d. Increase the #define?\n", sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE);
+ } else if(UNUM_DECIMALFORMAT_INTERNAL_SIZE > (sizeof(DecimalFormatInternal)+16)) {
+ infoln("Note: sizeof(DecimalFormatInternal)=%d but UNUM_DECIMALFORMAT_INTERNAL_SIZE is %d. Decrease the #define? sizeof(DecimalFormat)=%d\n", sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE, sizeof(DecimalFormat));
+ }
+#else
+ infoln("NOTE: UCONFIG_FORMAT_FASTPATHS not set, test skipped.");
+#endif
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
void TestExplicitParents();
void TestAvailableNumberingSystems();
void Test9087();
+ void TestFormatFastpaths();
private:
#include "unicode/utimer.h"
#include "udbgutil.h"
#include "unicode/ustring.h"
-
+#include "unicode/decimfmt.h"
void runTests(void);
#ifndef ITERATIONS
}
protected:
virtual UNumberFormat* initFmt() {
- return unum_open(UNUM_PATTERN_DECIMAL, fPat.getTerminatedBuffer(), 1, "en_US", 0, &setupStatus);
+ return unum_open(UNUM_PATTERN_DECIMAL, fPat.getTerminatedBuffer(), -1, "en_US", 0, &setupStatus);
}
virtual const char *getClassName() {
return "NumTest";
}
protected:
virtual UNumberFormat* initFmt() {
- return unum_open(UNUM_PATTERN_DECIMAL, fPat.getTerminatedBuffer(), 1, "en_US", 0, &setupStatus);
+ return unum_open(UNUM_PATTERN_DECIMAL, fPat.getTerminatedBuffer(), -1, "en_US", 0, &setupStatus);
}
virtual const char *getClassName() {
return "NumFmtTest";
}
protected:
virtual UNumberFormat* initFmt() {
- return unum_open(UNUM_PATTERN_DECIMAL, fPat.getTerminatedBuffer(), 1, "en_US", 0, &setupStatus);
+ return unum_open(UNUM_PATTERN_DECIMAL, fPat.getTerminatedBuffer(), -1, "en_US", 0, &setupStatus);
}
virtual const char *getClassName() {
return "NumFmtInt64Test";
#define DO_NumFmtInt64Test(p,n,x) { NumFmtInt64Test t(p,n,x,__FILE__,__LINE__); runTestOn(t); }
+
+class NumFmtStringPieceTest : public HowExpensiveTest {
+private:
+ const StringPiece &fExpect;
+ UNumberFormat *fFmt;
+ UnicodeString fPat;
+ UnicodeString fString;
+ const UChar *fStr;
+ int32_t fLen;
+ const char *fFile;
+ int fLine;
+ const char *fCPat;
+ const char *fCStr;
+ char name[100];
+public:
+ virtual const char *getName() {
+ if(name[0]==0) {
+ sprintf(name,"%s:p=|%s|,str=|%s|,sp=|%s|",getClassName(),fCPat,fCStr, fExpect.data());
+ }
+ return name;
+ }
+protected:
+ virtual UNumberFormat* initFmt() {
+ DecimalFormat *d = new DecimalFormat(setupStatus);
+ UParseError pe;
+ d->applyPattern(fPat, pe, setupStatus);
+ return (UNumberFormat*) d;
+ }
+ virtual const char *getClassName() {
+ return "NumFmtStringPieceTest";
+ }
+public:
+ NumFmtStringPieceTest(const char *pat, const char *num, const StringPiece& expect, const char *FILE, int LINE)
+ : HowExpensiveTest("(n/a)",FILE, LINE),
+ fExpect(expect),
+ fFmt(0),
+ fPat(pat, -1, US_INV),
+ fString(num,-1,US_INV),
+ fStr(fString.getTerminatedBuffer()),
+ fLen(u_strlen(fStr)),
+ fFile(FILE),
+ fLine(LINE),
+ fCPat(pat),
+ fCStr(num)
+ {
+ name[0]=0;
+ }
+ void warmup() {
+ fFmt = initFmt();
+ UnicodeString buf;
+ if(U_SUCCESS(setupStatus)) {
+ buf.remove();
+ ((const DecimalFormat*)fFmt)->format(fExpect, buf, NULL, setupStatus);
+ if(!U_SUCCESS(setupStatus)
+ || fString!=buf
+ ) {
+ char strBuf[200];
+ u_strToUTF8(strBuf,200,NULL,buf.getTerminatedBuffer(),buf.length()+1,&setupStatus);
+ printf("%s:%d: warmup() %s got %s (len %d) expected %s (len %d), err %s\n",
+ fFile,fLine,getName(),strBuf,buf.length(),fCStr,fLen, u_errorName(setupStatus));
+ setupStatus = U_INTERNAL_PROGRAM_ERROR;
+ }
+ }
+ }
+
+ int32_t run() {
+ int32_t trial;
+ int i;
+ UnicodeString buf;
+ if(U_SUCCESS(setupStatus)) {
+ for(i=0;i<U_LOTS_OF_TIMES;i++){
+ buf.remove();
+ ((const DecimalFormat*)fFmt)->format(fExpect, buf, NULL, setupStatus);
+ }
+ }
+ return i;
+ }
+ virtual ~NumFmtStringPieceTest(){}
+};
+
+#define DO_NumFmtStringPieceTest(p,n,x) { NumFmtStringPieceTest t(p,n,x,__FILE__,__LINE__); runTestOn(t); }
+
// TODO: move, scope.
static UChar pattern[] = { 0x23 }; // '#'
static UChar strdot[] = { '2', '.', '0', 0 };
#ifndef SKIP_NUMFORMAT_TESTS
// format tests
{
+
+ DO_NumFmtInt64Test("0000","0001",1);
+ DO_NumFmtInt64Test("0000","0000",0);
+ StringPiece sp3456("3456");
+ DO_NumFmtStringPieceTest("0000","3456",sp3456);
+ DO_NumFmtStringPieceTest("#","3456",sp3456);
+ StringPiece sp3("3");
+ DO_NumFmtStringPieceTest("0000","0003",sp3);
+ DO_NumFmtStringPieceTest("#","3",sp3);
+ StringPiece spn3("-3");
+ DO_NumFmtStringPieceTest("0000","-0003",spn3);
+ DO_NumFmtStringPieceTest("#","-3",spn3);
+ StringPiece spPI("123.456");
+ DO_NumFmtStringPieceTest("#.0000","123.4560",spPI);
+ DO_NumFmtStringPieceTest("#.00","123.46",spPI);
+
+#if 1
DO_NumFmtTest("#","0",0.0);
DO_NumFmtTest("#","12345",12345);
DO_NumFmtTest("#","-2",-2);
#include "putilimp.h"
#include "unicode/ulocdata.h"
#include "unicode/ucnv.h"
+
/*
To add a new enum type
(For example: UShoeSize with values USHOE_WIDE=0, USHOE_REGULAR, USHOE_NARROW, USHOE_COUNT)
#if defined (CYGWINMSVC)
{ "build.cygwinmsvc", paramInteger, "b", 1},
#endif
-
+ { "uconfig.internal_digitlist", paramInteger, "b", UCONFIG_INTERNAL_DIGITLIST},
+ { "uconfig.have_parseallinput", paramInteger, "b", UCONFIG_HAVE_PARSEALLINPUT},
+ { "uconfig.format_fastpaths_49",paramInteger, "b", UCONFIG_FORMAT_FASTPATHS_49},
};