ICU-6426 Zone String Formatter, reduce heap memory usage.

X-SVN-Rev: 26718
This commit is contained in:
Andy Heninger 2009-10-01 18:31:00 +00:00
parent e937802586
commit abb85c8441
2 changed files with 72 additions and 38 deletions

View File

@ -531,7 +531,10 @@ ZoneStringFormat::ZoneStringFormat(const UnicodeString* const* strings,
fTzidToStrings(NULL),
fMzidToStrings(NULL),
fZoneStringsTrie(TRUE),
fStringPool(status)
fStringPool(status),
fZoneStringsArray(NULL),
fMetazoneItem(NULL),
fZoneItem(NULL)
{
if (U_FAILURE(status)) {
return;
@ -624,7 +627,10 @@ ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
fTzidToStrings(NULL),
fMzidToStrings(NULL),
fZoneStringsTrie(TRUE),
fStringPool(status)
fStringPool(status),
fZoneStringsArray(NULL),
fMetazoneItem(NULL),
fZoneItem(NULL)
{
if (U_FAILURE(status)) {
return;
@ -640,25 +646,22 @@ ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
uhash_setValueDeleter(fTzidToStrings, deleteZoneStrings);
uhash_setValueDeleter(fMzidToStrings, deleteZoneStrings);
UResourceBundle *zoneStringsArray = ures_open(NULL, locale.getName(), &status);
zoneStringsArray = ures_getByKeyWithFallback(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
fZoneStringsArray = ures_open(NULL, locale.getName(), &status);
fZoneStringsArray = ures_getByKeyWithFallback(fZoneStringsArray, gZoneStringsTag, fZoneStringsArray, &status);
if (U_FAILURE(status)) {
// If no locale bundles are available, zoneStrings will be null.
// We still want to go through the rest of zone strings initialization,
// because generic location format is generated from tzid for the case.
// The rest of code should work even zoneStrings is null.
status = U_ZERO_ERROR;
ures_close(zoneStringsArray);
zoneStringsArray = NULL;
ures_close(fZoneStringsArray);
fZoneStringsArray = NULL;
}
StringEnumeration *tzids = NULL;
MessageFormat *fallbackFmt = NULL;
MessageFormat *regionFmt = NULL;
UResourceBundle *zoneItem = NULL;
UResourceBundle *metazoneItem = NULL;
char zidkey[ZID_KEY_MAX];
const UChar *zstrarray[ZSIDX_COUNT];
const UChar *mzstrarray[ZSIDX_COUNT];
@ -708,21 +711,21 @@ ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
p++;
}
if (zoneStringsArray != NULL) {
zoneItem = ures_getByKeyWithFallback(zoneStringsArray, zidkey, zoneItem, &status);
if (fZoneStringsArray != NULL) {
fZoneItem = ures_getByKeyWithFallback(fZoneStringsArray, zidkey, fZoneItem, &status);
if (U_FAILURE(status)) {
// If failed to open the zone item, create only location string
ures_close(zoneItem);
zoneItem = NULL;
ures_close(fZoneItem);
fZoneItem = NULL;
status = U_ZERO_ERROR;
}
}
zstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(zoneItem, gLongStandardTag);
zstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(zoneItem, gShortStandardTag);
zstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(zoneItem, gLongDaylightTag);
zstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(zoneItem, gShortDaylightTag);
zstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(zoneItem, gLongGenericTag);
zstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(zoneItem, gShortGenericTag);
zstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(fZoneItem, gLongStandardTag);
zstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(fZoneItem, gShortStandardTag);
zstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(fZoneItem, gLongDaylightTag);
zstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(fZoneItem, gShortDaylightTag);
zstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(fZoneItem, gLongGenericTag);
zstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(fZoneItem, gShortGenericTag);
// Compose location format string
UnicodeString location;
@ -731,7 +734,7 @@ ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
UnicodeString countryCode;
ZoneMeta::getCanonicalCountry(utzid, countryCode);
if (!countryCode.isEmpty()) {
const UChar* tmpCity = getZoneStringFromBundle(zoneItem, gExemplarCityTag);
const UChar* tmpCity = getZoneStringFromBundle(fZoneItem, gExemplarCityTag);
if (tmpCity != NULL) {
city.setTo(TRUE, tmpCity, -1);
} else {
@ -798,7 +801,7 @@ ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
}
}
UBool commonlyUsed = isCommonlyUsed(zoneItem);
UBool commonlyUsed = isCommonlyUsed(fZoneItem);
// Resolve metazones used by this zone
int32_t mzPartialLocIdx = 0;
@ -815,20 +818,20 @@ ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
char mzidkey[ZID_KEY_MAX];
uprv_strcpy(mzidkey, gMetazoneIdPrefix);
u_UCharsToChars(mzmap->mzid, mzidkey + MZID_PREFIX_LEN, u_strlen(mzmap->mzid) + 1);
metazoneItem = ures_getByKeyWithFallback(zoneStringsArray, mzidkey, metazoneItem, &status);
fMetazoneItem = ures_getByKeyWithFallback(fZoneStringsArray, mzidkey, fMetazoneItem, &status);
if (U_FAILURE(status)) {
// No resources available for this metazone
// Resource bundle will be cleaned up after end of the loop.
status = U_ZERO_ERROR;
continue;
}
UBool mzCommonlyUsed = isCommonlyUsed(metazoneItem);
mzstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(metazoneItem, gLongStandardTag);
mzstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(metazoneItem, gShortStandardTag);
mzstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(metazoneItem, gLongDaylightTag);
mzstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(metazoneItem, gShortDaylightTag);
mzstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(metazoneItem, gLongGenericTag);
mzstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(metazoneItem, gShortGenericTag);
UBool mzCommonlyUsed = isCommonlyUsed(fMetazoneItem);
mzstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(fMetazoneItem, gLongStandardTag);
mzstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(fMetazoneItem, gShortStandardTag);
mzstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(fMetazoneItem, gLongDaylightTag);
mzstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(fMetazoneItem, gShortDaylightTag);
mzstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(fMetazoneItem, gLongGenericTag);
mzstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(fMetazoneItem, gShortGenericTag);
mzstrarray[ZSIDX_LOCATION] = NULL;
int32_t lastNonNullIdx = ZSIDX_COUNT - 1;
@ -1039,15 +1042,15 @@ error_cleanup:
if (tzids != NULL) {
delete tzids;
}
ures_close(zoneItem);
ures_close(metazoneItem);
ures_close(zoneStringsArray);
fStringPool.freeze();
}
ZoneStringFormat::~ZoneStringFormat() {
uhash_close(fTzidToStrings);
uhash_close(fMzidToStrings);
ures_close(fZoneItem);
ures_close(fMetazoneItem);
ures_close(fZoneStringsArray);
}
SafeZoneStringFormatPtr*
@ -1583,6 +1586,7 @@ ZoneStringFormat::getZoneStringFromBundle(const UResourceBundle *zoneitem, const
UErrorCode status = U_ZERO_ERROR;
int32_t len;
str = ures_getStringByKeyWithFallback(zoneitem, key, &len, &status);
str = fStringPool.adopt(str, status);
if (U_FAILURE(status)) {
str = NULL;
}
@ -1997,6 +2001,27 @@ const UChar *ZSFStringPool::get(const UChar *s, UErrorCode &status) {
}
//
// ZSFStringPool::adopt() Put a string into the hash, but do not copy the string data
// into the pool's storage. Used for strings from resource bundles,
// which will perisist for the life of the zone string formatter, and
// therefore can be used directly without copying.
const UChar *ZSFStringPool::adopt(const UChar * s, UErrorCode &status) {
const UChar *pooledString;
if (U_FAILURE(status)) {
return &EmptyString;
}
if (s != NULL) {
pooledString = static_cast<UChar *>(uhash_get(fHash, s));
if (pooledString == NULL) {
UChar *ncs = const_cast<UChar *>(s);
uhash_put(fHash, ncs, ncs, &status);
}
}
return s;
}
const UChar *ZSFStringPool::get(const UnicodeString &s, UErrorCode &status) {
UnicodeString &nonConstStr = const_cast<UnicodeString &>(s);
return this->get(nonConstStr.getTerminatedBuffer(), status);

View File

@ -98,6 +98,11 @@ class ZSFStringPool: public UMemory {
*/
const UChar *get(const UnicodeString &s, UErrorCode &status);
/* Adopt a string into the pool, without copying it.
* Used for strings from resource bundles, which will persist without copying.
*/
const UChar *adopt(const UChar *s, UErrorCode &status);
/* Freeze the string pool. Discards the hash table that is used
* for looking up a string. All pointers to pooled strings remain valid.
*/
@ -281,12 +286,16 @@ public:
inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const;
private:
Locale fLocale;
UHashtable *fTzidToStrings;
UHashtable *fMzidToStrings;
Locale fLocale;
UHashtable *fTzidToStrings;
UHashtable *fMzidToStrings;
TextTrieMap fZoneStringsTrie;
ZSFStringPool fStringPool;
TextTrieMap fZoneStringsTrie;
ZSFStringPool fStringPool;
UResourceBundle *fZoneStringsArray;
UResourceBundle *fMetazoneItem;
UResourceBundle *fZoneItem;
/*
* Private method to get a zone string except generic partial location types.
@ -340,7 +349,7 @@ private:
static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status);
static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status);
static const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key);
const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key);
static UBool isCommonlyUsed(const UResourceBundle *zoneitem);
static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale,
UnicodeString &displayCountry);