1b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/*
2b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho*******************************************************************************
3b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho* Copyright (C) 2011, International Business Machines Corporation and         *
4b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho* others. All Rights Reserved.                                                *
5b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho*******************************************************************************
6b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho*/
7b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
8b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/utypes.h"
9b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
10b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#if !UCONFIG_NO_FORMATTING
11b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
12b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "tznames.h"
13b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "tznames_impl.h"
14b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
15b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/locid.h"
16b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/uenum.h"
17b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "cmemory.h"
18b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "cstring.h"
19b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "putilimp.h"
20b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "uassert.h"
21b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "ucln_in.h"
22b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "uhash.h"
23b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "umutex.h"
24b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
25b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
26b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoU_NAMESPACE_BEGIN
27b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
28b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const UChar gEtcPrefix[]         = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
29b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const int32_t gEtcPrefixLen      = 4;
30b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const UChar gSystemVPrefix[]     = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
31b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const int32_t gSystemVPrefixLen  = 8;
32b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const UChar gRiyadh8[]           = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
33b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic const int32_t gRiyadh8Len       = 7;
34b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
35b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// TimeZoneNames object cache handling
36b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UMTX gTimeZoneNamesLock = NULL;
37b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UHashtable *gTimeZoneNamesCache = NULL;
38b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UBool gTimeZoneNamesCacheInitialized = FALSE;
39b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
40b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// Access count - incremented every time up to SWEEP_INTERVAL,
41b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// then reset to 0
42b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic int32_t gAccessCount = 0;
43b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
44b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// Interval for calling the cache sweep function - every 100 times
45b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#define SWEEP_INTERVAL 100
46b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
47b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// Cache expiration in millisecond. When a cached entry is no
48b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// longer referenced and exceeding this threshold since last
49b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// access time, then the cache entry will be deleted by the sweep
50b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// function. For now, 3 minutes.
51b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#define CACHE_EXPIRATION 180000.0
52b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
53b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehotypedef struct TimeZoneNamesCacheEntry {
54b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    TimeZoneNames*  names;
55b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t         refCount;
56b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    double          lastAccess;
57b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho} TimeZoneNamesCacheEntry;
58b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
59b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoU_CDECL_BEGIN
60b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/**
61b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * Cleanup callback func
62b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
63b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UBool U_CALLCONV timeZoneNames_cleanup(void)
64b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho{
65b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    umtx_destroy(&gTimeZoneNamesLock);
66b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
67b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (gTimeZoneNamesCache != NULL) {
68b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        uhash_close(gTimeZoneNamesCache);
69b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        gTimeZoneNamesCache = NULL;
70b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
71b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    gTimeZoneNamesCacheInitialized = FALSE;
72b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return TRUE;
73b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
74b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
75b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/**
76b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * Deleter for TimeZoneNamesCacheEntry
77b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
78b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic void U_CALLCONV
79b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehodeleteTimeZoneNamesCacheEntry(void *obj) {
80b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    icu::TimeZoneNamesCacheEntry *entry = (icu::TimeZoneNamesCacheEntry*)obj;
81b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    delete (icu::TimeZoneNamesImpl*) entry->names;
82b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    uprv_free(entry);
83b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
84b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoU_CDECL_END
85b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
86b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/**
87b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * Function used for removing unreferrenced cache entries exceeding
88b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * the expiration time. This function must be called with in the mutex
89b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * block.
90b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho */
91b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic void sweepCache() {
92b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t pos = -1;
93b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UHashElement* elem;
94b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    double now = (double)uprv_getUTCtime();
95b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
96b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos))) {
97b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        TimeZoneNamesCacheEntry *entry = (TimeZoneNamesCacheEntry *)elem->value.pointer;
98b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
99b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // delete this entry
100b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uhash_removeElement(gTimeZoneNamesCache, elem);
101b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
102b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
103b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
104b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
105b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoclass TimeZoneNamesDelegate : public TimeZoneNames {
106b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehopublic:
107b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status);
108b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    virtual ~TimeZoneNamesDelegate();
109b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
110b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
111b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
112b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString& getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const;
113b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString& getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const;
114b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
115b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString& getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const;
116b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString& getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const;
117b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
118b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString& getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const;
119b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
120b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    TimeZoneNameMatchInfo* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
121b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoprivate:
122b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    TimeZoneNamesCacheEntry*    fTZnamesCacheEntry;
123b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho};
124b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
125b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
126b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UBool initialized;
127b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UMTX_CHECK(&gTimeZoneNamesLock, gTimeZoneNamesCacheInitialized, initialized);
128b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (!initialized) {
129b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // Create empty hashtable
130b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        umtx_lock(&gTimeZoneNamesLock);
131b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        {
132b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (!gTimeZoneNamesCacheInitialized) {
133b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
134b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (U_SUCCESS(status)) {
135b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free);
136b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
137b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    gTimeZoneNamesCacheInitialized = TRUE;
138b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
139b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
140b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
141b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
142b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        umtx_unlock(&gTimeZoneNamesLock);
143b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
144b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_FAILURE(status)) {
145b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return;
146b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
147b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
148b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
149b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Check the cache, if not available, create new one and cache
150b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    TimeZoneNamesCacheEntry *cacheEntry = NULL;
151b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    umtx_lock(&gTimeZoneNamesLock);
152b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    {
153b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const char *key = locale.getName();
154b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
155b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (cacheEntry == NULL) {
156b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            TimeZoneNames *tznames = NULL;
157b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            char *newKey = NULL;
158b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
159b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            tznames = new TimeZoneNamesImpl(locale, status);
160b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (tznames == NULL) {
161b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                status = U_MEMORY_ALLOCATION_ERROR;
162b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
163b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (U_SUCCESS(status)) {
164b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
165b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (newKey == NULL) {
166b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    status = U_MEMORY_ALLOCATION_ERROR;
167b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                } else {
168b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    uprv_strcpy(newKey, key);
169b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
170b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
171b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (U_SUCCESS(status)) {
172b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
173b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (cacheEntry == NULL) {
174b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    status = U_MEMORY_ALLOCATION_ERROR;
175b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                } else {
176b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    cacheEntry->names = tznames;
177b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    cacheEntry->refCount = 1;
178b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    cacheEntry->lastAccess = (double)uprv_getUTCtime();
179b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
180b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
181b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
182b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
183b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (U_FAILURE(status)) {
184b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (tznames != NULL) {
185b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    delete tznames;
186b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
187b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (newKey != NULL) {
188b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    uprv_free(newKey);
189b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
190b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (cacheEntry != NULL) {
191b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    uprv_free(cacheEntry);
192b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
193b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                cacheEntry = NULL;
194b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
195b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        } else {
196b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // Update the reference count
197b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            cacheEntry->refCount++;
198b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            cacheEntry->lastAccess = (double)uprv_getUTCtime();
199b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
200b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        gAccessCount++;
201b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (gAccessCount >= SWEEP_INTERVAL) {
202b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // sweep
203b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            sweepCache();
204b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            gAccessCount = 0;
205b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
206b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
207b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    umtx_unlock(&gTimeZoneNamesLock);
208b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
209b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    fTZnamesCacheEntry = cacheEntry;
210b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
211b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
212b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
213b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    umtx_lock(&gTimeZoneNamesLock);
214b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    {
215b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        U_ASSERT(fTZnamesCacheEntry->refCount > 0);
216b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // Just decrement the reference count
217b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        fTZnamesCacheEntry->refCount--;
218b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
219b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    umtx_unlock(&gTimeZoneNamesLock);
220b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
221b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
222b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoStringEnumeration*
223b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::getAvailableMetaZoneIDs(UErrorCode& status) const {
224b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(status);
225b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
226b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
227b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoStringEnumeration*
228b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
229b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fTZnamesCacheEntry->names->getAvailableMetaZoneIDs(tzID, status);
230b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
231b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
232b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
233b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
234b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fTZnamesCacheEntry->names->getMetaZoneID(tzID, date, mzID);
235b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
236b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
237b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
238b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
239b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fTZnamesCacheEntry->names->getReferenceZoneID(mzID, region, tzID);
240b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
241b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
242b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
243b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::getMetaZoneDisplayName(const UnicodeString& mzID, UTimeZoneNameType type, UnicodeString& name) const {
244b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fTZnamesCacheEntry->names->getMetaZoneDisplayName(mzID, type, name);
245b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
246b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
247b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
248b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const {
249b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fTZnamesCacheEntry->names->getTimeZoneDisplayName(tzID, type, name);
250b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
251b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
252b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
253b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
254b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fTZnamesCacheEntry->names->getExemplarLocationName(tzID, name);
255b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
256b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
257b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNameMatchInfo*
258b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNamesDelegate::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
259b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return fTZnamesCacheEntry->names->find(text, start, types, status);
260b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
261b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
262b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
263b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
264b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNames*
265b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNames::createInstance(const Locale& locale, UErrorCode& status) {
266b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return new TimeZoneNamesDelegate(locale, status);
267b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
268b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
269b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
270b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNames::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
271b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
272b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        || tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
273b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        name.setToBogus();
274b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return name;
275b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
276b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
277b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t sep = tzID.lastIndexOf((UChar)0x2F /* '/' */);
278b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (sep > 0 && sep + 1 < tzID.length()) {
279b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        name.setTo(tzID, sep + 1);
280b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        name.findAndReplace(UnicodeString((UChar)0x5f /* _ */),
281b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            UnicodeString((UChar)0x20 /* space */));
282b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
283b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        name.setToBogus();
284b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
285b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return name;
286b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
287b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
288b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString&
289b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoTimeZoneNames::getDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UDate date, UnicodeString& name) const {
290b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    getTimeZoneDisplayName(tzID, type, name);
291b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (name.isEmpty()) {
292b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UnicodeString mzID;
293b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        getMetaZoneID(tzID, date, mzID);
294b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        getMetaZoneDisplayName(mzID, type, name);
295b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
296b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return name;
297b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
298b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
299b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoU_NAMESPACE_END
300b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#endif
301