LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - tznames.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 232 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 42 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : * Copyright (C) 2011-2015, International Business Machines Corporation and    *
       6             : * others. All Rights Reserved.                                                *
       7             : *******************************************************************************
       8             : */
       9             : 
      10             : #include "unicode/utypes.h"
      11             : 
      12             : #if !UCONFIG_NO_FORMATTING
      13             : 
      14             : #include "unicode/locid.h"
      15             : #include "unicode/tznames.h"
      16             : #include "unicode/uenum.h"
      17             : #include "cmemory.h"
      18             : #include "cstring.h"
      19             : #include "mutex.h"
      20             : #include "putilimp.h"
      21             : #include "tznames_impl.h"
      22             : #include "uassert.h"
      23             : #include "ucln_in.h"
      24             : #include "uhash.h"
      25             : #include "umutex.h"
      26             : #include "uvector.h"
      27             : 
      28             : 
      29             : U_NAMESPACE_BEGIN
      30             : 
      31             : // TimeZoneNames object cache handling
      32             : static UMutex gTimeZoneNamesLock = U_MUTEX_INITIALIZER;
      33             : static UHashtable *gTimeZoneNamesCache = NULL;
      34             : static UBool gTimeZoneNamesCacheInitialized = FALSE;
      35             : 
      36             : // Access count - incremented every time up to SWEEP_INTERVAL,
      37             : // then reset to 0
      38             : static int32_t gAccessCount = 0;
      39             : 
      40             : // Interval for calling the cache sweep function - every 100 times
      41             : #define SWEEP_INTERVAL 100
      42             : 
      43             : // Cache expiration in millisecond. When a cached entry is no
      44             : // longer referenced and exceeding this threshold since last
      45             : // access time, then the cache entry will be deleted by the sweep
      46             : // function. For now, 3 minutes.
      47             : #define CACHE_EXPIRATION 180000.0
      48             : 
      49             : typedef struct TimeZoneNamesCacheEntry {
      50             :     TimeZoneNames*  names;
      51             :     int32_t         refCount;
      52             :     double          lastAccess;
      53             : } TimeZoneNamesCacheEntry;
      54             : 
      55             : U_CDECL_BEGIN
      56             : /**
      57             :  * Cleanup callback func
      58             :  */
      59           0 : static UBool U_CALLCONV timeZoneNames_cleanup(void)
      60             : {
      61           0 :     if (gTimeZoneNamesCache != NULL) {
      62           0 :         uhash_close(gTimeZoneNamesCache);
      63           0 :         gTimeZoneNamesCache = NULL;
      64             :     }
      65           0 :     gTimeZoneNamesCacheInitialized = FALSE;
      66           0 :     return TRUE;
      67             : }
      68             : 
      69             : /**
      70             :  * Deleter for TimeZoneNamesCacheEntry
      71             :  */
      72             : static void U_CALLCONV
      73           0 : deleteTimeZoneNamesCacheEntry(void *obj) {
      74           0 :     icu::TimeZoneNamesCacheEntry *entry = (icu::TimeZoneNamesCacheEntry*)obj;
      75           0 :     delete (icu::TimeZoneNamesImpl*) entry->names;
      76           0 :     uprv_free(entry);
      77           0 : }
      78             : U_CDECL_END
      79             : 
      80             : /**
      81             :  * Function used for removing unreferrenced cache entries exceeding
      82             :  * the expiration time. This function must be called with in the mutex
      83             :  * block.
      84             :  */
      85           0 : static void sweepCache() {
      86           0 :     int32_t pos = UHASH_FIRST;
      87             :     const UHashElement* elem;
      88           0 :     double now = (double)uprv_getUTCtime();
      89             : 
      90           0 :     while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos))) {
      91           0 :         TimeZoneNamesCacheEntry *entry = (TimeZoneNamesCacheEntry *)elem->value.pointer;
      92           0 :         if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
      93             :             // delete this entry
      94           0 :             uhash_removeElement(gTimeZoneNamesCache, elem);
      95             :         }
      96             :     }
      97           0 : }
      98             : 
      99             : // ---------------------------------------------------
     100             : // TimeZoneNamesDelegate
     101             : // ---------------------------------------------------
     102             : class TimeZoneNamesDelegate : public TimeZoneNames {
     103             : public:
     104             :     TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status);
     105             :     virtual ~TimeZoneNamesDelegate();
     106             : 
     107             :     virtual UBool operator==(const TimeZoneNames& other) const;
     108           0 :     virtual UBool operator!=(const TimeZoneNames& other) const {return !operator==(other);};
     109             :     virtual TimeZoneNames* clone() const;
     110             : 
     111             :     StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
     112             :     StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
     113             :     UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const;
     114             :     UnicodeString& getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const;
     115             : 
     116             :     UnicodeString& getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const;
     117             :     UnicodeString& getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const;
     118             : 
     119             :     UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
     120             : 
     121             :     void loadAllDisplayNames(UErrorCode& status);
     122             :     void getDisplayNames(const UnicodeString& tzID, const UTimeZoneNameType types[], int32_t numTypes, UDate date, UnicodeString dest[], UErrorCode& status) const;
     123             : 
     124             :     MatchInfoCollection* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
     125             : private:
     126             :     TimeZoneNamesDelegate();
     127             :     TimeZoneNamesCacheEntry*    fTZnamesCacheEntry;
     128             : };
     129             : 
     130           0 : TimeZoneNamesDelegate::TimeZoneNamesDelegate()
     131           0 : : fTZnamesCacheEntry(0) {
     132           0 : }
     133             : 
     134           0 : TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
     135           0 :     Mutex lock(&gTimeZoneNamesLock);
     136           0 :     if (!gTimeZoneNamesCacheInitialized) {
     137             :         // Create empty hashtable if it is not already initialized.
     138           0 :         gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
     139           0 :         if (U_SUCCESS(status)) {
     140           0 :             uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free);
     141           0 :             uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
     142           0 :             gTimeZoneNamesCacheInitialized = TRUE;
     143           0 :             ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
     144             :         }
     145             :     }
     146             : 
     147           0 :     if (U_FAILURE(status)) {
     148           0 :         return;
     149             :     }
     150             : 
     151             :     // Check the cache, if not available, create new one and cache
     152           0 :     TimeZoneNamesCacheEntry *cacheEntry = NULL;
     153             : 
     154           0 :     const char *key = locale.getName();
     155           0 :     cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
     156           0 :     if (cacheEntry == NULL) {
     157           0 :         TimeZoneNames *tznames = NULL;
     158           0 :         char *newKey = NULL;
     159             : 
     160           0 :         tznames = new TimeZoneNamesImpl(locale, status);
     161           0 :         if (tznames == NULL) {
     162           0 :             status = U_MEMORY_ALLOCATION_ERROR;
     163             :         }
     164           0 :         if (U_SUCCESS(status)) {
     165           0 :             newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
     166           0 :             if (newKey == NULL) {
     167           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     168             :             } else {
     169           0 :                 uprv_strcpy(newKey, key);
     170             :             }
     171             :         }
     172           0 :         if (U_SUCCESS(status)) {
     173           0 :             cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
     174           0 :             if (cacheEntry == NULL) {
     175           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
     176             :             } else {
     177           0 :                 cacheEntry->names = tznames;
     178           0 :                 cacheEntry->refCount = 1;
     179           0 :                 cacheEntry->lastAccess = (double)uprv_getUTCtime();
     180             : 
     181           0 :                 uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
     182             :             }
     183             :         }
     184           0 :         if (U_FAILURE(status)) {
     185           0 :             if (tznames != NULL) {
     186           0 :                 delete tznames;
     187             :             }
     188           0 :             if (newKey != NULL) {
     189           0 :                 uprv_free(newKey);
     190             :             }
     191           0 :             if (cacheEntry != NULL) {
     192           0 :                 uprv_free(cacheEntry);
     193             :             }
     194           0 :             cacheEntry = NULL;
     195             :         }
     196             :     } else {
     197             :         // Update the reference count
     198           0 :         cacheEntry->refCount++;
     199           0 :         cacheEntry->lastAccess = (double)uprv_getUTCtime();
     200             :     }
     201           0 :     gAccessCount++;
     202           0 :     if (gAccessCount >= SWEEP_INTERVAL) {
     203             :         // sweep
     204           0 :         sweepCache();
     205           0 :         gAccessCount = 0;
     206             :     }
     207           0 :     fTZnamesCacheEntry = cacheEntry;
     208             : }
     209             : 
     210           0 : TimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
     211           0 :     umtx_lock(&gTimeZoneNamesLock);
     212             :     {
     213           0 :         if (fTZnamesCacheEntry) {
     214           0 :             U_ASSERT(fTZnamesCacheEntry->refCount > 0);
     215             :             // Just decrement the reference count
     216           0 :             fTZnamesCacheEntry->refCount--;
     217             :         }
     218             :     }
     219           0 :     umtx_unlock(&gTimeZoneNamesLock);
     220           0 : }
     221             : 
     222             : UBool
     223           0 : TimeZoneNamesDelegate::operator==(const TimeZoneNames& other) const {
     224           0 :     if (this == &other) {
     225           0 :         return TRUE;
     226             :     }
     227             :     // Just compare if the other object also use the same
     228             :     // cache entry
     229           0 :     const TimeZoneNamesDelegate* rhs = dynamic_cast<const TimeZoneNamesDelegate*>(&other);
     230           0 :     if (rhs) {
     231           0 :         return fTZnamesCacheEntry == rhs->fTZnamesCacheEntry;
     232             :     }
     233           0 :     return FALSE;
     234             : }
     235             : 
     236             : TimeZoneNames*
     237           0 : TimeZoneNamesDelegate::clone() const {
     238           0 :     TimeZoneNamesDelegate* other = new TimeZoneNamesDelegate();
     239           0 :     if (other != NULL) {
     240           0 :         umtx_lock(&gTimeZoneNamesLock);
     241             :         {
     242             :             // Just increment the reference count
     243           0 :             fTZnamesCacheEntry->refCount++;
     244           0 :             other->fTZnamesCacheEntry = fTZnamesCacheEntry;
     245             :         }
     246           0 :         umtx_unlock(&gTimeZoneNamesLock);
     247             :     }
     248           0 :     return other;
     249             : }
     250             : 
     251             : StringEnumeration*
     252           0 : TimeZoneNamesDelegate::getAvailableMetaZoneIDs(UErrorCode& status) const {
     253           0 :     return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(status);
     254             : }
     255             : 
     256             : StringEnumeration*
     257           0 : TimeZoneNamesDelegate::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
     258           0 :     return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(tzID, status);
     259             : }
     260             : 
     261             : UnicodeString&
     262           0 : TimeZoneNamesDelegate::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
     263           0 :     return fTZnamesCacheEntry->names->getMetaZoneID(tzID, date, mzID);
     264             : }
     265             : 
     266             : UnicodeString&
     267           0 : TimeZoneNamesDelegate::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
     268           0 :     return fTZnamesCacheEntry->names->getReferenceZoneID(mzID, region, tzID);
     269             : }
     270             : 
     271             : UnicodeString&
     272           0 : TimeZoneNamesDelegate::getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const {
     273           0 :     return fTZnamesCacheEntry->names->getMetaZoneDisplayName(mzID, type, name);
     274             : }
     275             : 
     276             : UnicodeString&
     277           0 : TimeZoneNamesDelegate::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const {
     278           0 :     return fTZnamesCacheEntry->names->getTimeZoneDisplayName(tzID, type, name);
     279             : }
     280             : 
     281             : UnicodeString&
     282           0 : TimeZoneNamesDelegate::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
     283           0 :     return fTZnamesCacheEntry->names->getExemplarLocationName(tzID, name);
     284             : }
     285             : 
     286             : void
     287           0 : TimeZoneNamesDelegate::loadAllDisplayNames(UErrorCode& status) {
     288           0 :     fTZnamesCacheEntry->names->loadAllDisplayNames(status);
     289           0 : }
     290             : 
     291             : void
     292           0 : TimeZoneNamesDelegate::getDisplayNames(const UnicodeString& tzID, const UTimeZoneNameType types[], int32_t numTypes, UDate date, UnicodeString dest[], UErrorCode& status) const {
     293           0 :     fTZnamesCacheEntry->names->getDisplayNames(tzID, types, numTypes, date, dest, status);
     294           0 : }
     295             : 
     296             : TimeZoneNames::MatchInfoCollection*
     297           0 : TimeZoneNamesDelegate::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
     298           0 :     return fTZnamesCacheEntry->names->find(text, start, types, status);
     299             : }
     300             : 
     301             : // ---------------------------------------------------
     302             : // TimeZoneNames base class
     303             : // ---------------------------------------------------
     304           0 : TimeZoneNames::~TimeZoneNames() {
     305           0 : }
     306             : 
     307             : TimeZoneNames*
     308           0 : TimeZoneNames::createInstance(const Locale& locale, UErrorCode& status) {
     309           0 :     TimeZoneNames *instance = NULL;
     310           0 :     if (U_SUCCESS(status)) {
     311           0 :         instance = new TimeZoneNamesDelegate(locale, status);
     312           0 :         if (instance == NULL && U_SUCCESS(status)) {
     313           0 :             status = U_MEMORY_ALLOCATION_ERROR;
     314             :         }
     315             :     }
     316           0 :     return instance;
     317             : }
     318             : 
     319             : TimeZoneNames*
     320           0 : TimeZoneNames::createTZDBInstance(const Locale& locale, UErrorCode& status) {
     321           0 :     TimeZoneNames *instance = NULL;
     322           0 :     if (U_SUCCESS(status)) {
     323           0 :         instance = new TZDBTimeZoneNames(locale);
     324           0 :         if (instance == NULL && U_SUCCESS(status)) {
     325           0 :             status = U_MEMORY_ALLOCATION_ERROR;
     326             :         }
     327             :     }
     328           0 :     return instance;
     329             : }
     330             : 
     331             : UnicodeString&
     332           0 : TimeZoneNames::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
     333           0 :     return TimeZoneNamesImpl::getDefaultExemplarLocationName(tzID, name);
     334             : }
     335             : 
     336             : UnicodeString&
     337           0 : TimeZoneNames::getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UDate date, UnicodeString& name) const {
     338           0 :     getTimeZoneDisplayName(tzID, type, name);
     339           0 :     if (name.isEmpty()) {
     340             :         UChar mzIDBuf[32];
     341           0 :         UnicodeString mzID(mzIDBuf, 0, UPRV_LENGTHOF(mzIDBuf));
     342           0 :         getMetaZoneID(tzID, date, mzID);
     343           0 :         getMetaZoneDisplayName(mzID, type, name);
     344             :     }
     345           0 :     return name;
     346             : }
     347             : 
     348             : // Empty default implementation, to be overriden in tznames_impl.cpp.
     349             : void
     350           0 : TimeZoneNames::loadAllDisplayNames(UErrorCode& /*status*/) {
     351           0 : }
     352             : 
     353             : // A default, lightweight implementation of getDisplayNames.
     354             : // Overridden in tznames_impl.cpp.
     355             : void
     356           0 : TimeZoneNames::getDisplayNames(const UnicodeString& tzID, const UTimeZoneNameType types[], int32_t numTypes, UDate date, UnicodeString dest[], UErrorCode& status) const {
     357           0 :     if (U_FAILURE(status)) { return; }
     358           0 :     if (tzID.isEmpty()) { return; }
     359           0 :     UnicodeString mzID;
     360           0 :     for (int i = 0; i < numTypes; i++) {
     361           0 :         getTimeZoneDisplayName(tzID, types[i], dest[i]);
     362           0 :         if (dest[i].isEmpty()) {
     363           0 :             if (mzID.isEmpty()) {
     364           0 :                 getMetaZoneID(tzID, date, mzID);
     365             :             }
     366           0 :             getMetaZoneDisplayName(mzID, types[i], dest[i]);
     367             :         }
     368             :     }
     369             : }
     370             : 
     371             : 
     372           0 : struct MatchInfo : UMemory {
     373             :     UTimeZoneNameType nameType;
     374             :     UnicodeString id;
     375             :     int32_t matchLength;
     376             :     UBool isTZID;
     377             : 
     378           0 :     MatchInfo(UTimeZoneNameType nameType, int32_t matchLength, const UnicodeString* tzID, const UnicodeString* mzID) {
     379           0 :         this->nameType = nameType;
     380           0 :         this->matchLength = matchLength;
     381           0 :         if (tzID != NULL) {
     382           0 :             this->id.setTo(*tzID);
     383           0 :             this->isTZID = TRUE;
     384             :         } else {
     385           0 :             this->id.setTo(*mzID);
     386           0 :             this->isTZID = FALSE;
     387             :         }
     388           0 :     }
     389             : };
     390             : 
     391             : U_CDECL_BEGIN
     392             : static void U_CALLCONV
     393           0 : deleteMatchInfo(void *obj) {
     394           0 :     delete static_cast<MatchInfo *>(obj);
     395           0 : }
     396             : U_CDECL_END
     397             : 
     398             : // ---------------------------------------------------
     399             : // MatchInfoCollection class
     400             : // ---------------------------------------------------
     401           0 : TimeZoneNames::MatchInfoCollection::MatchInfoCollection()
     402           0 : : fMatches(NULL) {
     403           0 : }
     404             : 
     405           0 : TimeZoneNames::MatchInfoCollection::~MatchInfoCollection() {
     406           0 :     if (fMatches != NULL) {
     407           0 :         delete fMatches;
     408             :     }
     409           0 : }
     410             : 
     411             : void
     412           0 : TimeZoneNames::MatchInfoCollection::addZone(UTimeZoneNameType nameType, int32_t matchLength,
     413             :             const UnicodeString& tzID, UErrorCode& status) {
     414           0 :     if (U_FAILURE(status)) {
     415           0 :         return;
     416             :     }
     417           0 :     MatchInfo* matchInfo = new MatchInfo(nameType, matchLength, &tzID, NULL);
     418           0 :     if (matchInfo == NULL) {
     419           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     420           0 :         return;
     421             :     }
     422           0 :     matches(status)->addElement(matchInfo, status);
     423           0 :     if (U_FAILURE(status)) {
     424           0 :         delete matchInfo;
     425             :     }
     426             : }
     427             : 
     428             : void
     429           0 : TimeZoneNames::MatchInfoCollection::addMetaZone(UTimeZoneNameType nameType, int32_t matchLength,
     430             :             const UnicodeString& mzID, UErrorCode& status) {
     431           0 :     if (U_FAILURE(status)) {
     432           0 :         return;
     433             :     }
     434           0 :     MatchInfo* matchInfo = new MatchInfo(nameType, matchLength, NULL, &mzID);
     435           0 :     if (matchInfo == NULL) {
     436           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     437           0 :         return;
     438             :     }
     439           0 :     matches(status)->addElement(matchInfo, status);
     440           0 :     if (U_FAILURE(status)) {
     441           0 :         delete matchInfo;
     442             :     }
     443             : }
     444             : 
     445             : int32_t
     446           0 : TimeZoneNames::MatchInfoCollection::size() const {
     447           0 :     if (fMatches == NULL) {
     448           0 :         return 0;
     449             :     }
     450           0 :     return fMatches->size();
     451             : }
     452             : 
     453             : UTimeZoneNameType
     454           0 : TimeZoneNames::MatchInfoCollection::getNameTypeAt(int32_t idx) const {
     455           0 :     const MatchInfo* match = (const MatchInfo*)fMatches->elementAt(idx);
     456           0 :     if (match) {
     457           0 :         return match->nameType;
     458             :     }
     459           0 :     return UTZNM_UNKNOWN;
     460             : }
     461             : 
     462             : int32_t
     463           0 : TimeZoneNames::MatchInfoCollection::getMatchLengthAt(int32_t idx) const {
     464           0 :     const MatchInfo* match = (const MatchInfo*)fMatches->elementAt(idx);
     465           0 :     if (match) {
     466           0 :         return match->matchLength;
     467             :     }
     468           0 :     return 0;
     469             : }
     470             : 
     471             : UBool
     472           0 : TimeZoneNames::MatchInfoCollection::getTimeZoneIDAt(int32_t idx, UnicodeString& tzID) const {
     473           0 :     tzID.remove();
     474           0 :     const MatchInfo* match = (const MatchInfo*)fMatches->elementAt(idx);
     475           0 :     if (match && match->isTZID) {
     476           0 :         tzID.setTo(match->id);
     477           0 :         return TRUE;
     478             :     }
     479           0 :     return FALSE;
     480             : }
     481             : 
     482             : UBool
     483           0 : TimeZoneNames::MatchInfoCollection::getMetaZoneIDAt(int32_t idx, UnicodeString& mzID) const {
     484           0 :     mzID.remove();
     485           0 :     const MatchInfo* match = (const MatchInfo*)fMatches->elementAt(idx);
     486           0 :     if (match && !match->isTZID) {
     487           0 :         mzID.setTo(match->id);
     488           0 :         return TRUE;
     489             :     }
     490           0 :     return FALSE;
     491             : }
     492             : 
     493             : UVector*
     494           0 : TimeZoneNames::MatchInfoCollection::matches(UErrorCode& status) {
     495           0 :     if (U_FAILURE(status)) {
     496           0 :         return NULL;
     497             :     }
     498           0 :     if (fMatches != NULL) {
     499           0 :         return fMatches;
     500             :     }
     501           0 :     fMatches = new UVector(deleteMatchInfo, NULL, status);
     502           0 :     if (fMatches == NULL) {
     503           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     504           0 :     } else if (U_FAILURE(status)) {
     505           0 :         delete fMatches;
     506           0 :         fMatches = NULL;
     507             :     }
     508           0 :     return fMatches;
     509             : }
     510             : 
     511             : 
     512             : U_NAMESPACE_END
     513             : #endif

Generated by: LCOV version 1.13