ICU-4084 Improve DateFormat construction performance.

X-SVN-Rev: 16247
This commit is contained in:
George Rhoten 2004-09-02 19:08:28 +00:00
parent fd5588b821
commit 95873dd022
7 changed files with 141 additions and 175 deletions

View File

@ -150,29 +150,30 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
} }
else { else {
UnicodeString numberElements[kFormatSymbolCount]; const UChar *numberElements[kFormatSymbolCount];
int32_t numberElementsStrLen[kFormatSymbolCount];
int32_t i = 0; int32_t i = 0;
for(i = 0; i<numberElementsLength; i++) { for(i = 0; i<numberElementsLength; i++) {
int32_t len = 0; int32_t len = 0;
const UChar *resUChars = ures_getStringByIndex(numberElementsRes, i, &len, &status); numberElements[i] = ures_getStringByIndex(numberElementsRes, i, &numberElementsStrLen[i], &status);
numberElements[i].setTo(TRUE, resUChars, len); /* This setTo does aliasing */
} }
if (U_SUCCESS(status)) { if (U_SUCCESS(status)) {
initialize(numberElements, numberElementsLength); initialize(numberElements, numberElementsStrLen, numberElementsLength);
// Obtain currency data from the currency API. This is strictly // Obtain currency data from the currency API. This is strictly
// for backward compatibility; we don't use DecimalFormatSymbols // for backward compatibility; we don't use DecimalFormatSymbols
// for currency data anymore. // for currency data anymore.
UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out
UChar curriso[4]; UChar curriso[4];
UnicodeString tempStr;
ucurr_forLocale(locStr, curriso, 4, &internalStatus); ucurr_forLocale(locStr, curriso, 4, &internalStatus);
// Reuse numberElements[0] as a temporary buffer // Reuse numberElements[0] as a temporary buffer
uprv_getStaticCurrencyName(curriso, locStr, numberElements[0], internalStatus); uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus);
if (U_SUCCESS(internalStatus)) { if (U_SUCCESS(internalStatus)) {
fSymbols[kIntlCurrencySymbol] = curriso; fSymbols[kIntlCurrencySymbol] = curriso;
fSymbols[kCurrencySymbol] = numberElements[0]; fSymbols[kCurrencySymbol] = tempStr;
} }
/* else use the default values. */ /* else use the default values. */
} }
@ -191,28 +192,35 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
// from ResourceBundle in the desired locale. // from ResourceBundle in the desired locale.
void void
DecimalFormatSymbols::initialize(const UnicodeString* numberElements, int32_t numberElementsLength) DecimalFormatSymbols::initialize(const UChar** numberElements, int32_t *numberElementsStrLen, int32_t numberElementsLength)
{ {
fSymbols[kDecimalSeparatorSymbol].fastCopyFrom(numberElements[0]); static const int32_t TYPE_MAPPING[][2] = {
fSymbols[kGroupingSeparatorSymbol].fastCopyFrom(numberElements[1]); {kDecimalSeparatorSymbol, 0},
fSymbols[kPatternSeparatorSymbol].fastCopyFrom(numberElements[2]); {kGroupingSeparatorSymbol, 1},
fSymbols[kPercentSymbol].fastCopyFrom(numberElements[3]); {kPatternSeparatorSymbol, 2},
fSymbols[kZeroDigitSymbol].fastCopyFrom(numberElements[4]); {kPercentSymbol, 3},
fSymbols[kDigitSymbol].fastCopyFrom(numberElements[5]); {kZeroDigitSymbol, 4},
fSymbols[kMinusSignSymbol].fastCopyFrom(numberElements[6]); {kDigitSymbol, 5},
fSymbols[kExponentialSymbol].fastCopyFrom(numberElements[7]); {kMinusSignSymbol, 6},
fSymbols[kPerMillSymbol].fastCopyFrom(numberElements[8]); {kExponentialSymbol, 7},
fSymbols[kPadEscapeSymbol] = (UChar)0x002a; // TODO: '*' Hard coded for now; get from resource later {kPerMillSymbol, 8},
fSymbols[kInfinitySymbol].fastCopyFrom(numberElements[9]); {kInfinitySymbol, 9},
fSymbols[kNaNSymbol].fastCopyFrom(numberElements[10]); {kNaNSymbol, 10},
fSymbols[kPlusSignSymbol].fastCopyFrom(numberElements[11]); {kPlusSignSymbol, 11},
fSymbols[kMonetarySeparatorSymbol].fastCopyFrom(numberElements[0]); {kMonetarySeparatorSymbol, 0}
};
int32_t idx;
for (idx = 0; idx < (int32_t)(sizeof(TYPE_MAPPING)/sizeof(TYPE_MAPPING[0])); idx++) {
fSymbols[TYPE_MAPPING[idx][0]].setTo(TRUE, numberElements[TYPE_MAPPING[idx][1]], numberElementsStrLen[TYPE_MAPPING[idx][1]]);
}
// Default values until it's set later on. // Default values until it's set later on.
fSymbols[kCurrencySymbol] = (UChar)0xa4; // 'OX' currency symbol fSymbols[kCurrencySymbol] = (UChar)0xa4; // 'OX' currency symbol
fSymbols[kIntlCurrencySymbol] = INTL_CURRENCY_SYMBOL_STR; fSymbols[kIntlCurrencySymbol] = INTL_CURRENCY_SYMBOL_STR;
// TODO: read from locale data, if this makes it into CLDR // TODO: read from locale data, if this makes it into CLDR
fSymbols[kSignificantDigitSymbol] = (UChar)0x0040; // '@' significant digit fSymbols[kSignificantDigitSymbol] = (UChar)0x0040; // '@' significant digit
fSymbols[kPadEscapeSymbol] = (UChar)0x002a; // TODO: '*' Hard coded for now; get from resource later
} }
// initialize with default values // initialize with default values

View File

@ -46,7 +46,7 @@
#include "unicode/ucurr.h" #include "unicode/ucurr.h"
#include "unicode/ustring.h" #include "unicode/ustring.h"
#include "unicode/dcfmtsym.h" #include "unicode/dcfmtsym.h"
#include "unicode/resbund.h" #include "unicode/ures.h"
#include "unicode/uchar.h" #include "unicode/uchar.h"
#include "unicode/curramt.h" #include "unicode/curramt.h"
#include "ucurrimp.h" #include "ucurrimp.h"
@ -306,10 +306,14 @@ DecimalFormat::construct(UErrorCode& status,
// one specified. // one specified.
if (pattern == NULL) if (pattern == NULL)
{ {
ResourceBundle resource((char *)0, Locale::getDefault(), status); int32_t len = 0;
UResourceBundle *resource = ures_open(NULL, Locale::getDefault().getName(), &status);
str = resource.get(fgNumberPatterns, status).getStringEx((int32_t)0, status); resource = ures_getByKey(resource, fgNumberPatterns, resource, &status);
const UChar *resStr = ures_getStringByIndex(resource, (int32_t)0, &len, &status);
str.setTo(TRUE, resStr, len);
pattern = &str; pattern = &str;
ures_close(resource);
} }
if (U_FAILURE(status)) if (U_FAILURE(status))

View File

@ -180,13 +180,6 @@ Format::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
return locBased.getLocaleID(type, status); return locBased.getLocaleID(type, status);
} }
void
Format::setLocales(const ResourceBundle& res) {
UErrorCode status = U_ZERO_ERROR;
setLocaleIDs(res.getLocale(ULOC_VALID_LOCALE, status).getName(),
res.getLocale(ULOC_ACTUAL_LOCALE, status).getName());
}
void void
Format::setLocaleIDs(const char* valid, const char* actual) { Format::setLocaleIDs(const char* valid, const char* actual) {
U_LOCALE_BASED(locBased, *this); U_LOCALE_BASED(locBased, *this);

View File

@ -808,120 +808,96 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
return NULL; return NULL;
} }
ResourceBundle resource((char *)0, desiredLocale, status); NumberFormat* f = NULL;
NumberFormat* f; DecimalFormatSymbols* symbolsToAdopt = NULL;
UnicodeString pattern;
UResourceBundle *resource = ures_open((char *)0, desiredLocale.getName(), &status);
UResourceBundle *numberPatterns = ures_getByKey(resource, DecimalFormat::fgNumberPatterns, NULL, &status);
if (U_FAILURE(status)) if (U_FAILURE(status)) {
{
// We don't appear to have resource data available -- use the last-resort data // We don't appear to have resource data available -- use the last-resort data
status = U_USING_FALLBACK_WARNING; status = U_USING_FALLBACK_WARNING;
// When the data is unavailable, and locale isn't passed in, last resort data is used.
// Use the DecimalFormatSymbols constructor which uses last-resort data symbolsToAdopt = new DecimalFormatSymbols(status);
DecimalFormatSymbols* symbolsToAdopt = new DecimalFormatSymbols(status);
if (symbolsToAdopt == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
if (U_FAILURE(status)) {
delete symbolsToAdopt; // This should never happen
return NULL;
}
// Creates a DecimalFormat instance with the last resort number patterns. // Creates a DecimalFormat instance with the last resort number patterns.
f = new DecimalFormat(fgLastResortNumberPatterns[style], symbolsToAdopt, status); pattern.setTo(TRUE, fgLastResortNumberPatterns[style], -1);
if (f == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
if (U_FAILURE(status)) {
delete f;
f = NULL;
}
return f;
}
ResourceBundle numberPatterns(resource.get(DecimalFormat::fgNumberPatterns, status));
// If not all the styled patterns exists for the NumberFormat in this locale,
// sets the status code to failure and returns nil.
//if (patternCount < fgNumberPatternsCount) status = U_INVALID_FORMAT_ERROR;
if (numberPatterns.getSize() < fgNumberPatternsCount)
status = U_INVALID_FORMAT_ERROR;
if (U_FAILURE(status))
return NULL;
// Loads the decimal symbols of the desired locale.
DecimalFormatSymbols* symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
if (symbolsToAdopt == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
if (U_FAILURE(status)) {
delete symbolsToAdopt;
return NULL;
}
// Creates the specified decimal format style of the desired locale.
if (style < numberPatterns.getSize()) {
UnicodeString pattern(numberPatterns.getStringEx(style, status));
if (U_SUCCESS(status)) {
// Here we assume that the locale passed in is in the canonical
// form, e.g: pt_PT_@currency=PTE not pt_PT_PREEURO
if(style==kCurrencyStyle){
char buf[8]={0};
int32_t bufCap = 8;
const char* locName = desiredLocale.getName();
bufCap = uloc_getKeywordValue(locName, "currency", buf, bufCap, &status);
if(U_SUCCESS(status) && bufCap > 0) {
/* An explicit currency was requested */
UErrorCode localStatus = U_ZERO_ERROR;
ResourceBundle currencies(resource.getWithFallback("Currencies", localStatus));
ResourceBundle currency(currencies.getWithFallback(buf,localStatus));
if(U_SUCCESS(localStatus) && currency.getSize()>2) {
ResourceBundle elements = currency.get(2, localStatus);
UnicodeString currPattern = elements.getStringEx((int32_t)0, localStatus);
UnicodeString decimalSep = elements.getStringEx((int32_t)1, localStatus);
UnicodeString groupingSep = elements.getStringEx((int32_t)2, localStatus);
if(U_SUCCESS(localStatus)){
symbolsToAdopt->setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, groupingSep);
symbolsToAdopt->setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, decimalSep);
pattern = currPattern;
}
if (status == U_ZERO_ERROR) {
status = localStatus;
}
}
/* else An explicit currency was requested and is unknown or locale data is malformed. */
/* ucurr_* API will get the correct value later on. */
}
}
if (U_FAILURE(status)) {
delete symbolsToAdopt;
return NULL;
}
f = new DecimalFormat(pattern, symbolsToAdopt, status);
}
else {
return NULL;
}
} }
else { else {
// If the requested style doesn't exist, use a last-resort style. // If not all the styled patterns exists for the NumberFormat in this locale,
// This is to support scientific styles before we have all the // sets the status code to failure and returns nil.
// resource data in place. if (ures_getSize(numberPatterns) < fgNumberPatternsCount) {
f = new DecimalFormat(fgLastResortNumberPatterns[style], symbolsToAdopt, status); status = U_INVALID_FORMAT_ERROR;
goto cleanup;
}
// Loads the decimal symbols of the desired locale.
symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
int32_t patLen = 0;
const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)style, &patLen, &status);
// Creates the specified decimal format style of the desired locale.
pattern.setTo(TRUE, patResStr, patLen);
} }
if (U_FAILURE(status) || symbolsToAdopt == NULL) {
if (f == NULL) { goto cleanup;
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
} }
// Here we assume that the locale passed in is in the canonical
// form, e.g: pt_PT_@currency=PTE not pt_PT_PREEURO
if(style==kCurrencyStyle){
char currencyCode[8]={0};
int32_t currencyCodeCap = sizeof(currencyCode);
const char* locName = desiredLocale.getName();
currencyCodeCap = uloc_getKeywordValue(locName, "currency", currencyCode, currencyCodeCap, &status);
if(U_SUCCESS(status) && currencyCodeCap > 0) {
/* An explicit currency was requested */
UErrorCode localStatus = U_ZERO_ERROR;
UResourceBundle *currency = ures_getByKeyWithFallback(resource, "Currencies", NULL, &localStatus);
currency = ures_getByKeyWithFallback(currency, currencyCode, currency, &localStatus);
if(U_SUCCESS(localStatus) && ures_getSize(currency)>2) {
currency = ures_getByIndex(currency, 2, currency, &localStatus);
int32_t currPatternLen = 0;
const UChar *currPattern = ures_getStringByIndex(currency, (int32_t)0, &currPatternLen, &localStatus);
UnicodeString decimalSep = ures_getStringByIndex(currency, (int32_t)1, NULL, &localStatus);
UnicodeString groupingSep = ures_getStringByIndex(currency, (int32_t)2, NULL, &localStatus);
if(U_SUCCESS(localStatus)){
symbolsToAdopt->setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, groupingSep);
symbolsToAdopt->setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, decimalSep);
pattern.setTo(TRUE, currPattern, currPatternLen);
status = localStatus;
}
}
ures_close(currency);
/* else An explicit currency was requested and is unknown or locale data is malformed. */
/* ucurr_* API will get the correct value later on. */
}
/* else no currency keyword used. */
}
f = new DecimalFormat(pattern, symbolsToAdopt, status);
if (U_FAILURE(status) || f == NULL) {
goto cleanup;
}
f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(numberPatterns, ULOC_ACTUAL_LOCALE, &status));
cleanup:
ures_close(numberPatterns);
ures_close(resource);
if (U_FAILURE(status)) { if (U_FAILURE(status)) {
delete f; /* If f exists, then it will delete the symbols */
f = NULL; if (f==NULL) {
delete symbolsToAdopt;
}
else {
delete f;
}
return NULL; return NULL;
} }
f->setLocales(numberPatterns); if (f == NULL || symbolsToAdopt == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
f = NULL;
}
return f; return f;
} }

View File

@ -30,7 +30,7 @@
#include "unicode/smpdtfmt.h" #include "unicode/smpdtfmt.h"
#include "unicode/dtfmtsym.h" #include "unicode/dtfmtsym.h"
#include "unicode/resbund.h" #include "unicode/ures.h"
#include "unicode/msgfmt.h" #include "unicode/msgfmt.h"
#include "unicode/calendar.h" #include "unicode/calendar.h"
#include "unicode/gregocal.h" #include "unicode/gregocal.h"
@ -278,17 +278,17 @@ void SimpleDateFormat::construct(EStyle timeStyle,
initializeCalendar(NULL, locale, status); initializeCalendar(NULL, locale, status);
CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status); CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
UResourceBundle *dtp = calData.getByKey(gDateTimePatternsTag, status); UResourceBundle *dateTimePatterns = calData.getByKey(gDateTimePatternsTag, status);
ResourceBundle dateTimePatterns(dtp, status);
if (U_FAILURE(status)) return; if (U_FAILURE(status)) return;
if (dateTimePatterns.getSize() <= kDateTime) if (ures_getSize(dateTimePatterns) <= kDateTime)
{ {
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
return; return;
} }
setLocales(dateTimePatterns); setLocaleIDs(ures_getLocaleByType(dateTimePatterns, ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(dateTimePatterns, ULOC_ACTUAL_LOCALE, &status));
// create a symbols object from the locale // create a symbols object from the locale
initializeSymbols(locale,fCalendar, status); initializeSymbols(locale,fCalendar, status);
@ -299,52 +299,43 @@ void SimpleDateFormat::construct(EStyle timeStyle,
return; return;
} }
UnicodeString str; const UChar *resStr;
int32_t resStrLen = 0;
// Move dateStyle from the range [0, 3] to [4, 7] if necessary
//if (dateStyle >= 0 && dateStyle < DATE_OFFSET) dateStyle = (EStyle)(dateStyle + DATE_OFFSET);
// if the pattern should include both date and time information, use the date/time // if the pattern should include both date and time information, use the date/time
// pattern string as a guide to tell use how to glue together the appropriate date // pattern string as a guide to tell use how to glue together the appropriate date
// and time pattern strings. The actual gluing-together is handled by a convenience // and time pattern strings. The actual gluing-together is handled by a convenience
// method on MessageFormat. // method on MessageFormat.
if ((timeStyle != kNone) && if ((timeStyle != kNone) && (dateStyle != kNone))
(dateStyle != kNone))
{ {
// Object[] dateTimeArgs = { Formattable timeDateArray[2];
// dateTimePatterns[timeStyle], dateTimePatterns[dateStyle]
// };
// pattern = MessageFormat.format(dateTimePatterns[8], dateTimeArgs);
Formattable *timeDateArray = new Formattable[2];
/* test for NULL */
if (timeDateArray == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
//timeDateArray[0].setString(UnicodeString(dateTimePatterns[timeStyle]));
//timeDateArray[1].setString(UnicodeString(dateTimePatterns[dateStyle]));
// use Formattable::adoptString() so that we can use fastCopyFrom() // use Formattable::adoptString() so that we can use fastCopyFrom()
// instead of Formattable::setString()'s unaware, safe, deep string clone // instead of Formattable::setString()'s unaware, safe, deep string clone
// see Jitterbug 2296 // see Jitterbug 2296
timeDateArray[0].adoptString(&(new UnicodeString)->fastCopyFrom(dateTimePatterns.getStringEx(timeStyle, status))); resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)timeStyle, &resStrLen, &status);
timeDateArray[1].adoptString(&(new UnicodeString)->fastCopyFrom(dateTimePatterns.getStringEx(dateStyle, status))); timeDateArray[0].adoptString(new UnicodeString(TRUE, resStr, resStrLen));
resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)dateStyle, &resStrLen, &status);
timeDateArray[1].adoptString(new UnicodeString(TRUE, resStr, resStrLen));
//MessageFormat::format(UnicodeString(dateTimePatterns[kDateTime]), timeDateArray, 2, fPattern, status); resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)kDateTime, &resStrLen, &status);
MessageFormat::format(dateTimePatterns.getStringEx(kDateTime, status), timeDateArray, 2, fPattern, status); MessageFormat::format(UnicodeString(TRUE, resStr, resStrLen), timeDateArray, 2, fPattern, status);
delete [] timeDateArray;
} }
// if the pattern includes just time data or just date date, load the appropriate // if the pattern includes just time data or just date date, load the appropriate
// pattern string from the resources // pattern string from the resources
//else if (timeStyle != kNone) fPattern = UnicodeString(dateTimePatterns[timeStyle]); // setTo() - see DateFormatSymbols::assignArray comments
//else if (dateStyle != kNone) fPattern = UnicodeString(dateTimePatterns[dateStyle]); else if (timeStyle != kNone) {
// fastCopyFrom() - see DateFormatSymbols::assignArray comments resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)timeStyle, &resStrLen, &status);
else if (timeStyle != kNone) fPattern.fastCopyFrom(dateTimePatterns.getStringEx(timeStyle, status)); fPattern.setTo(TRUE, resStr, resStrLen);
else if (dateStyle != kNone) fPattern.fastCopyFrom(dateTimePatterns.getStringEx(dateStyle, status)); }
else if (dateStyle != kNone) {
resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)dateStyle, &resStrLen, &status);
fPattern.setTo(TRUE, resStr, resStrLen);
}
// and if it includes _neither_, that's an error // and if it includes _neither_, that's an error
else status = U_INVALID_FORMAT_ERROR; else
status = U_INVALID_FORMAT_ERROR;
// finally, finish initializing by creating a Calendar and a NumberFormat // finally, finish initializing by creating a Calendar and a NumberFormat
initialize(locale, status); initialize(locale, status);

View File

@ -248,7 +248,7 @@ private:
* @param numberElements the number format symbols * @param numberElements the number format symbols
* @param numberElementsLength length of numberElements * @param numberElementsLength length of numberElements
*/ */
void initialize(const UnicodeString* numberElements, int32_t numberElementsLength); void initialize(const UChar** numberElements, int32_t *numberElementsStrLen, int32_t numberElementsLength);
/** /**
* Initialize the symbols with default values. * Initialize the symbols with default values.

View File

@ -25,7 +25,6 @@
#if !UCONFIG_NO_FORMATTING #if !UCONFIG_NO_FORMATTING
#include "unicode/uobject.h"
#include "unicode/unistr.h" #include "unicode/unistr.h"
#include "unicode/fmtable.h" #include "unicode/fmtable.h"
#include "unicode/fieldpos.h" #include "unicode/fieldpos.h"
@ -35,8 +34,6 @@
U_NAMESPACE_BEGIN U_NAMESPACE_BEGIN
class ResourceBundle;
/** /**
* Base class for all formats. This is an abstract base class which * Base class for all formats. This is an abstract base class which
* specifies the protocol for classes which convert other objects or * specifies the protocol for classes which convert other objects or
@ -247,9 +244,6 @@ public:
const char* getLocaleID(ULocDataLocaleType type, UErrorCode &status) const; const char* getLocaleID(ULocDataLocaleType type, UErrorCode &status) const;
protected: protected:
/** @draft ICU 2.8 */
void setLocales(const ResourceBundle& res);
/** @draft ICU 2.8 */ /** @draft ICU 2.8 */
void setLocaleIDs(const char* valid, const char* actual); void setLocaleIDs(const char* valid, const char* actual);