diff options
author | Jean-Baptiste Queru <jbq@google.com> | 2009-07-17 17:59:18 -0700 |
---|---|---|
committer | Jean-Baptiste Queru <jbq@google.com> | 2009-07-17 17:59:18 -0700 |
commit | 072a5238ae2b3c25cf72bead1dbb1026de054103 (patch) | |
tree | 4b884c484184c7d9b8543b697b7a5f091873dd5c /i18n | |
parent | 037e0a44b2bb27f80aab2556d41e26bdb2aafcd7 (diff) | |
download | icu4c-072a5238ae2b3c25cf72bead1dbb1026de054103.tar.gz |
import cl @80894
Diffstat (limited to 'i18n')
-rw-r--r-- | i18n/zstrfmt.cpp | 258 | ||||
-rw-r--r-- | i18n/zstrfmt.h | 78 |
2 files changed, 219 insertions, 117 deletions
diff --git a/i18n/zstrfmt.cpp b/i18n/zstrfmt.cpp index b42bbfb2..79e5d768 100644 --- a/i18n/zstrfmt.cpp +++ b/i18n/zstrfmt.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2007, International Business Machines Corporation and * +* Copyright (C) 2007-2008, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -145,9 +145,11 @@ getTimeZoneTranslationType(TimeZoneTranslationTypeIndex typeIdx) { case ZSIDX_LONG_DAYLIGHT: type = DAYLIGHT_LONG; break; + case ZSIDX_COUNT: case ZSIDX_SHORT_DAYLIGHT: type = DAYLIGHT_SHORT; break; + } return type; } @@ -155,106 +157,183 @@ getTimeZoneTranslationType(TimeZoneTranslationTypeIndex typeIdx) { #define DEFAULT_CHARACTERNODE_CAPACITY 1 // ---------------------------------------------------------------------------- -CharacterNode::CharacterNode(UChar32 c, UObjectDeleter *valueDeleterFunc, UErrorCode &status) -: UMemory(), - fChildren(valueDeleterFunc, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status), - fValues(valueDeleterFunc, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status), - fValueDeleter(valueDeleterFunc), - fCharacter(c) -{ +void CharacterNode::clear() { + uprv_memset(this, 0, sizeof(*this)); } -CharacterNode::~CharacterNode() { - while (!fChildren.isEmpty()) { - CharacterNode *node = (CharacterNode*)fChildren.orphanElementAt(0); - delete node; +void CharacterNode::deleteValues() { + if (fValues == NULL) { + // Do nothing. + } else if (!fHasValuesVector) { + deleteZoneStringInfo(fValues); + } else { + delete (UVector *)fValues; } } void CharacterNode::addValue(void *value, UErrorCode &status) { if (U_FAILURE(status)) { + deleteZoneStringInfo(value); return; } - fValues.addElement(value, status); -} - -CharacterNode* -CharacterNode::addChildNode(UChar32 c, UErrorCode &status) { - if (U_FAILURE(status)) { - return NULL; - } - CharacterNode *result = NULL; - for (int32_t i = 0; i < fChildren.size(); i++) { - CharacterNode *node = (CharacterNode*)fChildren.elementAt(i); - if (node->getCharacter() == c) { - result = node; - break; + if (fValues == NULL) { + fValues = value; + } else { + // At least one value already. + if (!fHasValuesVector) { + // There is only one value so far, and not in a vector yet. + // Create a vector and add the old value. + UVector *values = new UVector(deleteZoneStringInfo, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status); + if (U_FAILURE(status)) { + deleteZoneStringInfo(value); + return; + } + values->addElement(fValues, status); + fValues = values; + fHasValuesVector = TRUE; } + // Add the new value. + ((UVector *)fValues)->addElement(value, status); } - if (result == NULL) { - result = new CharacterNode(c, fValueDeleter, status); - fChildren.addElement(result, status); - } - - return result; } -CharacterNode* -CharacterNode::getChildNode(UChar32 c) const { - CharacterNode *result = NULL; - for (int32_t i = 0; i < fChildren.size(); i++) { - CharacterNode *node = (CharacterNode*)fChildren.elementAt(i); - if (node->getCharacter() == c) { - result = node; - break; - } - } - return result; +//---------------------------------------------------------------------------- +// Virtual destructor to avoid warning +TextTrieMapSearchResultHandler::~TextTrieMapSearchResultHandler(){ } // ---------------------------------------------------------------------------- -TextTrieMap::TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleterFunc) -: UMemory(), fIgnoreCase(ignoreCase), fValueDeleter(valueDeleterFunc), fRoot(NULL) { +TextTrieMap::TextTrieMap(UBool ignoreCase) +: fIgnoreCase(ignoreCase), fNodes(NULL), fNodesCapacity(0), fNodesCount(0) { } TextTrieMap::~TextTrieMap() { - if (fRoot != NULL) { - delete fRoot; + int32_t index; + for (index = 0; index < fNodesCount; ++index) { + fNodes[index].deleteValues(); } + uprv_free(fNodes); } void TextTrieMap::put(const UnicodeString &key, void *value, UErrorCode &status) { - if (fRoot == NULL) { - fRoot = new CharacterNode(0, fValueDeleter, status); + if (fNodes == NULL) { + fNodesCapacity = 512; + fNodes = (CharacterNode *)uprv_malloc(fNodesCapacity * sizeof(CharacterNode)); + fNodes[0].clear(); // Init root node. + fNodesCount = 1; } - UnicodeString keyString(key); + UnicodeString foldedKey; + const UChar *keyBuffer; + int32_t keyLength; if (fIgnoreCase) { - keyString.foldCase(); + // Ok to use fastCopyFrom() because we discard the copy when we return. + foldedKey.fastCopyFrom(key).foldCase(); + keyBuffer = foldedKey.getBuffer(); + keyLength = foldedKey.length(); + } else { + keyBuffer = key.getBuffer(); + keyLength = key.length(); } - CharacterNode *node = fRoot; - int32_t index = 0; - while (index < keyString.length()) { - UChar32 c = keyString.char32At(index); - node = node->addChildNode(c, status); - if (U_FAILURE(status)) { - return; - } - index = keyString.moveIndex32(index, 1); + CharacterNode *node = fNodes; + int32_t index; + for (index = 0; index < keyLength; ++index) { + node = addChildNode(node, keyBuffer[index], status); } node->addValue(value, status); } +UBool +TextTrieMap::growNodes() { + if (fNodesCapacity == 0xffff) { + return FALSE; // We use 16-bit node indexes. + } + int32_t newCapacity = fNodesCapacity * 2; + if (newCapacity > 0xffff) { + newCapacity = 0xffff; + } + CharacterNode *newNodes = (CharacterNode *)uprv_malloc(newCapacity * sizeof(CharacterNode)); + if (newNodes == NULL) { + return FALSE; + } + uprv_memcpy(newNodes, fNodes, fNodesCount * sizeof(CharacterNode)); + uprv_free(fNodes); + fNodes = newNodes; + fNodesCapacity = newCapacity; + return TRUE; +} + +CharacterNode* +TextTrieMap::addChildNode(CharacterNode *parent, UChar c, UErrorCode &status) { + if (U_FAILURE(status)) { + return NULL; + } + // Linear search of the sorted list of children. + uint16_t prevIndex = 0; + uint16_t nodeIndex = parent->fFirstChild; + while (nodeIndex > 0) { + CharacterNode *current = fNodes + nodeIndex; + UChar childCharacter = current->fCharacter; + if (childCharacter == c) { + return current; + } else if (childCharacter > c) { + break; + } + prevIndex = nodeIndex; + nodeIndex = current->fNextSibling; + } + + // Ensure capacity. Grow fNodes[] if needed. + if (fNodesCount == fNodesCapacity) { + int32_t parentIndex = (parent - fNodes); + if (!growNodes()) { + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + parent = fNodes + parentIndex; + } + + // Insert a new child node with c in sorted order. + CharacterNode *node = fNodes + fNodesCount; + node->clear(); + node->fCharacter = c; + node->fNextSibling = nodeIndex; + if (prevIndex == 0) { + parent->fFirstChild = (uint16_t)fNodesCount; + } else { + fNodes[prevIndex].fNextSibling = (uint16_t)fNodesCount; + } + ++fNodesCount; + return node; +} + +CharacterNode* +TextTrieMap::getChildNode(CharacterNode *parent, UChar c) const { + // Linear search of the sorted list of children. + uint16_t nodeIndex = parent->fFirstChild; + while (nodeIndex > 0) { + CharacterNode *current = fNodes + nodeIndex; + UChar childCharacter = current->fCharacter; + if (childCharacter == c) { + return current; + } else if (childCharacter > c) { + break; + } + nodeIndex = current->fNextSibling; + } + return NULL; +} + void TextTrieMap::search(const UnicodeString &text, int32_t start, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const { - if (fRoot == NULL) { + if (fNodes == NULL) { return; } - search(fRoot, text, start, start, handler, status); + search(fNodes, text, start, start, handler, status); } void @@ -263,9 +342,8 @@ TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t star if (U_FAILURE(status)) { return; } - const UVector *values = node->getValues(); - if (values != NULL) { - if (!handler->handleMatch(index - start, values, status)) { + if (node->hasValues()) { + if (!handler->handleMatch(index - start, node, status)) { return; } if (U_FAILURE(status)) { @@ -280,14 +358,14 @@ TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t star int32_t tmpidx = 0; while (tmpidx < tmp.length()) { c = tmp.char32At(tmpidx); - node = node->getChildNode(c); + node = getChildNode(node, c); if (node == NULL) { break; } tmpidx = tmp.moveIndex32(tmpidx, 1); } } else { - node = node->getChildNode(c); + node = getChildNode(node, c); } if (node != NULL) { search(node, text, start, index+1, handler, status); @@ -297,14 +375,14 @@ TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t star // ---------------------------------------------------------------------------- ZoneStringInfo::ZoneStringInfo(const UnicodeString &id, const UnicodeString &str, TimeZoneTranslationType type) -: UMemory(), fId(id), fStr(str), fType(type) { +: fId(id), fStr(str), fType(type) { } ZoneStringInfo::~ZoneStringInfo() { } // ---------------------------------------------------------------------------- ZoneStringSearchResultHandler::ZoneStringSearchResultHandler(UErrorCode &status) -: UMemory(), fResults(status) +: fResults(status) { clear(); } @@ -314,13 +392,14 @@ ZoneStringSearchResultHandler::~ZoneStringSearchResultHandler() { } UBool -ZoneStringSearchResultHandler::handleMatch(int32_t matchLength, const UVector *values, UErrorCode &status) { +ZoneStringSearchResultHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) { if (U_FAILURE(status)) { return FALSE; } - if (values != NULL) { - for (int32_t i = 0; values->size(); i++) { - ZoneStringInfo *zsinfo = (ZoneStringInfo*)values->elementAt(i); + if (node->hasValues()) { + int32_t valuesCount = node->countValues(); + for (int32_t i = 0; i < valuesCount; i++) { + ZoneStringInfo *zsinfo = (ZoneStringInfo*)node->getValue(i); if (zsinfo == NULL) { break; } @@ -374,11 +453,10 @@ ZoneStringSearchResultHandler::clear(void) { // ---------------------------------------------------------------------------- ZoneStringFormat::ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status) -: UMemory(), - fLocale(""), +: fLocale(""), fTzidToStrings(uhash_compareUnicodeString, NULL, status), fMzidToStrings(uhash_compareUnicodeString, NULL, status), - fZoneStringsTrie(TRUE, deleteZoneStringInfo) + fZoneStringsTrie(TRUE) { if (U_FAILURE(status)) { return; @@ -450,11 +528,10 @@ error_cleanup: } ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status) -: UMemory(), - fLocale(locale), +: fLocale(locale), fTzidToStrings(uhash_compareUnicodeString, NULL, status), fMzidToStrings(uhash_compareUnicodeString, NULL, status), - fZoneStringsTrie(TRUE, deleteZoneStringInfo) + fZoneStringsTrie(TRUE) { if (U_FAILURE(status)) { return; @@ -647,8 +724,7 @@ ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status) ZoneStringInfo *zsinfo = new ZoneStringInfo(preferredIdForLocale, strings_mz[typeidx], (TimeZoneTranslationType)type); fZoneStringsTrie.put(strings_mz[typeidx], zsinfo, status); if (U_FAILURE(status)) { - delete zsinfo; - delete strings_mz; + delete []strings_mz; goto error_cleanup; } } @@ -661,7 +737,6 @@ ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status) fMzidToStrings.put(mzid, tmp_mzStrings, status); if (U_FAILURE(status)) { - delete tmp_mzStrings; goto error_cleanup; } @@ -987,6 +1062,7 @@ ZoneStringFormat::getString(const UnicodeString &tzid, TimeZoneTranslationTypeIn // ICU's own array does not have entries for aliases UnicodeString canonicalID; + UErrorCode status = U_ZERO_ERROR; ZoneMeta::getCanonicalID(tzid, canonicalID); if (fTzidToStrings.count() > 0) { @@ -1001,6 +1077,7 @@ ZoneStringFormat::getString(const UnicodeString &tzid, TimeZoneTranslationTypeIn break; case ZSIDX_SHORT_STANDARD: case ZSIDX_SHORT_DAYLIGHT: + case ZSIDX_COUNT: //added to avoid warning case ZSIDX_SHORT_GENERIC: if (!commonlyUsedOnly || zstrings->isShortFormatCommonlyUsed()) { zstrings->getString(typeIdx, result); @@ -1025,6 +1102,7 @@ ZoneStringFormat::getString(const UnicodeString &tzid, TimeZoneTranslationTypeIn break; case ZSIDX_SHORT_STANDARD: case ZSIDX_SHORT_DAYLIGHT: + case ZSIDX_COUNT: //added to avoid warning case ZSIDX_SHORT_GENERIC: if (!commonlyUsedOnly || mzstrings->isShortFormatCommonlyUsed()) { mzstrings->getString(typeIdx, result); @@ -1053,7 +1131,7 @@ ZoneStringFormat::getGenericString(const Calendar &cal, UBool isShort, UBool com UnicodeString canonicalID; ZoneMeta::getCanonicalID(tzid, canonicalID); - ZoneStrings *zstrings; + ZoneStrings *zstrings = NULL; if (fTzidToStrings.count() > 0) { zstrings = (ZoneStrings*)fTzidToStrings.get(canonicalID); if (zstrings != NULL) { @@ -1205,6 +1283,7 @@ ZoneStringFormat::getGenericPartialLocationString(const UnicodeString &tzid, UBo } UnicodeString canonicalID; + UErrorCode status = U_ZERO_ERROR; ZoneMeta::getCanonicalID(tzid, canonicalID); UnicodeString mzid; @@ -1397,7 +1476,7 @@ ZoneStringFormat::getLocalizedCountry(const UnicodeString &countryCode, const Lo */ ZoneStrings::ZoneStrings(UnicodeString *strings, int32_t stringsCount, UBool commonlyUsed, UnicodeString **genericPartialLocationStrings, int32_t genericRowCount, int32_t genericColCount) -: UMemory(), fStrings(strings), fStringsCount(stringsCount), fIsCommonlyUsed(commonlyUsed), +: fStrings(strings), fStringsCount(stringsCount), fIsCommonlyUsed(commonlyUsed), fGenericPartialLocationStrings(genericPartialLocationStrings), fGenericPartialLocationRowCount(genericRowCount), fGenericPartialLocationColCount(genericColCount) { } @@ -1456,7 +1535,7 @@ ZoneStrings::getGenericPartialLocationString(const UnicodeString &mzid, UBool is // -------------------------------------------------------------- SafeZoneStringFormatPtr::SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry) -: UMemory(), fCacheEntry(cacheEntry) { +: fCacheEntry(cacheEntry) { } SafeZoneStringFormatPtr::~SafeZoneStringFormatPtr() { @@ -1469,7 +1548,7 @@ SafeZoneStringFormatPtr::get() const { } ZSFCacheEntry::ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next) -: UMemory(), fLocale(locale), fZoneStringFormat(zsf), +: fLocale(locale), fZoneStringFormat(zsf), fNext(next), fRefCount(1) { } @@ -1491,7 +1570,7 @@ ZSFCacheEntry::delRef(void) { } ZSFCache::ZSFCache(int32_t capacity) -: UMemory(), fCapacity(capacity), fFirst(NULL) { +: fCapacity(capacity), fFirst(NULL) { } ZSFCache::~ZSFCache() { @@ -1537,6 +1616,11 @@ ZSFCache::get(const Locale &locale, UErrorCode &status) { if (entry == NULL) { ZoneStringFormat *zsf = new ZoneStringFormat(locale, status); if (U_FAILURE(status)) { + delete zsf; + return NULL; + } + if (zsf == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; return NULL; } // Now add the new entry diff --git a/i18n/zstrfmt.h b/i18n/zstrfmt.h index 6765d6dd..bbc5c9be 100644 --- a/i18n/zstrfmt.h +++ b/i18n/zstrfmt.h @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2007, International Business Machines Corporation and * +* Copyright (C) 2007-2008, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -21,45 +21,58 @@ U_NAMESPACE_BEGIN /* * Character node used by TextTrieMap */ -class CharacterNode : public UMemory { -public: - CharacterNode(UChar32 c, UObjectDeleter *fn, UErrorCode &status); - virtual ~CharacterNode(); +struct CharacterNode { + // No constructor or destructor. + // We malloc and free an uninitalized array of CharacterNode objects + // and clear and delete them ourselves. - inline UChar32 getCharacter(void) const; - inline const UVector* getValues(void) const; - inline const UVector* getChildNodes(void) const; + void clear(); + void deleteValues(); void addValue(void *value, UErrorCode &status); - CharacterNode* addChildNode(UChar32 c, UErrorCode &status); - CharacterNode* getChildNode(UChar32 c) const; - -private: - UVector fChildren; - UVector fValues; - UObjectDeleter *fValueDeleter; - UChar32 fCharacter; + inline UBool hasValues() const; + inline int32_t countValues() const; + inline const void *getValue(int32_t index) const; + + void *fValues; // Union of one single value vs. UVector of values. + UChar fCharacter; // UTF-16 code unit. + uint16_t fFirstChild; // 0 if no children. + uint16_t fNextSibling; // 0 terminates the list. + UBool fHasValuesVector; + UBool fPadding; + + // No value: fValues == NULL and fHasValuesVector == FALSE + // One value: fValues == value and fHasValuesVector == FALSE + // >=2 values: fValues == UVector of values and fHasValuesVector == TRUE }; -inline UChar32 CharacterNode::getCharacter(void) const { - return fCharacter; +inline UBool CharacterNode::hasValues() const { + return (UBool)(fValues != NULL); } -inline const UVector* CharacterNode::getValues(void) const { - return &fValues; +inline int32_t CharacterNode::countValues() const { + return + fValues == NULL ? 0 : + !fHasValuesVector ? 1 : + ((const UVector *)fValues)->size(); } -inline const UVector* CharacterNode::getChildNodes(void) const { - return &fChildren; +inline const void *CharacterNode::getValue(int32_t index) const { + if (!fHasValuesVector) { + return fValues; // Assume index == 0. + } else { + return ((const UVector *)fValues)->elementAt(index); + } } /* * Search result handler callback interface used by TextTrieMap search. */ -class TextTrieMapSearchResultHandler { +class TextTrieMapSearchResultHandler : public UMemory { public: virtual UBool handleMatch(int32_t matchLength, - const UVector *values, UErrorCode& status) = 0; + const CharacterNode *node, UErrorCode& status) = 0; + virtual ~TextTrieMapSearchResultHandler(); //added to avoid warning }; /** @@ -68,7 +81,7 @@ public: */ class TextTrieMap : public UMemory { public: - TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleterFunc); + TextTrieMap(UBool ignoreCase); virtual ~TextTrieMap(); void put(const UnicodeString &key, void *value, UErrorCode &status); @@ -78,15 +91,20 @@ public: private: UBool fIgnoreCase; - UObjectDeleter *fValueDeleter; - CharacterNode *fRoot; + CharacterNode *fNodes; + int32_t fNodesCapacity; + int32_t fNodesCount; + + UBool growNodes(); + CharacterNode* addChildNode(CharacterNode *parent, UChar c, UErrorCode &status); + CharacterNode* getChildNode(CharacterNode *parent, UChar c) const; void search(CharacterNode *node, const UnicodeString &text, int32_t start, int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const; }; inline UChar32 TextTrieMap::isEmpty(void) const { - return fRoot == NULL; + return fNodes == NULL; } // Name types, these bit flag are used for zone string lookup @@ -373,12 +391,12 @@ ZoneStrings::isShortFormatCommonlyUsed(void) const { * TextTrieMapSearchHandler. This class is used by ZoneStringFormat * for collecting search results for localized zone strings. */ -class ZoneStringSearchResultHandler : public UMemory, TextTrieMapSearchResultHandler { +class ZoneStringSearchResultHandler : public TextTrieMapSearchResultHandler { public: ZoneStringSearchResultHandler(UErrorCode &status); virtual ~ZoneStringSearchResultHandler(); - virtual UBool handleMatch(int32_t matchLength, const UVector *values, UErrorCode &status); + virtual UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status); int32_t countMatches(void); const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength); void clear(void); |