]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/tznames.cpp
ICU-64243.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / tznames.cpp
index 55ee4168b77f545c8197135965613ffcd0b473bf..bceab395fdbe6485eba5594f1ed82f88b6da9d82 100644 (file)
@@ -1,6 +1,8 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
-* Copyright (C) 2011-2012, International Business Machines Corporation and    *
+* Copyright (C) 2011-2015, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
@@ -14,6 +16,7 @@
 #include "unicode/uenum.h"
 #include "cmemory.h"
 #include "cstring.h"
+#include "mutex.h"
 #include "putilimp.h"
 #include "tznames_impl.h"
 #include "uassert.h"
 
 U_NAMESPACE_BEGIN
 
-static const UChar gEtcPrefix[]         = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
-static const int32_t gEtcPrefixLen      = 4;
-static const UChar gSystemVPrefix[]     = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
-static const int32_t gSystemVPrefixLen  = 8;
-static const UChar gRiyadh8[]           = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
-static const int32_t gRiyadh8Len       = 7;
-
 // TimeZoneNames object cache handling
-static UMTX gTimeZoneNamesLock = NULL;
+static UMutex *gTimeZoneNamesLock() {
+    static UMutex *m = STATIC_NEW(UMutex);
+    return m;
+}
 static UHashtable *gTimeZoneNamesCache = NULL;
 static UBool gTimeZoneNamesCacheInitialized = FALSE;
 
@@ -62,8 +61,6 @@ U_CDECL_BEGIN
  */
 static UBool U_CALLCONV timeZoneNames_cleanup(void)
 {
-    umtx_destroy(&gTimeZoneNamesLock);
-
     if (gTimeZoneNamesCache != NULL) {
         uhash_close(gTimeZoneNamesCache);
         gTimeZoneNamesCache = NULL;
@@ -89,11 +86,11 @@ U_CDECL_END
  * block.
  */
 static void sweepCache() {
-    int32_t pos = -1;
+    int32_t pos = UHASH_FIRST;
     const UHashElement* elem;
     double now = (double)uprv_getUTCtime();
 
-    while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos))) {
+    while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos)) != 0) {
         TimeZoneNamesCacheEntry *entry = (TimeZoneNamesCacheEntry *)elem->value.pointer;
         if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
             // delete this entry
@@ -111,7 +108,7 @@ public:
     virtual ~TimeZoneNamesDelegate();
 
     virtual UBool operator==(const TimeZoneNames& other) const;
-    virtual UBool operator!=(const TimeZoneNames& other) const {return !operator==(other);};
+    virtual UBool operator!=(const TimeZoneNames& other) const {return !operator==(other);}
     virtual TimeZoneNames* clone() const;
 
     StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
@@ -124,6 +121,9 @@ public:
 
     UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
 
+    void loadAllDisplayNames(UErrorCode& status);
+    void getDisplayNames(const UnicodeString& tzID, const UTimeZoneNameType types[], int32_t numTypes, UDate date, UnicodeString dest[], UErrorCode& status) const;
+
     MatchInfoCollection* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
 private:
     TimeZoneNamesDelegate();
@@ -135,94 +135,83 @@ TimeZoneNamesDelegate::TimeZoneNamesDelegate()
 }
 
 TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
-    UBool initialized;
-    UMTX_CHECK(&gTimeZoneNamesLock, gTimeZoneNamesCacheInitialized, initialized);
-    if (!initialized) {
-        // Create empty hashtable
-        umtx_lock(&gTimeZoneNamesLock);
-        {
-            if (!gTimeZoneNamesCacheInitialized) {
-                gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
-                if (U_SUCCESS(status)) {
-                    uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free);
-                    uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
-                    gTimeZoneNamesCacheInitialized = TRUE;
-                    ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
-                }
-            }
+    Mutex lock(gTimeZoneNamesLock());
+    if (!gTimeZoneNamesCacheInitialized) {
+        // Create empty hashtable if it is not already initialized.
+        gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+        if (U_SUCCESS(status)) {
+            uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free);
+            uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
+            gTimeZoneNamesCacheInitialized = TRUE;
+            ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
         }
-        umtx_unlock(&gTimeZoneNamesLock);
+    }
 
-        if (U_FAILURE(status)) {
-            return;
-        }
+    if (U_FAILURE(status)) {
+        return;
     }
 
     // Check the cache, if not available, create new one and cache
     TimeZoneNamesCacheEntry *cacheEntry = NULL;
-    umtx_lock(&gTimeZoneNamesLock);
-    {
-        const char *key = locale.getName();
-        cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
-        if (cacheEntry == NULL) {
-            TimeZoneNames *tznames = NULL;
-            char *newKey = NULL;
-
-            tznames = new TimeZoneNamesImpl(locale, status);
-            if (tznames == NULL) {
+
+    const char *key = locale.getName();
+    cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
+    if (cacheEntry == NULL) {
+        TimeZoneNames *tznames = NULL;
+        char *newKey = NULL;
+
+        tznames = new TimeZoneNamesImpl(locale, status);
+        if (tznames == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+        if (U_SUCCESS(status)) {
+            newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
+            if (newKey == NULL) {
                 status = U_MEMORY_ALLOCATION_ERROR;
+            } else {
+                uprv_strcpy(newKey, key);
             }
-            if (U_SUCCESS(status)) {
-                newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
-                if (newKey == NULL) {
-                    status = U_MEMORY_ALLOCATION_ERROR;
-                } else {
-                    uprv_strcpy(newKey, key);
-                }
+        }
+        if (U_SUCCESS(status)) {
+            cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
+            if (cacheEntry == NULL) {
+                status = U_MEMORY_ALLOCATION_ERROR;
+            } else {
+                cacheEntry->names = tznames;
+                cacheEntry->refCount = 1;
+                cacheEntry->lastAccess = (double)uprv_getUTCtime();
+
+                uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
             }
-            if (U_SUCCESS(status)) {
-                cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
-                if (cacheEntry == NULL) {
-                    status = U_MEMORY_ALLOCATION_ERROR;
-                } else {
-                    cacheEntry->names = tznames;
-                    cacheEntry->refCount = 1;
-                    cacheEntry->lastAccess = (double)uprv_getUTCtime();
-
-                    uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
-                }
+        }
+        if (U_FAILURE(status)) {
+            if (tznames != NULL) {
+                delete tznames;
             }
-            if (U_FAILURE(status)) {
-                if (tznames != NULL) {
-                    delete tznames;
-                }
-                if (newKey != NULL) {
-                    uprv_free(newKey);
-                }
-                if (cacheEntry != NULL) {
-                    uprv_free(cacheEntry);
-                }
-                cacheEntry = NULL;
+            if (newKey != NULL) {
+                uprv_free(newKey);
             }
-        } else {
-            // Update the reference count
-            cacheEntry->refCount++;
-            cacheEntry->lastAccess = (double)uprv_getUTCtime();
-        }
-        gAccessCount++;
-        if (gAccessCount >= SWEEP_INTERVAL) {
-            // sweep
-            sweepCache();
-            gAccessCount = 0;
+            if (cacheEntry != NULL) {
+                uprv_free(cacheEntry);
+            }
+            cacheEntry = NULL;
         }
+    } else {
+        // Update the reference count
+        cacheEntry->refCount++;
+        cacheEntry->lastAccess = (double)uprv_getUTCtime();
+    }
+    gAccessCount++;
+    if (gAccessCount >= SWEEP_INTERVAL) {
+        // sweep
+        sweepCache();
+        gAccessCount = 0;
     }
-    umtx_unlock(&gTimeZoneNamesLock);
-
     fTZnamesCacheEntry = cacheEntry;
 }
 
 TimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
-    umtx_lock(&gTimeZoneNamesLock);
+    umtx_lock(gTimeZoneNamesLock());
     {
         if (fTZnamesCacheEntry) {
             U_ASSERT(fTZnamesCacheEntry->refCount > 0);
@@ -230,7 +219,7 @@ TimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
             fTZnamesCacheEntry->refCount--;
         }
     }
-    umtx_unlock(&gTimeZoneNamesLock);
+    umtx_unlock(gTimeZoneNamesLock());
 }
 
 UBool
@@ -251,13 +240,13 @@ TimeZoneNames*
 TimeZoneNamesDelegate::clone() const {
     TimeZoneNamesDelegate* other = new TimeZoneNamesDelegate();
     if (other != NULL) {
-        umtx_lock(&gTimeZoneNamesLock);
+        umtx_lock(gTimeZoneNamesLock());
         {
             // Just increment the reference count
             fTZnamesCacheEntry->refCount++;
             other->fTZnamesCacheEntry = fTZnamesCacheEntry;
         }
-        umtx_unlock(&gTimeZoneNamesLock);
+        umtx_unlock(gTimeZoneNamesLock());
     }
     return other;
 }
@@ -297,6 +286,16 @@ TimeZoneNamesDelegate::getExemplarLocationName(const UnicodeString& tzID, Unicod
     return fTZnamesCacheEntry->names->getExemplarLocationName(tzID, name);
 }
 
+void
+TimeZoneNamesDelegate::loadAllDisplayNames(UErrorCode& status) {
+    fTZnamesCacheEntry->names->loadAllDisplayNames(status);
+}
+
+void
+TimeZoneNamesDelegate::getDisplayNames(const UnicodeString& tzID, const UTimeZoneNameType types[], int32_t numTypes, UDate date, UnicodeString dest[], UErrorCode& status) const {
+    fTZnamesCacheEntry->names->getDisplayNames(tzID, types, numTypes, date, dest, status);
+}
+
 TimeZoneNames::MatchInfoCollection*
 TimeZoneNamesDelegate::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
     return fTZnamesCacheEntry->names->find(text, start, types, status);
@@ -305,46 +304,73 @@ TimeZoneNamesDelegate::find(const UnicodeString& text, int32_t start, uint32_t t
 // ---------------------------------------------------
 // TimeZoneNames base class
 // ---------------------------------------------------
-UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(TimeZoneNames)
-
 TimeZoneNames::~TimeZoneNames() {
 }
 
 TimeZoneNames*
 TimeZoneNames::createInstance(const Locale& locale, UErrorCode& status) {
-    return new TimeZoneNamesDelegate(locale, status);
+    TimeZoneNames *instance = NULL;
+    if (U_SUCCESS(status)) {
+        instance = new TimeZoneNamesDelegate(locale, status);
+        if (instance == NULL && U_SUCCESS(status)) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+    }
+    return instance;
 }
 
-UnicodeString&
-TimeZoneNames::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
-    if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
-        || tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
-        name.setToBogus();
-        return name;
+TimeZoneNames*
+TimeZoneNames::createTZDBInstance(const Locale& locale, UErrorCode& status) {
+    TimeZoneNames *instance = NULL;
+    if (U_SUCCESS(status)) {
+        instance = new TZDBTimeZoneNames(locale);
+        if (instance == NULL && U_SUCCESS(status)) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
     }
+    return instance;
+}
 
-    int32_t sep = tzID.lastIndexOf((UChar)0x2F /* '/' */);
-    if (sep > 0 && sep + 1 < tzID.length()) {
-        name.setTo(tzID, sep + 1);
-        name.findAndReplace(UnicodeString((UChar)0x5f /* _ */),
-                            UnicodeString((UChar)0x20 /* space */));
-    } else {
-        name.setToBogus();
-    }
-    return name;
+UnicodeString&
+TimeZoneNames::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
+    return TimeZoneNamesImpl::getDefaultExemplarLocationName(tzID, name);
 }
 
 UnicodeString&
 TimeZoneNames::getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UDate date, UnicodeString& name) const {
     getTimeZoneDisplayName(tzID, type, name);
     if (name.isEmpty()) {
-        UnicodeString mzID;
+        UChar mzIDBuf[32];
+        UnicodeString mzID(mzIDBuf, 0, UPRV_LENGTHOF(mzIDBuf));
         getMetaZoneID(tzID, date, mzID);
         getMetaZoneDisplayName(mzID, type, name);
     }
     return name;
 }
 
+// Empty default implementation, to be overriden in tznames_impl.cpp.
+void
+TimeZoneNames::loadAllDisplayNames(UErrorCode& /*status*/) {
+}
+
+// A default, lightweight implementation of getDisplayNames.
+// Overridden in tznames_impl.cpp.
+void
+TimeZoneNames::getDisplayNames(const UnicodeString& tzID, const UTimeZoneNameType types[], int32_t numTypes, UDate date, UnicodeString dest[], UErrorCode& status) const {
+    if (U_FAILURE(status)) { return; }
+    if (tzID.isEmpty()) { return; }
+    UnicodeString mzID;
+    for (int i = 0; i < numTypes; i++) {
+        getTimeZoneDisplayName(tzID, types[i], dest[i]);
+        if (dest[i].isEmpty()) {
+            if (mzID.isEmpty()) {
+                getMetaZoneID(tzID, date, mzID);
+            }
+            getMetaZoneDisplayName(mzID, types[i], dest[i]);
+        }
+    }
+}
+
 
 struct MatchInfo : UMemory {
     UTimeZoneNameType nameType;