+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
-* Copyright (C) 2011-2013, International Business Machines Corporation and
+* Copyright (C) 2011-2016, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
#include "unicode/basictz.h"
#include "unicode/locdspnm.h"
-#include "unicode/msgfmt.h"
#include "unicode/rbtz.h"
+#include "unicode/simpleformatter.h"
#include "unicode/simpletz.h"
+#include "unicode/strenum.h"
#include "unicode/vtzone.h"
#include "cmemory.h"
#include "cstring.h"
+#include "mutex.h"
#include "uhash.h"
#include "uassert.h"
#include "umutex.h"
static const char gZoneStrings[] = "zoneStrings";
static const char gRegionFormatTag[] = "regionFormat";
-static const char gFallbackRegionFormatTag[] = "fallbackRegionFormat";
static const char gFallbackFormatTag[] = "fallbackFormat";
static const UChar gEmpty[] = {0x00};
static const UChar gDefRegionPattern[] = {0x7B, 0x30, 0x7D, 0x00}; // "{0}"
-static const UChar gDefFallbackRegionPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
static const UChar gDefFallbackPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
static const double kDstCheckRange = (double)184*U_MILLIS_PER_DAY;
return results;
}
-static UMutex gLock = U_MUTEX_INITIALIZER;
+static UMutex *gLock() {
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
+}
class TZGNCore : public UMemory {
public:
UHashtable* fLocationNamesMap;
UHashtable* fPartialLocationNamesMap;
- MessageFormat* fRegionFormat;
- MessageFormat* fFallbackFormat;
+ SimpleFormatter fRegionFormat;
+ SimpleFormatter fFallbackFormat;
LocaleDisplayNames* fLocaleDisplayNames;
ZNStringPool fStringPool;
fTimeZoneNames(NULL),
fLocationNamesMap(NULL),
fPartialLocationNamesMap(NULL),
- fRegionFormat(NULL),
- fFallbackFormat(NULL),
fLocaleDisplayNames(NULL),
fStringPool(status),
fGNamesTrie(TRUE, deleteGNameInfo),
// Initialize format patterns
UnicodeString rpat(TRUE, gDefRegionPattern, -1);
- UnicodeString frpat(TRUE, gDefFallbackRegionPattern, -1);
UnicodeString fpat(TRUE, gDefFallbackPattern, -1);
UErrorCode tmpsts = U_ZERO_ERROR; // OK with fallback warning..
rpat.setTo(regionPattern, -1);
}
tmpsts = U_ZERO_ERROR;
- const UChar *fallbackRegionPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackRegionFormatTag, NULL, &tmpsts);
- if (U_SUCCESS(tmpsts) && u_strlen(fallbackRegionPattern) > 0) {
- frpat.setTo(fallbackRegionPattern, -1);
- }
- tmpsts = U_ZERO_ERROR;
const UChar *fallbackPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackFormatTag, NULL, &tmpsts);
if (U_SUCCESS(tmpsts) && u_strlen(fallbackPattern) > 0) {
fpat.setTo(fallbackPattern, -1);
}
ures_close(zoneStrings);
- fRegionFormat = new MessageFormat(rpat, status);
- if (fRegionFormat == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- fFallbackFormat = new MessageFormat(fpat, status);
- if (fFallbackFormat == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ fRegionFormat.applyPatternMinMaxArguments(rpat, 1, 1, status);
+ fFallbackFormat.applyPatternMinMaxArguments(fpat, 2, 2, status);
if (U_FAILURE(status)) {
cleanup();
return;
// target region
const char* region = fLocale.getCountry();
- int32_t regionLen = uprv_strlen(region);
+ int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
if (regionLen == 0) {
char loc[ULOC_FULLNAME_CAPACITY];
uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
TimeZone *tz = TimeZone::createDefault();
const UChar *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
if (tzID != NULL) {
- loadStrings(UnicodeString(tzID));
+ loadStrings(UnicodeString(TRUE, tzID, -1));
}
delete tz;
}
void
TZGNCore::cleanup() {
- if (fRegionFormat != NULL) {
- delete fRegionFormat;
- }
- if (fFallbackFormat != NULL) {
- delete fFallbackFormat;
- }
if (fLocaleDisplayNames != NULL) {
delete fLocaleDisplayNames;
}
{
const UChar* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
if (tzCanonicalID != NULL) {
- getGenericLocationName(UnicodeString(tzCanonicalID), name);
+ getGenericLocationName(UnicodeString(TRUE, tzCanonicalID, -1), name);
}
}
break;
if (name.isEmpty()) {
const UChar* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
if (tzCanonicalID != NULL) {
- getGenericLocationName(UnicodeString(tzCanonicalID), name);
+ getGenericLocationName(UnicodeString(TRUE, tzCanonicalID, -1), name);
}
}
break;
const UChar *locname = NULL;
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
- umtx_lock(&gLock);
+ umtx_lock(gLock());
{
locname = nonConstThis->getGenericLocationName(tzCanonicalID);
}
- umtx_unlock(&gLock);
+ umtx_unlock(gLock());
if (locname == NULL) {
name.setToBogus();
ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode, &isPrimary);
if (!usCountryCode.isEmpty()) {
- FieldPosition fpos;
-
if (isPrimary) {
// If this is the primary zone in the country, use the country name.
char countryCode[ULOC_COUNTRY_CAPACITY];
UnicodeString country;
fLocaleDisplayNames->regionDisplayName(countryCode, country);
-
- Formattable param[] = {
- Formattable(country)
- };
-
- fRegionFormat->format(param, 1, name, fpos, status);
+ fRegionFormat.format(country, name, status);
} else {
// If this is not the primary zone in the country,
// use the exemplar city name.
UnicodeString city;
fTimeZoneNames->getExemplarLocationName(tzCanonicalID, city);
-
- Formattable param[] = {
- Formattable(city),
- };
-
- fRegionFormat->format(param, 1, name, fpos, status);
+ fRegionFormat.format(city, name, status);
}
if (U_FAILURE(status)) {
return NULL;
return name;
}
- UnicodeString tzID(uID);
+ UnicodeString tzID(TRUE, uID, -1);
// Try to get a name from time zone first
UTimeZoneNameType nameType = (type == UTZGNM_LONG) ? UTZNM_LONG_GENERIC : UTZNM_SHORT_GENERIC;
}
// Try meta zone
- UnicodeString mzID;
+ UChar mzIDBuf[32];
+ UnicodeString mzID(mzIDBuf, 0, UPRV_LENGTHOF(mzIDBuf));
fTimeZoneNames->getMetaZoneID(tzID, date, mzID);
if (!mzID.isEmpty()) {
UErrorCode status = U_ZERO_ERROR;
UBool useStandard = FALSE;
int32_t raw, sav;
+ UChar tmpNameBuf[ZONE_NAME_U16_MAX];
tz.getOffset(date, FALSE, raw, sav, status);
if (U_FAILURE(status)) {
if (useStandard) {
UTimeZoneNameType stdNameType = (nameType == UTZNM_LONG_GENERIC)
? UTZNM_LONG_STANDARD : UTZNM_SHORT_STANDARD;
- UnicodeString stdName;
+ UnicodeString stdName(tmpNameBuf, 0, UPRV_LENGTHOF(tmpNameBuf));
fTimeZoneNames->getDisplayName(tzID, stdNameType, date, stdName);
if (!stdName.isEmpty()) {
name.setTo(stdName);
// for some meta zones in some locales. This looks like a data bugs.
// For now, we check if the standard name is different from its generic
// name below.
- UnicodeString mzGenericName;
+ UChar genNameBuf[ZONE_NAME_U16_MAX];
+ UnicodeString mzGenericName(genNameBuf, 0, UPRV_LENGTHOF(genNameBuf));
fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzGenericName);
if (stdName.caseCompare(mzGenericName, 0) == 0) {
name.setToBogus();
}
if (name.isEmpty()) {
// Get a name from meta zone
- UnicodeString mzName;
+ UnicodeString mzName(tmpNameBuf, 0, UPRV_LENGTHOF(tmpNameBuf));
fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzName);
if (!mzName.isEmpty()) {
// Check if we need to use a partial location format.
// This check is done by comparing offset with the meta zone's
// golden zone at the given date.
- UnicodeString goldenID;
+ UChar idBuf[32];
+ UnicodeString goldenID(idBuf, 0, UPRV_LENGTHOF(idBuf));
fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, goldenID);
if (!goldenID.isEmpty() && goldenID != tzID) {
TimeZone *goldenZone = TimeZone::createTimeZone(goldenID);
const UChar *uplname = NULL;
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
- umtx_lock(&gLock);
+ umtx_lock(gLock());
{
uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName);
}
- umtx_unlock(&gLock);
+ umtx_unlock(gLock());
if (uplname == NULL) {
name.setToBogus();
UErrorCode status = U_ZERO_ERROR;
UnicodeString name;
-
- FieldPosition fpos;
- Formattable param[] = {
- Formattable(location),
- Formattable(mzDisplayName)
- };
- fFallbackFormat->format(param, 2, name, fpos, status);
+ fFallbackFormat.format(location, mzDisplayName, name, status);
if (U_FAILURE(status)) {
return NULL;
}
};
StringEnumeration *mzIDs = fTimeZoneNames->getAvailableMetaZoneIDs(tzCanonicalID, status);
- while ((mzID = mzIDs->snext(status))) {
+ while ((mzID = mzIDs->snext(status)) != NULL) {
if (U_FAILURE(status)) {
break;
}
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
- umtx_lock(&gLock);
+ umtx_lock(gLock());
{
fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
}
- umtx_unlock(&gLock);
+ umtx_unlock(gLock());
if (U_FAILURE(status)) {
return NULL;
// All names are not yet loaded into the local trie.
// Load all available names into the trie. This could be very heavy.
- umtx_lock(&gLock);
+ umtx_lock(gLock());
{
if (!fGNamesTrieFullyLoaded) {
StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
if (U_SUCCESS(status)) {
const UnicodeString *tzID;
- while ((tzID = tzIDs->snext(status))) {
+ while ((tzID = tzIDs->snext(status)) != NULL) {
if (U_FAILURE(status)) {
break;
}
}
}
}
- umtx_unlock(&gLock);
+ umtx_unlock(gLock());
if (U_FAILURE(status)) {
return NULL;
}
- umtx_lock(&gLock);
+ umtx_lock(gLock());
{
// now try it again
fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
}
- umtx_unlock(&gLock);
+ umtx_unlock(gLock());
results = handler.getMatches(maxLen);
if (results != NULL && maxLen > 0) {
} TZGNCoreRef;
// TZGNCore object cache handling
-static UMutex gTZGNLock = U_MUTEX_INITIALIZER;
+static UMutex *gTZGNLock() {
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
+}
static UHashtable *gTZGNCoreCache = NULL;
static UBool gTZGNCoreCacheInitialized = FALSE;
* 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(gTZGNCoreCache, &pos))) {
+ while ((elem = uhash_nextElement(gTZGNCoreCache, &pos)) != NULL) {
TZGNCoreRef *entry = (TZGNCoreRef *)elem->value.pointer;
if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
// delete this entry
}
TimeZoneGenericNames::~TimeZoneGenericNames() {
- umtx_lock(&gTZGNLock);
+ umtx_lock(gTZGNLock());
{
U_ASSERT(fRef->refCount > 0);
// Just decrement the reference count
fRef->refCount--;
}
- umtx_unlock(&gTZGNLock);
+ umtx_unlock(gTZGNLock());
}
TimeZoneGenericNames*
return NULL;
}
- UBool initialized;
- UMTX_CHECK(&gTZGNLock, gTZGNCoreCacheInitialized, initialized);
- if (!initialized) {
- // Create empty hashtable
- umtx_lock(&gTZGNLock);
- {
- if (!gTZGNCoreCacheInitialized) {
- gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_SUCCESS(status)) {
- uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
- uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
- gTZGNCoreCacheInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
- }
+ TZGNCoreRef *cacheEntry = NULL;
+ {
+ Mutex lock(gTZGNLock());
+
+ if (!gTZGNCoreCacheInitialized) {
+ // Create empty hashtable
+ gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+ if (U_SUCCESS(status)) {
+ uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
+ uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
+ gTZGNCoreCacheInitialized = TRUE;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
}
}
- umtx_unlock(&gTZGNLock);
-
if (U_FAILURE(status)) {
return NULL;
}
- }
- // Check the cache, if not available, create new one and cache
- TZGNCoreRef *cacheEntry = NULL;
- umtx_lock(&gTZGNLock);
- {
+ // Check the cache, if not available, create new one and cache
const char *key = locale.getName();
cacheEntry = (TZGNCoreRef *)uhash_get(gTZGNCoreCache, key);
if (cacheEntry == NULL) {
sweepCache();
gAccessCount = 0;
}
- }
- umtx_unlock(&gTZGNLock);
+ } // End of mutex locked block
if (cacheEntry == NULL) {
delete instance;
TimeZoneGenericNames::clone() const {
TimeZoneGenericNames* other = new TimeZoneGenericNames();
if (other) {
- umtx_lock(&gTZGNLock);
+ umtx_lock(gTZGNLock());
{
// Just increments the reference count
fRef->refCount++;
other->fRef = fRef;
}
- umtx_unlock(&gTZGNLock);
+ umtx_unlock(gTZGNLock());
}
return other;
}