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

View File

@ -46,7 +46,7 @@
#include "unicode/ucurr.h"
#include "unicode/ustring.h"
#include "unicode/dcfmtsym.h"
#include "unicode/resbund.h"
#include "unicode/ures.h"
#include "unicode/uchar.h"
#include "unicode/curramt.h"
#include "ucurrimp.h"
@ -306,10 +306,14 @@ DecimalFormat::construct(UErrorCode& status,
// one specified.
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;
ures_close(resource);
}
if (U_FAILURE(status))

View File

@ -180,13 +180,6 @@ Format::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
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
Format::setLocaleIDs(const char* valid, const char* actual) {
U_LOCALE_BASED(locBased, *this);

View File

@ -808,120 +808,96 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
return NULL;
}
ResourceBundle resource((char *)0, desiredLocale, status);
NumberFormat* f;
NumberFormat* f = NULL;
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
status = U_USING_FALLBACK_WARNING;
// Use the DecimalFormatSymbols constructor which uses last-resort data
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;
}
// When the data is unavailable, and locale isn't passed in, last resort data is used.
symbolsToAdopt = new DecimalFormatSymbols(status);
// Creates a DecimalFormat instance with the last resort number patterns.
f = new DecimalFormat(fgLastResortNumberPatterns[style], symbolsToAdopt, status);
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;
}
pattern.setTo(TRUE, fgLastResortNumberPatterns[style], -1);
}
else {
// If the requested style doesn't exist, use a last-resort style.
// This is to support scientific styles before we have all the
// resource data in place.
f = new DecimalFormat(fgLastResortNumberPatterns[style], symbolsToAdopt, status);
// If not all the styled patterns exists for the NumberFormat in this locale,
// sets the status code to failure and returns nil.
if (ures_getSize(numberPatterns) < fgNumberPatternsCount) {
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 (f == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
if (U_FAILURE(status) || symbolsToAdopt == NULL) {
goto cleanup;
}
// 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)) {
delete f;
f = NULL;
/* If f exists, then it will delete the symbols */
if (f==NULL) {
delete symbolsToAdopt;
}
else {
delete f;
}
return NULL;
}
f->setLocales(numberPatterns);
if (f == NULL || symbolsToAdopt == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
f = NULL;
}
return f;
}

View File

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

View File

@ -248,7 +248,7 @@ private:
* @param numberElements the number format symbols
* @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.

View File

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