+// © 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. *
*******************************************************************************
*/
#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;
*/
static UBool U_CALLCONV timeZoneNames_cleanup(void)
{
- umtx_destroy(&gTimeZoneNamesLock);
-
if (gTimeZoneNamesCache != NULL) {
uhash_close(gTimeZoneNamesCache);
gTimeZoneNamesCache = NULL;
* 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
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;
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();
}
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);
fTZnamesCacheEntry->refCount--;
}
}
- umtx_unlock(&gTimeZoneNamesLock);
+ umtx_unlock(gTimeZoneNamesLock());
}
UBool
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;
}
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);
// ---------------------------------------------------
// 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;