From 43b918a0c83432c626c9e1a9f90661113db7ae59 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Wed, 30 May 2012 00:41:57 +0000 Subject: [PATCH] ICU-9258 merge from branches, performance improvements X-SVN-Rev: 31881 --- icu4c/source/common/cmemory.c | 25 +- icu4c/source/common/cmemory.h | 18 +- icu4c/source/common/unicode/uconfig.h | 34 ++ icu4c/source/i18n/dcfmtimp.h | 43 ++ icu4c/source/i18n/decimfmt.cpp | 510 ++++++++++++++++-- icu4c/source/i18n/digitlst.cpp | 79 ++- icu4c/source/i18n/digitlst.h | 47 +- icu4c/source/i18n/fmtable.cpp | 51 +- icu4c/source/i18n/numfmt.cpp | 2 +- icu4c/source/i18n/unicode/decimfmt.h | 39 +- icu4c/source/i18n/unicode/fmtable.h | 15 +- icu4c/source/i18n/unicode/unum.h | 22 + icu4c/source/i18n/unum.cpp | 6 + icu4c/source/test/cintltst/cnumtst.c | 18 +- icu4c/source/test/intltest/numfmtst.cpp | 18 + icu4c/source/test/intltest/numfmtst.h | 1 + .../perf/howExpensiveIs/howExpensiveIs.cpp | 107 +++- icu4c/source/tools/toolutil/udbgutil.cpp | 5 +- 18 files changed, 947 insertions(+), 93 deletions(-) create mode 100644 icu4c/source/i18n/dcfmtimp.h diff --git a/icu4c/source/common/cmemory.c b/icu4c/source/common/cmemory.c index b8916077038..d0839215207 100644 --- a/icu4c/source/common/cmemory.c +++ b/icu4c/source/common/cmemory.c @@ -1,7 +1,7 @@ /* ****************************************************************************** * -* Copyright (C) 2002-2011, International Business Machines +* Copyright (C) 2002-2012, International Business Machines * Corporation and others. All Rights Reserved. * ****************************************************************************** @@ -36,8 +36,23 @@ static UMemFreeFn *pFree; * Used to prevent changing out the heap functions after allocations have been made */ static UBool gHeapInUse; +#if U_DEBUG && defined(UPRV_MALLOC_COUNT) +#include +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) { @@ -52,6 +67,10 @@ uprv_malloc(size_t s) { 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) { @@ -73,6 +92,10 @@ uprv_realloc(void * buffer, size_t size) { 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); diff --git a/icu4c/source/common/cmemory.h b/icu4c/source/common/cmemory.h index c48e7a4c3ef..8feb7009c21 100644 --- a/icu4c/source/common/cmemory.h +++ b/icu4c/source/common/cmemory.h @@ -1,7 +1,7 @@ /* ****************************************************************************** * -* Copyright (C) 1997-2011, International Business Machines +* Copyright (C) 1997-2012, International Business Machines * Corporation and others. All Rights Reserved. * ****************************************************************************** @@ -29,6 +29,10 @@ #include "unicode/utypes.h" #include "unicode/localpointer.h" +#if U_DEBUG && defined(UPRV_MALLOC_COUNT) +#include +#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) @@ -331,6 +335,9 @@ private: template inline T *MaybeStackArray::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) { @@ -365,6 +372,9 @@ inline T *MaybeStackArray::orphanOrClone(int32_t length, int32 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; } @@ -501,6 +511,9 @@ template inline H *MaybeStackHeaderAndArray::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) { @@ -537,6 +550,9 @@ inline H *MaybeStackHeaderAndArray::orphanOrClone(int32_t l } 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; diff --git a/icu4c/source/common/unicode/uconfig.h b/icu4c/source/common/unicode/uconfig.h index f39eede23f1..ab03755c2a9 100644 --- a/icu4c/source/common/unicode/uconfig.h +++ b/icu4c/source/common/unicode/uconfig.h @@ -404,4 +404,38 @@ # 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 diff --git a/icu4c/source/i18n/dcfmtimp.h b/icu4c/source/i18n/dcfmtimp.h new file mode 100644 index 00000000000..6bc2c0f0871 --- /dev/null +++ b/icu4c/source/i18n/dcfmtimp.h @@ -0,0 +1,43 @@ +/* +******************************************************************************** +* 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 diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index ae68388cf17..ff15a14765a 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -69,10 +69,22 @@ #include #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(reserved); +} +inline const DecimalFormatInternal& internalData(const uint8_t *reserved) { + return *reinterpret_cast(reserved); +} +#else +#endif + /* For currency parsing purose, * Need to remember all prefix patterns and suffix patterns of * every currency format pattern, @@ -180,12 +192,15 @@ U_CDECL_END #ifdef FMT_DEBUG #include -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("",""); +#define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null)) #else #define debugout(x) #define debug(x) @@ -247,7 +262,7 @@ inline int32_t _max(int32_t a, int32_t b) { return (a fgCurrencySignCountZero) { setCurrencyInternally(getCurrency(), status); } +#if UCONFIG_FORMAT_FASTPATHS_49 + DecimalFormatInternal &data = internalData(fReserved); + data.fFastpathStatus = kFastpathNO; // allow it to be calculated + handleChanged(); +#endif } @@ -654,7 +684,8 @@ DecimalFormat::~DecimalFormat() 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; } @@ -744,6 +775,9 @@ DecimalFormat::operator=(const DecimalFormat& rhs) copyHashForAffix(rhs.fPluralAffixesForCurrency, fPluralAffixesForCurrency, status); } } +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif return *this; } @@ -966,6 +1000,43 @@ DecimalFormat::format(int32_t number, 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& @@ -973,8 +1044,8 @@ DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& fieldPosition) const { - FieldPositionOnlyHandler handler(fieldPosition); - return _format(number, appendTo, handler); + FieldPositionOnlyHandler handler(fieldPosition); + return _format(number, appendTo, handler); } UnicodeString& @@ -992,7 +1063,76 @@ DecimalFormat::_format(int64_t number, 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); @@ -1055,6 +1195,47 @@ DecimalFormat::format(const StringPiece &number, 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)) { @@ -1672,7 +1853,12 @@ void DecimalFormat::parse(const UnicodeString& text, // 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. } @@ -1680,8 +1866,10 @@ void DecimalFormat::parse(const UnicodeString& text, 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, @@ -1689,8 +1877,11 @@ void DecimalFormat::parse(const UnicodeString& 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; } } @@ -1699,7 +1890,10 @@ void DecimalFormat::parse(const UnicodeString& text, 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 { @@ -1878,8 +2072,121 @@ UBool DecimalFormat::subparse(const UnicodeString& text, 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("")); } 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=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); @@ -1935,7 +2242,6 @@ UBool DecimalFormat::subparse(const UnicodeString& text, // 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? @@ -1948,10 +2254,14 @@ UBool DecimalFormat::subparse(const UnicodeString& text, } 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; @@ -1959,11 +2269,6 @@ UBool DecimalFormat::subparse(const UnicodeString& text, 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; @@ -2185,6 +2490,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text, parsePosition.setIndex(oldStart); parsePosition.setErrorIndex(position); + debug("strictFail!"); return FALSE; } @@ -2195,6 +2501,10 @@ UBool DecimalFormat::subparse(const UnicodeString& text, // 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; @@ -2226,6 +2536,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text, // Fail if neither or both if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) { parsePosition.setErrorIndex(position); + debug("neither or both"); return FALSE; } @@ -2239,15 +2550,34 @@ UBool DecimalFormat::subparse(const UnicodeString& text, 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; } @@ -2345,8 +2675,6 @@ int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix, int32_t affixCharLength = U16_LENGTH(affixChar); UnicodeSet *affixSet; - DecimalFormatStaticSets::initSets(&status); - if (!lenient) { affixSet = DecimalFormatStaticSets::gStaticSets->fStrictDashEquivalents; @@ -2707,6 +3035,9 @@ DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) setCurrencyForSymbols(); } expandAffixes(NULL); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ // Setting the symbols is equlivalent to adopting a newly created localized @@ -2716,6 +3047,9 @@ void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) { adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols)); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } @@ -2745,12 +3079,18 @@ DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) } } } +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) { adoptCurrencyPluralInfo(info.clone()); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } @@ -2791,6 +3131,9 @@ DecimalFormat::setCurrencyForSymbols() { } ec = U_ZERO_ERROR; // reset local error code! setCurrencyInternally(c, ec); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } @@ -2813,6 +3156,9 @@ DecimalFormat::setPositivePrefix(const UnicodeString& newValue) fPositivePrefix = newValue; delete fPosPrefixPattern; fPosPrefixPattern = 0; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ @@ -2834,6 +3180,9 @@ DecimalFormat::setNegativePrefix(const UnicodeString& newValue) fNegativePrefix = newValue; delete fNegPrefixPattern; fNegPrefixPattern = 0; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ @@ -2855,6 +3204,9 @@ DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) fPositiveSuffix = newValue; delete fPosSuffixPattern; fPosSuffixPattern = 0; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ @@ -2876,6 +3228,9 @@ DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) fNegativeSuffix = newValue; delete fNegSuffixPattern; fNegSuffixPattern = 0; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ @@ -2916,6 +3271,9 @@ DecimalFormat::setMultiplier(int32_t newValue) fMultiplier->set(newValue); } } +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -2957,6 +3315,9 @@ void DecimalFormat::setRoundingIncrement(double newValue) { // or fRoundingIncrement could not be created. delete fRoundingIncrement; fRoundingIncrement = NULL; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -2980,6 +3341,9 @@ DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const { */ void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) { fRoundingMode = roundingMode; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -3009,6 +3373,9 @@ int32_t DecimalFormat::getFormatWidth() const { */ void DecimalFormat::setFormatWidth(int32_t width) { fFormatWidth = (width > 0) ? width : 0; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } UnicodeString DecimalFormat::getPadCharacterString() const { @@ -3022,6 +3389,9 @@ void DecimalFormat::setPadCharacter(const UnicodeString &padChar) { else { fPad = kDefaultPad; } +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -3066,6 +3436,9 @@ DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const { */ void DecimalFormat::setPadPosition(EPadPosition padPos) { fPadPosition = padPos; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -3093,6 +3466,9 @@ UBool DecimalFormat::isScientificNotation() { */ void DecimalFormat::setScientificNotation(UBool useScientific) { fUseExponentialNotation = useScientific; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -3121,6 +3497,9 @@ int8_t DecimalFormat::getMinimumExponentDigits() const { */ void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) { fMinExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -3152,6 +3531,9 @@ UBool DecimalFormat::isExponentSignAlwaysShown() { */ void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) { fExponentSignAlwaysShown = expSignAlways; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ @@ -3171,6 +3553,9 @@ void DecimalFormat::setGroupingSize(int32_t newValue) { fGroupingSize = newValue; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ @@ -3187,6 +3572,9 @@ void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) { fGroupingSize2 = newValue; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ @@ -3205,6 +3593,9 @@ void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) { fDecimalSeparatorAlwaysShown = newValue; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } //------------------------------------------------------------------------------ @@ -3255,13 +3646,13 @@ void DecimalFormat::expandAffixes(const UnicodeString* pluralCount) { } #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 } @@ -4533,7 +4924,7 @@ DecimalFormat::applyPatternWithoutExpandAffix(const UnicodeString& pattern, } #ifdef FMT_DEBUG UnicodeString s; - s.append("\"").append(pattern).append("\"->"); + s.append((UnicodeString)"\"").append(pattern).append((UnicodeString)"\"->"); debugout(s); #endif @@ -4577,6 +4968,9 @@ DecimalFormat::applyPattern(const UnicodeString& pattern, } applyPatternWithoutExpandAffix(pattern, localized, parseError, status); expandAffixAdjustWidth(NULL); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } @@ -4588,6 +4982,9 @@ DecimalFormat::applyPatternInternally(const UnicodeString& pluralCount, UErrorCode& status) { applyPatternWithoutExpandAffix(pattern, localized, parseError, status); expandAffixAdjustWidth(&pluralCount); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } @@ -4598,6 +4995,9 @@ DecimalFormat::applyPatternInternally(const UnicodeString& pluralCount, */ void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { NumberFormat::setMaximumIntegerDigits(_min(newValue, kDoubleIntegerDigits)); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -4607,6 +5007,9 @@ void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { */ void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) { NumberFormat::setMinimumIntegerDigits(_min(newValue, kDoubleIntegerDigits)); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -4616,6 +5019,9 @@ void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) { */ void DecimalFormat::setMaximumFractionDigits(int32_t newValue) { NumberFormat::setMaximumFractionDigits(_min(newValue, kDoubleFractionDigits)); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } /** @@ -4625,6 +5031,9 @@ void DecimalFormat::setMaximumFractionDigits(int32_t newValue) { */ void DecimalFormat::setMinimumFractionDigits(int32_t newValue) { NumberFormat::setMinimumFractionDigits(_min(newValue, kDoubleFractionDigits)); +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } int32_t DecimalFormat::getMinimumSignificantDigits() const { @@ -4643,6 +5052,9 @@ void DecimalFormat::setMinimumSignificantDigits(int32_t min) { int32_t max = _max(fMaxSignificantDigits, min); fMinSignificantDigits = min; fMaxSignificantDigits = max; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } void DecimalFormat::setMaximumSignificantDigits(int32_t max) { @@ -4654,6 +5066,9 @@ 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 { @@ -4662,6 +5077,9 @@ UBool DecimalFormat::areSignificantDigitsUsed() const { void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) { fUseSignificantDigits = useSignificantDigits; +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } void DecimalFormat::setCurrencyInternally(const UChar* theCurrency, @@ -4696,6 +5114,9 @@ void DecimalFormat::setCurrencyInternally(const UChar* theCurrency, } expandAffixes(NULL); } +#if UCONFIG_FORMAT_FASTPATHS_49 + handleChanged(); +#endif } void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) { @@ -4709,12 +5130,18 @@ 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 { @@ -4853,7 +5280,14 @@ DecimalFormat::copyHashForAffixPattern(const Hashtable* source, } } - +#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, diff --git a/icu4c/source/i18n/digitlst.cpp b/icu4c/source/i18n/digitlst.cpp index 31361be5aa9..5d7eb92e93f 100644 --- a/icu4c/source/i18n/digitlst.cpp +++ b/icu4c/source/i18n/digitlst.cpp @@ -58,6 +58,10 @@ //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 // ------------------------------------- @@ -73,8 +77,7 @@ DigitList::DigitList() fDecNumber = fStorage.getAlias(); uprv_decNumberZero(fDecNumber); - fDouble = 0.0; - fHaveDouble = TRUE; + internalSetDouble(0.0); } // ------------------------------------- @@ -116,8 +119,13 @@ DigitList::operator=(const DigitList& other) // 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; @@ -190,8 +198,7 @@ DigitList::clear() { uprv_decNumberZero(fDecNumber); uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN); - fDouble = 0.0; - fHaveDouble = TRUE; + internalSetDouble(0.0); } @@ -278,7 +285,7 @@ DigitList::setPositive(UBool s) { } else { fDecNumber->bits |= DECNEG; } - fHaveDouble = FALSE; + internalClear(); } // ------------------------------------- @@ -293,7 +300,7 @@ DigitList::setDecimalAt(int32_t d) { adjustedDigits = 0; } fDecNumber->exponent = d - adjustedDigits; - fHaveDouble = FALSE; + internalClear(); } int32_t @@ -315,7 +322,7 @@ DigitList::setCount(int32_t c) { fDecNumber->lsu[0] = 0; } fDecNumber->digits = c; - fHaveDouble = FALSE; + internalClear(); } int32_t @@ -336,7 +343,7 @@ DigitList::setDigit(int32_t i, char v) { U_ASSERT(v>='0' && v<='9'); v &= 0x0f; fDecNumber->lsu[count-i-1] = v; - fHaveDouble = FALSE; + internalClear(); } char @@ -390,7 +397,7 @@ DigitList::append(char digit) fDecNumber->exponent--; } } - fHaveDouble = FALSE; + internalClear(); } // ------------------------------------- @@ -409,8 +416,10 @@ DigitList::getDouble() const char decimalSeparator; { Mutex mutex; - if (fHaveDouble) { - return fDouble; + if (fHave == kDouble) { + return fUnion.fDouble; + } else if(fHave == kInt64) { + return (double)fUnion.fInt64; } decimalSeparator = gDecimal; } @@ -438,7 +447,7 @@ DigitList::getDouble() const tDouble = std::numeric_limits::max(); } if (!isPositive()) { - tDouble = -fDouble; + tDouble = -tDouble; //this was incorrectly "-fDouble" originally. } } else { MaybeStackArray s; @@ -472,8 +481,7 @@ DigitList::getDouble() const { Mutex mutex; DigitList *nonConstThis = const_cast(this); - nonConstThis->fDouble = tDouble; - nonConstThis->fHaveDouble = TRUE; + nonConstThis->internalSetDouble(tDouble); gDecimal = decimalSeparator; } return tDouble; @@ -511,6 +519,9 @@ int32_t DigitList::getLong() /*const*/ * 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) @@ -682,8 +693,7 @@ void DigitList::set(int32_t source) { set((int64_t)source); - fDouble = source; - fHaveDouble = TRUE; + internalSetDouble(source); } // ------------------------------------- @@ -699,8 +709,18 @@ DigitList::set(int64_t 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); } @@ -738,7 +758,7 @@ DigitList::set(const StringPiece &source, UErrorCode &status) { if ((fContext.status & DEC_Conversion_syntax) != 0) { status = U_DECIMAL_NUMBER_SYNTAX_ERROR; } - fHaveDouble = FALSE; + internalClear(); } /** @@ -778,8 +798,7 @@ DigitList::set(double source) // Create a decNumber from the string. uprv_decNumberFromString(fDecNumber, rep, &fContext); uprv_decNumberTrim(fDecNumber); - fDouble = source; - fHaveDouble = TRUE; + internalSetDouble(source); } // ------------------------------------- @@ -800,7 +819,7 @@ DigitList::mult(const DigitList &other, UErrorCode &status) { ensureCapacity(requiredDigits, status); } uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext); - fHaveDouble = FALSE; + internalClear(); } // ------------------------------------- @@ -817,7 +836,7 @@ DigitList::div(const DigitList &other, UErrorCode &status) { return; } uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext); - fHaveDouble = FALSE; + internalClear(); } // ------------------------------------- @@ -867,7 +886,7 @@ DigitList::round(int32_t maximumDigits) uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext); fContext.digits = savedDigits; uprv_decNumberTrim(fDecNumber); - fHaveDouble = FALSE; + internalClear(); } @@ -884,7 +903,7 @@ DigitList::roundFixedPoint(int32_t maximumFractionDigits) { uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext); trim(); - fHaveDouble = FALSE; + internalClear(); } // ------------------------------------- @@ -903,6 +922,12 @@ DigitList::isZero() const } + +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 diff --git a/icu4c/source/i18n/digitlst.h b/icu4c/source/i18n/digitlst.h index c4e1d88e07b..7234afed05e 100644 --- a/icu4c/source/i18n/digitlst.h +++ b/icu4c/source/i18n/digitlst.h @@ -1,7 +1,7 @@ /* ****************************************************************************** * -* Copyright (C) 1997-2011, International Business Machines +* Copyright (C) 1997-2012, International Business Machines * Corporation and others. All Rights Reserved. * ****************************************************************************** @@ -66,6 +66,8 @@ template class U_I18N_API MaybeStackHeaderAndArraystackDecimalNum)) { + delete fDecimalNum; + } else { + fDecimalNum->~DigitList(); // destruct, don't deallocate + } +#else delete fDecimalNum; +#endif fDecimalNum = NULL; } @@ -695,7 +714,7 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) { // 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 ""; @@ -729,13 +748,33 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) { } +#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, @@ -765,7 +804,7 @@ Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &statu // 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; diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp index df768aef139..161559ace00 100644 --- a/icu4c/source/i18n/numfmt.cpp +++ b/icu4c/source/i18n/numfmt.cpp @@ -54,7 +54,7 @@ #ifdef FMT_DEBUG #include -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); diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h index 04cef429036..f483cffed2e 100644 --- a/icu4c/source/i18n/unicode/decimfmt.h +++ b/icu4c/source/i18n/unicode/decimfmt.h @@ -39,6 +39,14 @@ #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; @@ -747,6 +755,15 @@ public: DecimalFormatSymbols* symbolsToAdopt, UNumberFormatStyle style, UErrorCode& status); + + +#if UCONFIG_HAVE_PARSEALLINPUT + /** + * @internal + */ + void setParseAllInput(UNumberFormatAttributeValue value); +#endif + #endif /* U_HIDE_INTERNAL_API */ /** @@ -1864,7 +1881,7 @@ private: * 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. @@ -2261,6 +2278,11 @@ private: // Information needed for DecimalFormat to format/parse currency plural. CurrencyPluralInfo* fCurrencyPluralInfo; +#if UCONFIG_HAVE_PARSEALLINPUT + UNumberFormatAttributeValue fParseAllInput; +#endif + + protected: /** @@ -2293,6 +2315,21 @@ 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& diff --git a/icu4c/source/i18n/unicode/fmtable.h b/icu4c/source/i18n/unicode/fmtable.h index 641236fed49..694e2793256 100644 --- a/icu4c/source/i18n/unicode/fmtable.h +++ b/icu4c/source/i18n/unicode/fmtable.h @@ -1,6 +1,6 @@ /* ******************************************************************************** -* Copyright (C) 1997-2011, International Business Machines +* Copyright (C) 1997-2012, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************** * @@ -605,6 +605,14 @@ public: */ 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. @@ -641,8 +649,13 @@ private: } 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. }; diff --git a/icu4c/source/i18n/unicode/unum.h b/icu4c/source/i18n/unicode/unum.h index 3f9f291aac2..d26719797f9 100644 --- a/icu4c/source/i18n/unicode/unum.h +++ b/icu4c/source/i18n/unicode/unum.h @@ -715,6 +715,20 @@ unum_getAvailable(int32_t localeIndex); 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 */ @@ -762,6 +776,14 @@ typedef enum UNumberFormatAttribute { * @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; /** diff --git a/icu4c/source/i18n/unum.cpp b/icu4c/source/i18n/unum.cpp index 4fc3f5d4b8c..be519d4ef49 100644 --- a/icu4c/source/i18n/unum.cpp +++ b/icu4c/source/i18n/unum.cpp @@ -626,6 +626,12 @@ unum_setAttribute( UNumberFormat* fmt, 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; diff --git a/icu4c/source/test/cintltst/cnumtst.c b/icu4c/source/test/cintltst/cnumtst.c index 25c53a21715..81ba501d836 100644 --- a/icu4c/source/test/cintltst/cnumtst.c +++ b/icu4c/source/test/cintltst/cnumtst.c @@ -1888,32 +1888,32 @@ static void TestTextAttributeCrash(void) { 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) { @@ -1925,7 +1925,7 @@ 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); diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index 85028207da7..734465c6f3c 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -118,6 +118,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n CASE(52,TestAvailableNumberingSystems); CASE(53,TestRoundingPattern); CASE(54,Test9087); + CASE(55,TestFormatFastpaths); default: name = ""; break; } } @@ -6571,4 +6572,21 @@ NumberFormatTest::Test9087(void) 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 */ diff --git a/icu4c/source/test/intltest/numfmtst.h b/icu4c/source/test/intltest/numfmtst.h index da44791fb19..b95989bfe86 100644 --- a/icu4c/source/test/intltest/numfmtst.h +++ b/icu4c/source/test/intltest/numfmtst.h @@ -156,6 +156,7 @@ class NumberFormatTest: public CalendarTimeZoneTest { void TestExplicitParents(); void TestAvailableNumberingSystems(); void Test9087(); + void TestFormatFastpaths(); private: diff --git a/icu4c/source/test/perf/howExpensiveIs/howExpensiveIs.cpp b/icu4c/source/test/perf/howExpensiveIs/howExpensiveIs.cpp index 8f50d816db3..fcfd27b3f64 100644 --- a/icu4c/source/test/perf/howExpensiveIs/howExpensiveIs.cpp +++ b/icu4c/source/test/perf/howExpensiveIs/howExpensiveIs.cpp @@ -9,7 +9,7 @@ #include "unicode/utimer.h" #include "udbgutil.h" #include "unicode/ustring.h" - +#include "unicode/decimfmt.h" void runTests(void); #ifndef ITERATIONS @@ -187,7 +187,7 @@ public: } 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"; @@ -287,7 +287,7 @@ public: } 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"; @@ -364,7 +364,7 @@ public: } 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"; @@ -418,6 +418,88 @@ public: #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;iformat(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 }; @@ -489,6 +571,23 @@ void runTests() { #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); diff --git a/icu4c/source/tools/toolutil/udbgutil.cpp b/icu4c/source/tools/toolutil/udbgutil.cpp index 385a88b137e..d9f7869a3d5 100644 --- a/icu4c/source/tools/toolutil/udbgutil.cpp +++ b/icu4c/source/tools/toolutil/udbgutil.cpp @@ -11,6 +11,7 @@ #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) @@ -509,7 +510,9 @@ static USystemParams systemParams[] = { #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}, }; -- 2.40.0