Bug Summary

File:root/firefox-clang/intl/icu/source/i18n/tzgnames.cpp
Warning:line 1176, column 9
Access to field 'refCount' results in a dereference of a null pointer (loaded from field 'fRef')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tzgnames.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/i18n -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/i18n -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D U_I18N_IMPLEMENTATION -D _LIBCPP_DISABLE_DEPRECATION_WARNINGS -D U_USING_ICU_NAMESPACE=0 -D U_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -D U_HIDE_OBSOLETE_UTF_OLD_H=1 -D UCONFIG_NO_LEGACY_CONVERSION -D UCONFIG_NO_TRANSLITERATION -D UCONFIG_NO_REGULAR_EXPRESSIONS -D UCONFIG_NO_BREAK_ITERATION -D UCONFIG_NO_IDNA -D UCONFIG_NO_MF2 -D UCONFIG_NO_NORMALIZATION -D UCONFIG_NO_COLLATION -D U_CHARSET_IS_UTF8 -D UNISTR_FROM_CHAR_EXPLICIT=explicit -D UNISTR_FROM_STRING_EXPLICIT=explicit -D U_ENABLE_DYLOAD=0 -D U_DEBUG=1 -I /root/firefox-clang/config/external/icu/i18n -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/i18n -I /root/firefox-clang/intl/icu/source/common -I /root/firefox-clang/mfbt/double-conversion -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-comma -Wno-implicit-const-int-float-conversion -Wno-macro-redefined -Wno-microsoft-include -Wno-tautological-unsigned-enum-zero-compare -Wno-unreachable-code-loop-increment -Wno-unreachable-code-return -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/intl/icu/source/i18n/tzgnames.cpp

/root/firefox-clang/intl/icu/source/i18n/tzgnames.cpp

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-2016, International Business Machines Corporation and
6* others. All Rights Reserved.
7*******************************************************************************
8*/
9
10#include "unicode/utypes.h"
11
12#if !UCONFIG_NO_FORMATTING0
13
14#include "tzgnames.h"
15
16#include "unicode/basictz.h"
17#include "unicode/locdspnm.h"
18#include "unicode/rbtz.h"
19#include "unicode/simpleformatter.h"
20#include "unicode/simpletz.h"
21#include "unicode/strenum.h"
22#include "unicode/vtzone.h"
23
24#include "charstr.h"
25#include "cmemory.h"
26#include "cstring.h"
27#include "fixedstring.h"
28#include "mutex.h"
29#include "uhash.h"
30#include "uassert.h"
31#include "umutex.h"
32#include "ulocimp.h"
33#include "uresimp.h"
34#include "ureslocs.h"
35#include "zonemeta.h"
36#include "tznames_impl.h"
37#include "olsontz.h"
38#include "ucln_in.h"
39
40U_NAMESPACE_BEGINnamespace icu_78 {
41
42#define ZID_KEY_MAX128 128
43
44static const char gZoneStrings[] = "zoneStrings";
45
46static const char gRegionFormatTag[] = "regionFormat";
47static const char gFallbackFormatTag[] = "fallbackFormat";
48
49static const char16_t gEmpty[] = {0x00};
50
51static const char16_t gDefRegionPattern[] = {0x7B, 0x30, 0x7D, 0x00}; // "{0}"
52static const char16_t gDefFallbackPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
53
54static const double kDstCheckRange = static_cast<double>(184) * U_MILLIS_PER_DAY(86400000);
55
56
57
58U_CDECL_BEGINextern "C" {
59
60typedef struct PartialLocationKey {
61 const char16_t* tzID;
62 const char16_t* mzID;
63 UBool isLong;
64} PartialLocationKey;
65
66/**
67 * Hash function for partial location name hash key
68 */
69static int32_t U_CALLCONV
70hashPartialLocationKey(const UHashTok key) {
71 // <tzID>&<mzID>#[L|S]
72 PartialLocationKey *p = (PartialLocationKey *)key.pointer;
73 UnicodeString str(p->tzID);
74 str.append((char16_t)0x26)
75 .append(p->mzID, -1)
76 .append((char16_t)0x23)
77 .append((char16_t)(p->isLong ? 0x4C : 0x53));
78 return str.hashCode();
79}
80
81/**
82 * Comparer for partial location name hash key
83 */
84static UBool U_CALLCONV
85comparePartialLocationKey(const UHashTok key1, const UHashTok key2) {
86 PartialLocationKey *p1 = (PartialLocationKey *)key1.pointer;
87 PartialLocationKey *p2 = (PartialLocationKey *)key2.pointer;
88
89 if (p1 == p2) {
90 return true;
91 }
92 if (p1 == nullptr || p2 == nullptr) {
93 return false;
94 }
95 // We just check identity of tzID/mzID
96 return (p1->tzID == p2->tzID && p1->mzID == p2->mzID && p1->isLong == p2->isLong);
97}
98
99/**
100 * Deleter for GNameInfo
101 */
102static void U_CALLCONV
103deleteGNameInfo(void *obj) {
104 uprv_free(obj);
105}
106
107/**
108 * GNameInfo stores zone name information in the local trie
109 */
110typedef struct GNameInfo {
111 UTimeZoneGenericNameType type;
112 const char16_t* tzID;
113} ZNameInfo;
114
115/**
116 * GMatchInfo stores zone name match information used by find method
117 */
118typedef struct GMatchInfo {
119 const GNameInfo* gnameInfo;
120 int32_t matchLength;
121 UTimeZoneFormatTimeType timeType;
122} ZMatchInfo;
123
124U_CDECL_END}
125
126// ---------------------------------------------------
127// The class stores time zone generic name match information
128// ---------------------------------------------------
129class TimeZoneGenericNameMatchInfo : public UMemory {
130public:
131 TimeZoneGenericNameMatchInfo(UVector* matches);
132 ~TimeZoneGenericNameMatchInfo();
133
134 int32_t size() const;
135 UTimeZoneGenericNameType getGenericNameType(int32_t index) const;
136 int32_t getMatchLength(int32_t index) const;
137 UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const;
138
139private:
140 UVector* fMatches; // vector of MatchEntry
141};
142
143TimeZoneGenericNameMatchInfo::TimeZoneGenericNameMatchInfo(UVector* matches)
144: fMatches(matches) {
145}
146
147TimeZoneGenericNameMatchInfo::~TimeZoneGenericNameMatchInfo() {
148 delete fMatches;
149}
150
151int32_t
152TimeZoneGenericNameMatchInfo::size() const {
153 if (fMatches == nullptr) {
154 return 0;
155 }
156 return fMatches->size();
157}
158
159UTimeZoneGenericNameType
160TimeZoneGenericNameMatchInfo::getGenericNameType(int32_t index) const {
161 GMatchInfo* minfo = static_cast<GMatchInfo*>(fMatches->elementAt(index));
162 if (minfo != nullptr) {
163 return static_cast<UTimeZoneGenericNameType>(minfo->gnameInfo->type);
164 }
165 return UTZGNM_UNKNOWN;
166}
167
168int32_t
169TimeZoneGenericNameMatchInfo::getMatchLength(int32_t index) const {
170 ZMatchInfo* minfo = static_cast<ZMatchInfo*>(fMatches->elementAt(index));
171 if (minfo != nullptr) {
172 return minfo->matchLength;
173 }
174 return -1;
175}
176
177UnicodeString&
178TimeZoneGenericNameMatchInfo::getTimeZoneID(int32_t index, UnicodeString& tzID) const {
179 GMatchInfo* minfo = static_cast<GMatchInfo*>(fMatches->elementAt(index));
180 if (minfo != nullptr && minfo->gnameInfo->tzID != nullptr) {
181 tzID.setTo(true, minfo->gnameInfo->tzID, -1);
182 } else {
183 tzID.setToBogus();
184 }
185 return tzID;
186}
187
188// ---------------------------------------------------
189// GNameSearchHandler
190// ---------------------------------------------------
191class GNameSearchHandler : public TextTrieMapSearchResultHandler {
192public:
193 GNameSearchHandler(uint32_t types);
194 virtual ~GNameSearchHandler();
195
196 UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) override;
197 UVector* getMatches(int32_t& maxMatchLen);
198
199private:
200 uint32_t fTypes;
201 UVector* fResults;
202 int32_t fMaxMatchLen;
203};
204
205GNameSearchHandler::GNameSearchHandler(uint32_t types)
206: fTypes(types), fResults(nullptr), fMaxMatchLen(0) {
207}
208
209GNameSearchHandler::~GNameSearchHandler() {
210 delete fResults;
211}
212
213UBool
214GNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
215 if (U_FAILURE(status)) {
216 return false;
217 }
218 if (node->hasValues()) {
219 int32_t valuesCount = node->countValues();
220 for (int32_t i = 0; i < valuesCount; i++) {
221 GNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
222 if (nameinfo == nullptr) {
223 break;
224 }
225 if ((nameinfo->type & fTypes) != 0) {
226 // matches a requested type
227 if (fResults == nullptr) {
228 LocalPointer<UVector> lpResults(new UVector(uprv_free, nullptr, status), status);
229 if (U_FAILURE(status)) {
230 return false;
231 }
232 fResults = lpResults.orphan();
233 }
234 GMatchInfo* gmatch = static_cast<GMatchInfo*>(uprv_malloc(sizeof(GMatchInfo)));
235 if (gmatch == nullptr) {
236 status = U_MEMORY_ALLOCATION_ERROR;
237 return false;
238 }
239 // add the match to the vector
240 gmatch->gnameInfo = nameinfo;
241 gmatch->matchLength = matchLength;
242 gmatch->timeType = UTZFMT_TIME_TYPE_UNKNOWN;
243 fResults->adoptElement(gmatch, status);
244 if (U_FAILURE(status)) {
245 return false;
246 }
247 if (matchLength > fMaxMatchLen) {
248 fMaxMatchLen = matchLength;
249 }
250 }
251 }
252 }
253 return true;
254}
255
256UVector*
257GNameSearchHandler::getMatches(int32_t& maxMatchLen) {
258 // give the ownership to the caller
259 UVector *results = fResults;
260 maxMatchLen = fMaxMatchLen;
261
262 // reset
263 fResults = nullptr;
264 fMaxMatchLen = 0;
265 return results;
266}
267
268static UMutex gLock;
269
270class TZGNCore : public UMemory {
271public:
272 TZGNCore(const Locale& locale, UErrorCode& status);
273 virtual ~TZGNCore();
274
275 UnicodeString& getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
276 UDate date, UnicodeString& name) const;
277
278 UnicodeString& getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const;
279
280 int32_t findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
281 UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const;
282
283private:
284 Locale fLocale;
285 const TimeZoneNames* fTimeZoneNames;
286 UHashtable* fLocationNamesMap;
287 UHashtable* fPartialLocationNamesMap;
288
289 SimpleFormatter fRegionFormat;
290 SimpleFormatter fFallbackFormat;
291
292 LocaleDisplayNames* fLocaleDisplayNames;
293 ZNStringPool fStringPool;
294
295 TextTrieMap fGNamesTrie;
296 UBool fGNamesTrieFullyLoaded;
297
298 FixedString fTargetRegion;
299
300 void initialize(const Locale& locale, UErrorCode& status);
301 void cleanup();
302
303 void loadStrings(const UnicodeString& tzCanonicalID);
304
305 const char16_t* getGenericLocationName(const UnicodeString& tzCanonicalID);
306
307 UnicodeString& formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type,
308 UDate date, UnicodeString& name) const;
309
310 UnicodeString& getPartialLocationName(const UnicodeString& tzCanonicalID,
311 const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
312 UnicodeString& name) const;
313
314 const char16_t* getPartialLocationName(const UnicodeString& tzCanonicalID,
315 const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName);
316
317 TimeZoneGenericNameMatchInfo* findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
318
319 TimeZoneNames::MatchInfoCollection* findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
320};
321
322
323// ---------------------------------------------------
324// TZGNCore - core implementation of TimeZoneGenericNames
325//
326// TimeZoneGenericNames is parallel to TimeZoneNames,
327// but handles run-time generated time zone names.
328// This is the main part of this module.
329// ---------------------------------------------------
330TZGNCore::TZGNCore(const Locale& locale, UErrorCode& status)
331: fLocale(locale),
332 fTimeZoneNames(nullptr),
333 fLocationNamesMap(nullptr),
334 fPartialLocationNamesMap(nullptr),
335 fLocaleDisplayNames(nullptr),
336 fStringPool(status),
337 fGNamesTrie(true, deleteGNameInfo),
338 fGNamesTrieFullyLoaded(false),
339 fTargetRegion() {
340 initialize(locale, status);
341}
342
343TZGNCore::~TZGNCore() {
344 cleanup();
345}
346
347void
348TZGNCore::initialize(const Locale& locale, UErrorCode& status) {
349 if (U_FAILURE(status)) {
350 return;
351 }
352
353 // TimeZoneNames
354 fTimeZoneNames = TimeZoneNames::createInstance(locale, status);
355 if (U_FAILURE(status)) {
356 return;
357 }
358
359 // Initialize format patterns
360 UnicodeString rpat(true, gDefRegionPattern, -1);
361 UnicodeString fpat(true, gDefFallbackPattern, -1);
362
363 UErrorCode tmpsts = U_ZERO_ERROR; // OK with fallback warning..
364 UResourceBundle *zoneStrings = ures_open(U_ICUDATA_ZONE"icudt" "78" "l" "-" "zone", locale.getName(), &tmpsts);
365 zoneStrings = ures_getByKeyWithFallback(zoneStrings, gZoneStrings, zoneStrings, &tmpsts);
366
367 if (U_SUCCESS(tmpsts)) {
368 const char16_t *regionPattern = ures_getStringByKeyWithFallback(zoneStrings, gRegionFormatTag, nullptr, &tmpsts);
369 if (U_SUCCESS(tmpsts) && u_strlen(regionPattern) > 0) {
370 rpat.setTo(regionPattern, -1);
371 }
372 tmpsts = U_ZERO_ERROR;
373 const char16_t *fallbackPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackFormatTag, nullptr, &tmpsts);
374 if (U_SUCCESS(tmpsts) && u_strlen(fallbackPattern) > 0) {
375 fpat.setTo(fallbackPattern, -1);
376 }
377 }
378 ures_close(zoneStrings);
379
380 fRegionFormat.applyPatternMinMaxArguments(rpat, 1, 1, status);
381 fFallbackFormat.applyPatternMinMaxArguments(fpat, 2, 2, status);
382 if (U_FAILURE(status)) {
383 cleanup();
384 return;
385 }
386
387 // locale display names
388 fLocaleDisplayNames = LocaleDisplayNames::createInstance(locale);
389
390 // hash table for names - no key/value deleters
391 fLocationNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status);
392 if (U_FAILURE(status)) {
393 cleanup();
394 return;
395 }
396
397 fPartialLocationNamesMap = uhash_open(hashPartialLocationKey, comparePartialLocationKey, nullptr, &status);
398 if (U_FAILURE(status)) {
399 cleanup();
400 return;
401 }
402 uhash_setKeyDeleter(fPartialLocationNamesMap, uprv_free);
403 // no value deleter
404
405 // target region
406 const char* region = fLocale.getCountry();
407 int32_t regionLen = static_cast<int32_t>(uprv_strlen(region):: strlen(region));
408 if (regionLen == 0) {
409 CharString loc = ulocimp_addLikelySubtags(fLocale.getName(), status);
410 CharString tmp;
411 ulocimp_getSubtags(loc.toStringPiece(), nullptr, nullptr, &tmp, nullptr, nullptr, status);
412 if (U_FAILURE(status)) {
413 cleanup();
414 return;
415 }
416 fTargetRegion = tmp.toStringPiece();
417 if (fTargetRegion.isEmpty() != tmp.isEmpty()) {
418 status = U_MEMORY_ALLOCATION_ERROR;
419 cleanup();
420 return;
421 }
422 } else {
423 fTargetRegion = {region, static_cast<std::string_view::size_type>(regionLen)};
424 if (fTargetRegion.isEmpty()) {
425 status = U_MEMORY_ALLOCATION_ERROR;
426 cleanup();
427 return;
428 }
429 }
430
431 // preload generic names for the default zone
432 TimeZone *tz = TimeZone::createDefault();
433 const char16_t *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
434 if (tzID != nullptr) {
435 loadStrings(UnicodeString(true, tzID, -1));
436 }
437 delete tz;
438}
439
440void
441TZGNCore::cleanup() {
442 delete fLocaleDisplayNames;
443 delete fTimeZoneNames;
444
445 uhash_close(fLocationNamesMap);
446 uhash_close(fPartialLocationNamesMap);
447}
448
449
450UnicodeString&
451TZGNCore::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
452 name.setToBogus();
453 switch (type) {
454 case UTZGNM_LOCATION:
455 {
456 const char16_t* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
457 if (tzCanonicalID != nullptr) {
458 getGenericLocationName(UnicodeString(true, tzCanonicalID, -1), name);
459 }
460 }
461 break;
462 case UTZGNM_LONG:
463 case UTZGNM_SHORT:
464 formatGenericNonLocationName(tz, type, date, name);
465 if (name.isEmpty()) {
466 const char16_t* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
467 if (tzCanonicalID != nullptr) {
468 getGenericLocationName(UnicodeString(true, tzCanonicalID, -1), name);
469 }
470 }
471 break;
472 default:
473 break;
474 }
475 return name;
476}
477
478UnicodeString&
479TZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
480 if (tzCanonicalID.isEmpty()) {
481 name.setToBogus();
482 return name;
483 }
484
485 const char16_t *locname = nullptr;
486 TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
487 umtx_lock(&gLock);
488 {
489 locname = nonConstThis->getGenericLocationName(tzCanonicalID);
490 }
491 umtx_unlock(&gLock);
492
493 if (locname == nullptr) {
494 name.setToBogus();
495 } else {
496 name.setTo(locname, u_strlen(locname));
497 }
498
499 return name;
500}
501
502/*
503 * This method updates the cache and must be called with a lock
504 */
505const char16_t*
506TZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID) {
507 U_ASSERT(!tzCanonicalID.isEmpty())(static_cast <bool> (!tzCanonicalID.isEmpty()) ? void (
0) : __assert_fail ("!tzCanonicalID.isEmpty()", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
508 if (tzCanonicalID.length() > ZID_KEY_MAX128) {
509 return nullptr;
510 }
511
512 UErrorCode status = U_ZERO_ERROR;
513 char16_t tzIDKey[ZID_KEY_MAX128 + 1];
514 int32_t tzIDKeyLen = tzCanonicalID.extract(tzIDKey, ZID_KEY_MAX128 + 1, status);
515 U_ASSERT(status == U_ZERO_ERROR)(static_cast <bool> (status == U_ZERO_ERROR) ? void (0)
: __assert_fail ("status == U_ZERO_ERROR", __builtin_FILE ()
, __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
; // already checked length above
516 tzIDKey[tzIDKeyLen] = 0;
517
518 const char16_t* locname = static_cast<const char16_t*>(uhash_get(fLocationNamesMap, tzIDKey));
519
520 if (locname != nullptr) {
521 // gEmpty indicate the name is not available
522 if (locname == gEmpty) {
523 return nullptr;
524 }
525 return locname;
526 }
527
528 // Construct location name
529 UnicodeString name;
530 UnicodeString usCountryCode;
531 UBool isPrimary = false;
532
533 ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode, &isPrimary);
534
535 if (!usCountryCode.isEmpty()) {
536 if (isPrimary) {
537 // If this is the primary zone in the country, use the country name.
538 char countryCode[ULOC_COUNTRY_CAPACITY4];
539 U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY)(static_cast <bool> (usCountryCode.length() < 4) ? void
(0) : __assert_fail ("usCountryCode.length() < 4", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
540 int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INVicu::UnicodeString::kInvariant);
541 countryCode[ccLen] = 0;
542
543 UnicodeString country;
544 fLocaleDisplayNames->regionDisplayName(countryCode, country);
545 fRegionFormat.format(country, name, status);
546 } else {
547 // If this is not the primary zone in the country,
548 // use the exemplar city name.
549
550 // getExemplarLocationName should return non-empty string
551 // if the time zone is associated with a region
552
553 UnicodeString city;
554 fTimeZoneNames->getExemplarLocationName(tzCanonicalID, city);
555 fRegionFormat.format(city, name, status);
556 }
557 if (U_FAILURE(status)) {
558 return nullptr;
559 }
560 }
561
562 locname = name.isEmpty() ? nullptr : fStringPool.get(name, status);
563 if (U_SUCCESS(status)) {
564 // Cache the result
565 const char16_t* cacheID = ZoneMeta::findTimeZoneID(tzCanonicalID);
566 U_ASSERT(cacheID != nullptr)(static_cast <bool> (cacheID != nullptr) ? void (0) : __assert_fail
("cacheID != nullptr", __builtin_FILE (), __builtin_LINE (),
__extension__ __PRETTY_FUNCTION__))
;
567 if (locname == nullptr) {
568 // gEmpty to indicate - no location name available
569 uhash_put(fLocationNamesMap, (void *)cacheID, (void *)gEmpty, &status);
570 } else {
571 uhash_put(fLocationNamesMap, (void *)cacheID, (void *)locname, &status);
572 if (U_FAILURE(status)) {
573 locname = nullptr;
574 } else {
575 // put the name info into the trie
576 GNameInfo* nameinfo = static_cast<ZNameInfo*>(uprv_malloc(sizeof(GNameInfo)));
577 if (nameinfo != nullptr) {
578 nameinfo->type = UTZGNM_LOCATION;
579 nameinfo->tzID = cacheID;
580 fGNamesTrie.put(locname, nameinfo, status);
581 }
582 }
583 }
584 }
585
586 return locname;
587}
588
589UnicodeString&
590TZGNCore::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
591 U_ASSERT(type == UTZGNM_LONG || type == UTZGNM_SHORT)(static_cast <bool> (type == UTZGNM_LONG || type == UTZGNM_SHORT
) ? void (0) : __assert_fail ("type == UTZGNM_LONG || type == UTZGNM_SHORT"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
592 name.setToBogus();
593
594 const char16_t* uID = ZoneMeta::getCanonicalCLDRID(tz);
595 if (uID == nullptr) {
596 return name;
597 }
598
599 UnicodeString tzID(true, uID, -1);
600
601 // Try to get a name from time zone first
602 UTimeZoneNameType nameType = (type == UTZGNM_LONG) ? UTZNM_LONG_GENERIC : UTZNM_SHORT_GENERIC;
603 fTimeZoneNames->getTimeZoneDisplayName(tzID, nameType, name);
604
605 if (!name.isEmpty()) {
606 return name;
607 }
608
609 // Try meta zone
610 char16_t mzIDBuf[32];
611 UnicodeString mzID(mzIDBuf, 0, UPRV_LENGTHOF(mzIDBuf)(int32_t)(sizeof(mzIDBuf)/sizeof((mzIDBuf)[0])));
612 fTimeZoneNames->getMetaZoneID(tzID, date, mzID);
613 if (!mzID.isEmpty()) {
614 UErrorCode status = U_ZERO_ERROR;
615 UBool useStandard = false;
616 int32_t raw, sav;
617 char16_t tmpNameBuf[ZONE_NAME_U16_MAX128];
618
619 tz.getOffset(date, false, raw, sav, status);
620 if (U_FAILURE(status)) {
621 return name;
622 }
623
624 if (sav == 0) {
625 useStandard = true;
626
627 TimeZone *tmptz = tz.clone();
628 // Check if the zone actually uses daylight saving time around the time
629 BasicTimeZone *btz = nullptr;
630 if (dynamic_cast<OlsonTimeZone *>(tmptz) != nullptr
631 || dynamic_cast<SimpleTimeZone *>(tmptz) != nullptr
632 || dynamic_cast<RuleBasedTimeZone *>(tmptz) != nullptr
633 || dynamic_cast<VTimeZone *>(tmptz) != nullptr) {
634 btz = (BasicTimeZone*)tmptz;
635 }
636
637 if (btz != nullptr) {
638 TimeZoneTransition before;
639 UBool beforTrs = btz->getPreviousTransition(date, true, before);
640 if (beforTrs
641 && (date - before.getTime() < kDstCheckRange)
642 && before.getFrom()->getDSTSavings() != 0) {
643 useStandard = false;
644 } else {
645 TimeZoneTransition after;
646 UBool afterTrs = btz->getNextTransition(date, false, after);
647 if (afterTrs
648 && (after.getTime() - date < kDstCheckRange)
649 && after.getTo()->getDSTSavings() != 0) {
650 useStandard = false;
651 }
652 }
653 } else {
654 // If not BasicTimeZone... only if the instance is not an ICU's implementation.
655 // We may get a wrong answer in edge case, but it should practically work OK.
656 tmptz->getOffset(date - kDstCheckRange, false, raw, sav, status);
657 if (sav != 0) {
658 useStandard = false;
659 } else {
660 tmptz->getOffset(date + kDstCheckRange, false, raw, sav, status);
661 if (sav != 0){
662 useStandard = false;
663 }
664 }
665 if (U_FAILURE(status)) {
666 delete tmptz;
667 return name;
668 }
669 }
670 delete tmptz;
671 }
672 if (useStandard) {
673 UTimeZoneNameType stdNameType = (nameType == UTZNM_LONG_GENERIC)
674 ? UTZNM_LONG_STANDARD : UTZNM_SHORT_STANDARD;
675 UnicodeString stdName(tmpNameBuf, 0, UPRV_LENGTHOF(tmpNameBuf)(int32_t)(sizeof(tmpNameBuf)/sizeof((tmpNameBuf)[0])));
676 fTimeZoneNames->getDisplayName(tzID, stdNameType, date, stdName);
677 if (!stdName.isEmpty()) {
678 name.setTo(stdName);
679
680 // TODO: revisit this issue later
681 // In CLDR, a same display name is used for both generic and standard
682 // for some meta zones in some locales. This looks like a data bugs.
683 // For now, we check if the standard name is different from its generic
684 // name below.
685 char16_t genNameBuf[ZONE_NAME_U16_MAX128];
686 UnicodeString mzGenericName(genNameBuf, 0, UPRV_LENGTHOF(genNameBuf)(int32_t)(sizeof(genNameBuf)/sizeof((genNameBuf)[0])));
687 fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzGenericName);
688 if (stdName.caseCompare(mzGenericName, 0) == 0) {
689 name.setToBogus();
690 }
691 }
692 }
693 if (name.isEmpty()) {
694 // Get a name from meta zone
695 UnicodeString mzName(tmpNameBuf, 0, UPRV_LENGTHOF(tmpNameBuf)(int32_t)(sizeof(tmpNameBuf)/sizeof((tmpNameBuf)[0])));
696 fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzName);
697 if (!mzName.isEmpty()) {
698 // Check if we need to use a partial location format.
699 // This check is done by comparing offset with the meta zone's
700 // golden zone at the given date.
701 char16_t idBuf[32];
702 UnicodeString goldenID(idBuf, 0, UPRV_LENGTHOF(idBuf)(int32_t)(sizeof(idBuf)/sizeof((idBuf)[0])));
703 fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion.data(), goldenID);
704 if (!goldenID.isEmpty() && goldenID != tzID) {
705 TimeZone *goldenZone = TimeZone::createTimeZone(goldenID);
706 int32_t raw1, sav1;
707
708 // Check offset in the golden zone with wall time.
709 // With getOffset(date, false, offsets1),
710 // you may get incorrect results because of time overlap at DST->STD
711 // transition.
712 goldenZone->getOffset(date + raw + sav, true, raw1, sav1, status);
713 delete goldenZone;
714 if (U_SUCCESS(status)) {
715 if (raw != raw1 || sav != sav1) {
716 // Now we need to use a partial location format
717 getPartialLocationName(tzID, mzID, (nameType == UTZNM_LONG_GENERIC), mzName, name);
718 } else {
719 name.setTo(mzName);
720 }
721 }
722 } else {
723 name.setTo(mzName);
724 }
725 }
726 }
727 }
728 return name;
729}
730
731UnicodeString&
732TZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID,
733 const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
734 UnicodeString& name) const {
735 name.setToBogus();
736 if (tzCanonicalID.isEmpty() || mzID.isEmpty() || mzDisplayName.isEmpty()) {
737 return name;
738 }
739
740 const char16_t *uplname = nullptr;
741 TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
742 umtx_lock(&gLock);
743 {
744 uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName);
745 }
746 umtx_unlock(&gLock);
747
748 if (uplname == nullptr) {
749 name.setToBogus();
750 } else {
751 name.setTo(true, uplname, -1);
752 }
753 return name;
754}
755
756/*
757 * This method updates the cache and must be called with a lock
758 */
759const char16_t*
760TZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID,
761 const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName) {
762 U_ASSERT(!tzCanonicalID.isEmpty())(static_cast <bool> (!tzCanonicalID.isEmpty()) ? void (
0) : __assert_fail ("!tzCanonicalID.isEmpty()", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
763 U_ASSERT(!mzID.isEmpty())(static_cast <bool> (!mzID.isEmpty()) ? void (0) : __assert_fail
("!mzID.isEmpty()", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
764 U_ASSERT(!mzDisplayName.isEmpty())(static_cast <bool> (!mzDisplayName.isEmpty()) ? void (
0) : __assert_fail ("!mzDisplayName.isEmpty()", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
765
766 PartialLocationKey key;
767 key.tzID = ZoneMeta::findTimeZoneID(tzCanonicalID);
768 key.mzID = ZoneMeta::findMetaZoneID(mzID);
769 key.isLong = isLong;
770 U_ASSERT(key.tzID != nullptr && key.mzID != nullptr)(static_cast <bool> (key.tzID != nullptr && key
.mzID != nullptr) ? void (0) : __assert_fail ("key.tzID != nullptr && key.mzID != nullptr"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
771
772 const char16_t* uplname = static_cast<const char16_t*>(uhash_get(fPartialLocationNamesMap, &key));
773 if (uplname != nullptr) {
774 return uplname;
775 }
776
777 UnicodeString location;
778 UnicodeString usCountryCode;
779 ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode);
780 if (!usCountryCode.isEmpty()) {
781 char countryCode[ULOC_COUNTRY_CAPACITY4];
782 U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY)(static_cast <bool> (usCountryCode.length() < 4) ? void
(0) : __assert_fail ("usCountryCode.length() < 4", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
783 int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INVicu::UnicodeString::kInvariant);
784 countryCode[ccLen] = 0;
785
786 UnicodeString regionalGolden;
787 fTimeZoneNames->getReferenceZoneID(mzID, countryCode, regionalGolden);
788 if (tzCanonicalID == regionalGolden) {
789 // Use country name
790 fLocaleDisplayNames->regionDisplayName(countryCode, location);
791 } else {
792 // Otherwise, use exemplar city name
793 fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location);
794 }
795 } else {
796 fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location);
797 if (location.isEmpty()) {
798 // This could happen when the time zone is not associated with a country,
799 // and its ID is not hierarchical, for example, CST6CDT.
800 // We use the canonical ID itself as the location for this case.
801 location.setTo(tzCanonicalID);
802 }
803 }
804
805 UErrorCode status = U_ZERO_ERROR;
806 UnicodeString name;
807 fFallbackFormat.format(location, mzDisplayName, name, status);
808 if (U_FAILURE(status)) {
809 return nullptr;
810 }
811
812 uplname = fStringPool.get(name, status);
813 if (U_SUCCESS(status)) {
814 // Add the name to cache
815 PartialLocationKey* cacheKey = static_cast<PartialLocationKey*>(uprv_malloc(sizeof(PartialLocationKey)));
816 if (cacheKey != nullptr) {
817 cacheKey->tzID = key.tzID;
818 cacheKey->mzID = key.mzID;
819 cacheKey->isLong = key.isLong;
820 uhash_put(fPartialLocationNamesMap, (void *)cacheKey, (void *)uplname, &status);
821 if (U_FAILURE(status)) {
822 uprv_free(cacheKey);
823 } else {
824 // put the name to the local trie as well
825 GNameInfo* nameinfo = static_cast<ZNameInfo*>(uprv_malloc(sizeof(GNameInfo)));
826 if (nameinfo != nullptr) {
827 nameinfo->type = isLong ? UTZGNM_LONG : UTZGNM_SHORT;
828 nameinfo->tzID = key.tzID;
829 fGNamesTrie.put(uplname, nameinfo, status);
830 }
831 }
832 }
833 }
834 return uplname;
835}
836
837/*
838 * This method updates the cache and must be called with a lock,
839 * except initializer.
840 */
841void
842TZGNCore::loadStrings(const UnicodeString& tzCanonicalID) {
843 // load the generic location name
844 getGenericLocationName(tzCanonicalID);
845
846 // partial location names
847 UErrorCode status = U_ZERO_ERROR;
848
849 const UnicodeString *mzID;
850 UnicodeString goldenID;
851 UnicodeString mzGenName;
852 UTimeZoneNameType genNonLocTypes[] = {
853 UTZNM_LONG_GENERIC, UTZNM_SHORT_GENERIC,
854 UTZNM_UNKNOWN /*terminator*/
855 };
856
857 StringEnumeration *mzIDs = fTimeZoneNames->getAvailableMetaZoneIDs(tzCanonicalID, status);
858 while ((mzID = mzIDs->snext(status)) != nullptr) {
859 if (U_FAILURE(status)) {
860 break;
861 }
862 // if this time zone is not the golden zone of the meta zone,
863 // partial location name (such as "PT (Los Angeles)") might be
864 // available.
865 fTimeZoneNames->getReferenceZoneID(*mzID, fTargetRegion.data(), goldenID);
866 if (tzCanonicalID != goldenID) {
867 for (int32_t i = 0; genNonLocTypes[i] != UTZNM_UNKNOWN; i++) {
868 fTimeZoneNames->getMetaZoneDisplayName(*mzID, genNonLocTypes[i], mzGenName);
869 if (!mzGenName.isEmpty()) {
870 // getPartialLocationName formats a name and put it into the trie
871 getPartialLocationName(tzCanonicalID, *mzID,
872 (genNonLocTypes[i] == UTZNM_LONG_GENERIC), mzGenName);
873 }
874 }
875 }
876 }
877 delete mzIDs;
878}
879
880int32_t
881TZGNCore::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
882 UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const {
883 timeType = UTZFMT_TIME_TYPE_UNKNOWN;
884 tzID.setToBogus();
885
886 if (U_FAILURE(status)) {
887 return 0;
888 }
889
890 // Find matches in the TimeZoneNames first
891 TimeZoneNames::MatchInfoCollection *tznamesMatches = findTimeZoneNames(text, start, types, status);
892 if (U_FAILURE(status)) {
893 return 0;
894 }
895
896 int32_t bestMatchLen = 0;
897 UTimeZoneFormatTimeType bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
898 UnicodeString bestMatchTzID;
899 // UBool isLongStandard = false; // workaround - see the comments below
900 UBool isStandard = false; // TODO: Temporary hack (on hack) for short standard name/location name conflict (found in zh_Hant), should be removed after CLDR 21m1 integration
901
902 if (tznamesMatches != nullptr) {
903 UnicodeString mzID;
904 for (int32_t i = 0; i < tznamesMatches->size(); i++) {
905 int32_t len = tznamesMatches->getMatchLengthAt(i);
906 if (len > bestMatchLen) {
907 bestMatchLen = len;
908 if (!tznamesMatches->getTimeZoneIDAt(i, bestMatchTzID)) {
909 // name for a meta zone
910 if (tznamesMatches->getMetaZoneIDAt(i, mzID)) {
911 fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion.data(), bestMatchTzID);
912 }
913 }
914 UTimeZoneNameType nameType = tznamesMatches->getNameTypeAt(i);
915 if (U_FAILURE(status)) {
916 break;
917 }
918 switch (nameType) {
919 case UTZNM_LONG_STANDARD:
920 // isLongStandard = true;
921 case UTZNM_SHORT_STANDARD: // this one is never used for generic, but just in case
922 isStandard = true; // TODO: Remove this later, see the comments above.
923 bestMatchTimeType = UTZFMT_TIME_TYPE_STANDARD;
924 break;
925 case UTZNM_LONG_DAYLIGHT:
926 case UTZNM_SHORT_DAYLIGHT: // this one is never used for generic, but just in case
927 bestMatchTimeType = UTZFMT_TIME_TYPE_DAYLIGHT;
928 break;
929 default:
930 bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
931 }
932 }
933 }
934 delete tznamesMatches;
935 if (U_FAILURE(status)) {
936 return 0;
937 }
938
939 if (bestMatchLen == (text.length() - start)) {
940 // Full match
941
942 //tzID.setTo(bestMatchTzID);
943 //timeType = bestMatchTimeType;
944 //return bestMatchLen;
945
946 // TODO Some time zone uses a same name for the long standard name
947 // and the location name. When the match is a long standard name,
948 // then we need to check if the name is same with the location name.
949 // This is probably a data error or a design bug.
950/*
951 if (!isLongStandard) {
952 tzID.setTo(bestMatchTzID);
953 timeType = bestMatchTimeType;
954 return bestMatchLen;
955 }
956*/
957 // TODO The deprecation of commonlyUsed flag introduced the name
958 // conflict not only for long standard names, but short standard names too.
959 // These short names (found in zh_Hant) should be gone once we clean
960 // up CLDR time zone display name data. Once the short name conflict
961 // problem (with location name) is resolved, we should change the condition
962 // below back to the original one above. -Yoshito (2011-09-14)
963 if (!isStandard) {
964 tzID.setTo(bestMatchTzID);
965 timeType = bestMatchTimeType;
966 return bestMatchLen;
967 }
968 }
969 }
970
971 // Find matches in the local trie
972 TimeZoneGenericNameMatchInfo *localMatches = findLocal(text, start, types, status);
973 if (U_FAILURE(status)) {
974 return 0;
975 }
976 if (localMatches != nullptr) {
977 for (int32_t i = 0; i < localMatches->size(); i++) {
978 int32_t len = localMatches->getMatchLength(i);
979
980 // TODO See the above TODO. We use len >= bestMatchLen
981 // because of the long standard/location name collision
982 // problem. If it is also a location name, carrying
983 // timeType = UTZFMT_TIME_TYPE_STANDARD will cause a
984 // problem in SimpleDateFormat
985 if (len >= bestMatchLen) {
986 bestMatchLen = localMatches->getMatchLength(i);
987 bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN; // because generic
988 localMatches->getTimeZoneID(i, bestMatchTzID);
989 }
990 }
991 delete localMatches;
992 }
993
994 if (bestMatchLen > 0) {
995 timeType = bestMatchTimeType;
996 tzID.setTo(bestMatchTzID);
997 }
998 return bestMatchLen;
999}
1000
1001TimeZoneGenericNameMatchInfo*
1002TZGNCore::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
1003 GNameSearchHandler handler(types);
1004
1005 TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
1006
1007 umtx_lock(&gLock);
1008 {
1009 fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
1010 }
1011 umtx_unlock(&gLock);
1012
1013 if (U_FAILURE(status)) {
1014 return nullptr;
1015 }
1016
1017 TimeZoneGenericNameMatchInfo *gmatchInfo = nullptr;
1018
1019 int32_t maxLen = 0;
1020 UVector *results = handler.getMatches(maxLen);
1021 if (results != nullptr && ((maxLen == (text.length() - start)) || fGNamesTrieFullyLoaded)) {
1022 // perfect match
1023 gmatchInfo = new TimeZoneGenericNameMatchInfo(results);
1024 if (gmatchInfo == nullptr) {
1025 status = U_MEMORY_ALLOCATION_ERROR;
1026 delete results;
1027 return nullptr;
1028 }
1029 return gmatchInfo;
1030 }
1031
1032 delete results;
1033
1034 // All names are not yet loaded into the local trie.
1035 // Load all available names into the trie. This could be very heavy.
1036 umtx_lock(&gLock);
1037 {
1038 if (!fGNamesTrieFullyLoaded) {
1039 StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, nullptr, nullptr, status);
1040 if (U_SUCCESS(status)) {
1041 const UnicodeString *tzID;
1042 while ((tzID = tzIDs->snext(status)) != nullptr) {
1043 if (U_FAILURE(status)) {
1044 break;
1045 }
1046 nonConstThis->loadStrings(*tzID);
1047 }
1048 }
1049 delete tzIDs;
1050
1051 if (U_SUCCESS(status)) {
1052 nonConstThis->fGNamesTrieFullyLoaded = true;
1053 }
1054 }
1055 }
1056 umtx_unlock(&gLock);
1057
1058 if (U_FAILURE(status)) {
1059 return nullptr;
1060 }
1061
1062 umtx_lock(&gLock);
1063 {
1064 // now try it again
1065 fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
1066 }
1067 umtx_unlock(&gLock);
1068
1069 results = handler.getMatches(maxLen);
1070 if (results != nullptr && maxLen > 0) {
1071 gmatchInfo = new TimeZoneGenericNameMatchInfo(results);
1072 if (gmatchInfo == nullptr) {
1073 status = U_MEMORY_ALLOCATION_ERROR;
1074 delete results;
1075 return nullptr;
1076 }
1077 }
1078
1079 return gmatchInfo;
1080}
1081
1082TimeZoneNames::MatchInfoCollection*
1083TZGNCore::findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
1084 // Check if the target name typs is really in the TimeZoneNames
1085 uint32_t nameTypes = 0;
1086 if (types & UTZGNM_LONG) {
1087 nameTypes |= (UTZNM_LONG_GENERIC | UTZNM_LONG_STANDARD);
1088 }
1089 if (types & UTZGNM_SHORT) {
1090 nameTypes |= (UTZNM_SHORT_GENERIC | UTZNM_SHORT_STANDARD);
1091 }
1092
1093 if (types) {
1094 // Find matches in the TimeZoneNames
1095 return fTimeZoneNames->find(text, start, nameTypes, status);
1096 }
1097
1098 return nullptr;
1099}
1100
1101typedef struct TZGNCoreRef {
1102 TZGNCore* obj;
1103 int32_t refCount;
1104 double lastAccess;
1105} TZGNCoreRef;
1106
1107// TZGNCore object cache handling
1108static UMutex gTZGNLock;
1109static UHashtable *gTZGNCoreCache = nullptr;
1110static UBool gTZGNCoreCacheInitialized = false;
1111
1112// Access count - incremented every time up to SWEEP_INTERVAL,
1113// then reset to 0
1114static int32_t gAccessCount = 0;
1115
1116// Interval for calling the cache sweep function - every 100 times
1117#define SWEEP_INTERVAL100 100
1118
1119// Cache expiration in millisecond. When a cached entry is no
1120// longer referenced and exceeding this threshold since last
1121// access time, then the cache entry will be deleted by the sweep
1122// function. For now, 3 minutes.
1123#define CACHE_EXPIRATION180000.0 180000.0
1124
1125U_CDECL_BEGINextern "C" {
1126/**
1127 * Cleanup callback func
1128 */
1129static UBool U_CALLCONV tzgnCore_cleanup()
1130{
1131 if (gTZGNCoreCache != nullptr) {
1132 uhash_close(gTZGNCoreCache);
1133 gTZGNCoreCache = nullptr;
1134 }
1135 gTZGNCoreCacheInitialized = false;
1136 return true;
1137}
1138
1139/**
1140 * Deleter for TZGNCoreRef
1141 */
1142static void U_CALLCONV
1143deleteTZGNCoreRef(void *obj) {
1144 icu::TZGNCoreRef *entry = (icu::TZGNCoreRef*)obj;
1145 delete (icu::TZGNCore*) entry->obj;
1146 uprv_free(entry);
1147}
1148U_CDECL_END}
1149
1150/**
1151 * Function used for removing unreferrenced cache entries exceeding
1152 * the expiration time. This function must be called with in the mutex
1153 * block.
1154 */
1155static void sweepCache() {
1156 int32_t pos = UHASH_FIRST(-1);
1157 const UHashElement* elem;
1158 double now = static_cast<double>(uprv_getUTCtime());
1159
1160 while ((elem = uhash_nextElement(gTZGNCoreCache, &pos)) != nullptr) {
1161 TZGNCoreRef* entry = static_cast<TZGNCoreRef*>(elem->value.pointer);
1162 if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION180000.0) {
1163 // delete this entry
1164 uhash_removeElement(gTZGNCoreCache, elem);
1165 }
1166 }
1167}
1168
1169TimeZoneGenericNames::TimeZoneGenericNames()
1170: fRef(nullptr) {
3
Null pointer value stored to field 'fRef'
1171}
1172
1173TimeZoneGenericNames::~TimeZoneGenericNames() {
1174 umtx_lock(&gTZGNLock);
1175 {
1176 U_ASSERT(fRef->refCount > 0)(static_cast <bool> (fRef->refCount > 0) ? void (
0) : __assert_fail ("fRef->refCount > 0", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
17
Access to field 'refCount' results in a dereference of a null pointer (loaded from field 'fRef')
1177 // Just decrement the reference count
1178 fRef->refCount--;
1179 }
1180 umtx_unlock(&gTZGNLock);
1181}
1182
1183TimeZoneGenericNames*
1184TimeZoneGenericNames::createInstance(const Locale& locale, UErrorCode& status) {
1185 if (U_FAILURE(status)) {
1
Taking false branch
1186 return nullptr;
1187 }
1188 LocalPointer<TimeZoneGenericNames> instance(new TimeZoneGenericNames(), status);
2
Calling default constructor for 'TimeZoneGenericNames'
4
Returning from default constructor for 'TimeZoneGenericNames'
5
Calling constructor for 'LocalPointer<icu_78::TimeZoneGenericNames>'
9
Returning from constructor for 'LocalPointer<icu_78::TimeZoneGenericNames>'
1189 if (U_FAILURE(status)) {
10
Taking false branch
1190 return nullptr;
1191 }
1192
1193 TZGNCoreRef *cacheEntry = nullptr;
1194 {
1195 Mutex lock(&gTZGNLock);
1196
1197 if (!gTZGNCoreCacheInitialized) {
11
Assuming 'gTZGNCoreCacheInitialized' is 0
12
Taking true branch
1198 // Create empty hashtable
1199 gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, nullptr, &status);
1200 if (U_SUCCESS(status)) {
13
Taking false branch
1201 uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
1202 uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
1203 gTZGNCoreCacheInitialized = true;
1204 ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
1205 }
1206 }
1207 if (U_FAILURE(status)) {
14
Taking true branch
1208 return nullptr;
15
Calling '~LocalPointer'
1209 }
1210
1211 // Check the cache, if not available, create new one and cache
1212 const char *key = locale.getName();
1213 cacheEntry = static_cast<TZGNCoreRef*>(uhash_get(gTZGNCoreCache, key));
1214 if (cacheEntry == nullptr) {
1215 TZGNCore *tzgnCore = nullptr;
1216 char *newKey = nullptr;
1217
1218 tzgnCore = new TZGNCore(locale, status);
1219 if (tzgnCore == nullptr) {
1220 status = U_MEMORY_ALLOCATION_ERROR;
1221 }
1222 if (U_SUCCESS(status)) {
1223 newKey = static_cast<char*>(uprv_malloc(uprv_strlen(key):: strlen(key) + 1));
1224 if (newKey == nullptr) {
1225 status = U_MEMORY_ALLOCATION_ERROR;
1226 } else {
1227 uprv_strcpy(newKey, key):: strcpy(newKey, key);
1228 }
1229 }
1230 if (U_SUCCESS(status)) {
1231 cacheEntry = static_cast<TZGNCoreRef*>(uprv_malloc(sizeof(TZGNCoreRef)));
1232 if (cacheEntry == nullptr) {
1233 status = U_MEMORY_ALLOCATION_ERROR;
1234 } else {
1235 cacheEntry->obj = tzgnCore;
1236 cacheEntry->refCount = 1;
1237 cacheEntry->lastAccess = static_cast<double>(uprv_getUTCtime());
1238
1239 uhash_put(gTZGNCoreCache, newKey, cacheEntry, &status);
1240 }
1241 }
1242 if (U_FAILURE(status)) {
1243 delete tzgnCore;
1244 if (newKey != nullptr) {
1245 uprv_free(newKey);
1246 }
1247 if (cacheEntry != nullptr) {
1248 uprv_free(cacheEntry);
1249 }
1250 cacheEntry = nullptr;
1251 }
1252 } else {
1253 // Update the reference count
1254 cacheEntry->refCount++;
1255 cacheEntry->lastAccess = static_cast<double>(uprv_getUTCtime());
1256 }
1257 gAccessCount++;
1258 if (gAccessCount >= SWEEP_INTERVAL100) {
1259 // sweep
1260 sweepCache();
1261 gAccessCount = 0;
1262 }
1263 } // End of mutex locked block
1264
1265 if (cacheEntry == nullptr) {
1266 return nullptr;
1267 }
1268
1269 instance->fRef = cacheEntry;
1270 return instance.orphan();
1271}
1272
1273bool
1274TimeZoneGenericNames::operator==(const TimeZoneGenericNames& other) const {
1275 // Just compare if the other object also use the same
1276 // ref entry
1277 return fRef == other.fRef;
1278}
1279
1280TimeZoneGenericNames*
1281TimeZoneGenericNames::clone() const {
1282 TimeZoneGenericNames* other = new TimeZoneGenericNames();
1283 if (other) {
1284 umtx_lock(&gTZGNLock);
1285 {
1286 // Just increments the reference count
1287 fRef->refCount++;
1288 other->fRef = fRef;
1289 }
1290 umtx_unlock(&gTZGNLock);
1291 }
1292 return other;
1293}
1294
1295UnicodeString&
1296TimeZoneGenericNames::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
1297 UDate date, UnicodeString& name) const {
1298 return fRef->obj->getDisplayName(tz, type, date, name);
1299}
1300
1301UnicodeString&
1302TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
1303 return fRef->obj->getGenericLocationName(tzCanonicalID, name);
1304}
1305
1306int32_t
1307TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
1308 UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const {
1309 return fRef->obj->findBestMatch(text, start, types, tzID, timeType, status);
1310}
1311
1312U_NAMESPACE_END}
1313#endif

/root/firefox-clang/intl/icu/source/common/unicode/localpointer.h

1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5*
6* Copyright (C) 2009-2016, International Business Machines
7* Corporation and others. All Rights Reserved.
8*
9*******************************************************************************
10* file name: localpointer.h
11* encoding: UTF-8
12* tab size: 8 (not used)
13* indentation:4
14*
15* created on: 2009nov13
16* created by: Markus W. Scherer
17*/
18
19#ifndef __LOCALPOINTER_H__
20#define __LOCALPOINTER_H__
21
22/**
23 * \file
24 * \brief C++ API: "Smart pointers" for use with and in ICU4C C++ code.
25 *
26 * These classes are inspired by
27 * - std::auto_ptr
28 * - boost::scoped_ptr & boost::scoped_array
29 * - Taligent Safe Pointers (TOnlyPointerTo)
30 *
31 * but none of those provide for all of the goals for ICU smart pointers:
32 * - Smart pointer owns the object and releases it when it goes out of scope.
33 * - No transfer of ownership via copy/assignment to reduce misuse. Simpler & more robust.
34 * - ICU-compatible: No exceptions.
35 * - Need to be able to orphan/release the pointer and its ownership.
36 * - Need variants for normal C++ object pointers, C++ arrays, and ICU C service objects.
37 *
38 * For details see https://icu.unicode.org/design/cpp/scoped_ptr
39 */
40
41#include "unicode/utypes.h"
42
43#if U_SHOW_CPLUSPLUS_API1
44
45#include <memory>
46
47U_NAMESPACE_BEGINnamespace icu_78 {
48
49/**
50 * "Smart pointer" base class; do not use directly: use LocalPointer etc.
51 *
52 * Base class for smart pointer classes that do not throw exceptions.
53 *
54 * Do not use this base class directly, since it does not delete its pointer.
55 * A subclass must implement methods that delete the pointer:
56 * Destructor and adoptInstead().
57 *
58 * There is no operator T *() provided because the programmer must decide
59 * whether to use getAlias() (without transfer of ownership) or orphan()
60 * (with transfer of ownership and NULLing of the pointer).
61 *
62 * @see LocalPointer
63 * @see LocalArray
64 * @see U_DEFINE_LOCAL_OPEN_POINTER
65 * @stable ICU 4.4
66 */
67template<typename T>
68class LocalPointerBase {
69public:
70 // No heap allocation. Use only on the stack.
71 static void* U_EXPORT2 operator new(size_t) = delete;
72 static void* U_EXPORT2 operator new[](size_t) = delete;
73 static void* U_EXPORT2 operator new(size_t, void*) = delete;
74
75 /**
76 * Constructor takes ownership.
77 * @param p simple pointer to an object that is adopted
78 * @stable ICU 4.4
79 */
80 explicit LocalPointerBase(T *p=nullptr) : ptr(p) {}
81 /**
82 * Destructor deletes the object it owns.
83 * Subclass must override: Base class does nothing.
84 * @stable ICU 4.4
85 */
86 ~LocalPointerBase() { /* delete ptr; */ }
87 /**
88 * nullptr check.
89 * @return true if ==nullptr
90 * @stable ICU 4.4
91 */
92 UBool isNull() const { return ptr==nullptr; }
93 /**
94 * nullptr check.
95 * @return true if !=nullptr
96 * @stable ICU 4.4
97 */
98 UBool isValid() const { return ptr!=nullptr; }
99 /**
100 * Comparison with a simple pointer, so that existing code
101 * with ==nullptr need not be changed.
102 * @param other simple pointer for comparison
103 * @return true if this pointer value equals other
104 * @stable ICU 4.4
105 */
106 bool operator==(const T *other) const { return ptr==other; }
107 /**
108 * Comparison with a simple pointer, so that existing code
109 * with !=nullptr need not be changed.
110 * @param other simple pointer for comparison
111 * @return true if this pointer value differs from other
112 * @stable ICU 4.4
113 */
114 bool operator!=(const T *other) const { return ptr!=other; }
115 /**
116 * Access without ownership change.
117 * @return the pointer value
118 * @stable ICU 4.4
119 */
120 T *getAlias() const { return ptr; }
121 /**
122 * Access without ownership change.
123 * @return the pointer value as a reference
124 * @stable ICU 4.4
125 */
126 T &operator*() const { return *ptr; }
127 /**
128 * Access without ownership change.
129 * @return the pointer value
130 * @stable ICU 4.4
131 */
132 T *operator->() const { return ptr; }
133 /**
134 * Gives up ownership; the internal pointer becomes nullptr.
135 * @return the pointer value;
136 * caller becomes responsible for deleting the object
137 * @stable ICU 4.4
138 */
139 T *orphan() {
140 T *p=ptr;
141 ptr=nullptr;
142 return p;
143 }
144 /**
145 * Deletes the object it owns,
146 * and adopts (takes ownership of) the one passed in.
147 * Subclass must override: Base class does not delete the object.
148 * @param p simple pointer to an object that is adopted
149 * @stable ICU 4.4
150 */
151 void adoptInstead(T *p) {
152 // delete ptr;
153 ptr=p;
154 }
155protected:
156 /**
157 * Actual pointer.
158 * @internal
159 */
160 T *ptr;
161private:
162 // No comparison operators with other LocalPointerBases.
163 bool operator==(const LocalPointerBase<T> &other) = delete;
164 bool operator!=(const LocalPointerBase<T> &other) = delete;
165 // No ownership sharing: No copy constructor, no assignment operator.
166 LocalPointerBase(const LocalPointerBase<T> &other) = delete;
167 void operator=(const LocalPointerBase<T> &other) = delete;
168};
169
170/**
171 * "Smart pointer" class, deletes objects via the standard C++ delete operator.
172 * For most methods see the LocalPointerBase base class.
173 *
174 * Usage example:
175 * \code
176 * LocalPointer<UnicodeString> s(new UnicodeString((UChar32)0x50005));
177 * int32_t length=s->length(); // 2
178 * char16_t lead=s->charAt(0); // 0xd900
179 * if(some condition) { return; } // no need to explicitly delete the pointer
180 * s.adoptInstead(new UnicodeString((char16_t)0xfffc));
181 * length=s->length(); // 1
182 * // no need to explicitly delete the pointer
183 * \endcode
184 *
185 * @see LocalPointerBase
186 * @stable ICU 4.4
187 */
188template<typename T>
189class LocalPointer : public LocalPointerBase<T> {
190public:
191 using LocalPointerBase<T>::operator*;
192 using LocalPointerBase<T>::operator->;
193 /**
194 * Constructor takes ownership.
195 * @param p simple pointer to an object that is adopted
196 * @stable ICU 4.4
197 */
198 explicit LocalPointer(T *p=nullptr) : LocalPointerBase<T>(p) {}
199 /**
200 * Constructor takes ownership and reports an error if nullptr.
201 *
202 * This constructor is intended to be used with other-class constructors
203 * that may report a failure UErrorCode,
204 * so that callers need to check only for U_FAILURE(errorCode)
205 * and not also separately for isNull().
206 *
207 * @param p simple pointer to an object that is adopted
208 * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
209 * if p==nullptr and no other failure code had been set
210 * @stable ICU 55
211 */
212 LocalPointer(T *p, UErrorCode &errorCode) : LocalPointerBase<T>(p) {
6
Calling default constructor for 'LocalPointerBase<icu_78::TimeZoneGenericNames>'
7
Returning from default constructor for 'LocalPointerBase<icu_78::TimeZoneGenericNames>'
213 if(p==nullptr && U_SUCCESS(errorCode)) {
8
Assuming the condition is false
214 errorCode=U_MEMORY_ALLOCATION_ERROR;
215 }
216 }
217 /**
218 * Move constructor, leaves src with isNull().
219 * @param src source smart pointer
220 * @stable ICU 56
221 */
222 LocalPointer(LocalPointer<T> &&src) noexcept : LocalPointerBase<T>(src.ptr) {
223 src.ptr=nullptr;
224 }
225
226 /**
227 * Constructs a LocalPointer from a C++11 std::unique_ptr.
228 * The LocalPointer steals the object owned by the std::unique_ptr.
229 *
230 * This constructor works via move semantics. If your std::unique_ptr is
231 * in a local variable, you must use std::move.
232 *
233 * @param p The std::unique_ptr from which the pointer will be stolen.
234 * @stable ICU 64
235 */
236 explicit LocalPointer(std::unique_ptr<T> &&p)
237 : LocalPointerBase<T>(p.release()) {}
238
239 /**
240 * Destructor deletes the object it owns.
241 * @stable ICU 4.4
242 */
243 ~LocalPointer() {
244 delete LocalPointerBase<T>::ptr;
16
Calling '~TimeZoneGenericNames'
245 }
246 /**
247 * Move assignment operator, leaves src with isNull().
248 * The behavior is undefined if *this and src are the same object.
249 * @param src source smart pointer
250 * @return *this
251 * @stable ICU 56
252 */
253 LocalPointer<T> &operator=(LocalPointer<T> &&src) noexcept {
254 delete LocalPointerBase<T>::ptr;
255 LocalPointerBase<T>::ptr=src.ptr;
256 src.ptr=nullptr;
257 return *this;
258 }
259
260 /**
261 * Move-assign from an std::unique_ptr to this LocalPointer.
262 * Steals the pointer from the std::unique_ptr.
263 *
264 * @param p The std::unique_ptr from which the pointer will be stolen.
265 * @return *this
266 * @stable ICU 64
267 */
268 LocalPointer<T> &operator=(std::unique_ptr<T> &&p) noexcept {
269 adoptInstead(p.release());
270 return *this;
271 }
272
273 /**
274 * Swap pointers.
275 * @param other other smart pointer
276 * @stable ICU 56
277 */
278 void swap(LocalPointer<T> &other) noexcept {
279 T *temp=LocalPointerBase<T>::ptr;
280 LocalPointerBase<T>::ptr=other.ptr;
281 other.ptr=temp;
282 }
283 /**
284 * Non-member LocalPointer swap function.
285 * @param p1 will get p2's pointer
286 * @param p2 will get p1's pointer
287 * @stable ICU 56
288 */
289 friend inline void swap(LocalPointer<T> &p1, LocalPointer<T> &p2) noexcept {
290 p1.swap(p2);
291 }
292 /**
293 * Deletes the object it owns,
294 * and adopts (takes ownership of) the one passed in.
295 * @param p simple pointer to an object that is adopted
296 * @stable ICU 4.4
297 */
298 void adoptInstead(T *p) {
299 delete LocalPointerBase<T>::ptr;
300 LocalPointerBase<T>::ptr=p;
301 }
302 /**
303 * Deletes the object it owns,
304 * and adopts (takes ownership of) the one passed in.
305 *
306 * If U_FAILURE(errorCode), then the current object is retained and the new one deleted.
307 *
308 * If U_SUCCESS(errorCode) but the input pointer is nullptr,
309 * then U_MEMORY_ALLOCATION_ERROR is set,
310 * the current object is deleted, and nullptr is set.
311 *
312 * @param p simple pointer to an object that is adopted
313 * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
314 * if p==nullptr and no other failure code had been set
315 * @stable ICU 55
316 */
317 void adoptInsteadAndCheckErrorCode(T *p, UErrorCode &errorCode) {
318 if(U_SUCCESS(errorCode)) {
319 delete LocalPointerBase<T>::ptr;
320 LocalPointerBase<T>::ptr=p;
321 if(p==nullptr) {
322 errorCode=U_MEMORY_ALLOCATION_ERROR;
323 }
324 } else {
325 delete p;
326 }
327 }
328
329 /**
330 * Conversion operator to a C++11 std::unique_ptr.
331 * Disowns the object and gives it to the returned std::unique_ptr.
332 *
333 * This operator works via move semantics. If your LocalPointer is
334 * in a local variable, you must use std::move.
335 *
336 * @return An std::unique_ptr owning the pointer previously owned by this
337 * icu::LocalPointer.
338 * @stable ICU 64
339 */
340 operator std::unique_ptr<T> () && {
341 return std::unique_ptr<T>(LocalPointerBase<T>::orphan());
342 }
343};
344
345/**
346 * "Smart pointer" class, deletes objects via the C++ array delete[] operator.
347 * For most methods see the LocalPointerBase base class.
348 * Adds operator[] for array item access.
349 *
350 * Usage example:
351 * \code
352 * LocalArray<UnicodeString> a(new UnicodeString[2]);
353 * a[0].append((char16_t)0x61);
354 * if(some condition) { return; } // no need to explicitly delete the array
355 * a.adoptInstead(new UnicodeString[4]);
356 * a[3].append((char16_t)0x62).append((char16_t)0x63).reverse();
357 * // no need to explicitly delete the array
358 * \endcode
359 *
360 * @see LocalPointerBase
361 * @stable ICU 4.4
362 */
363template<typename T>
364class LocalArray : public LocalPointerBase<T> {
365public:
366 using LocalPointerBase<T>::operator*;
367 using LocalPointerBase<T>::operator->;
368 /**
369 * Constructor takes ownership.
370 * @param p simple pointer to an array of T objects that is adopted
371 * @stable ICU 4.4
372 */
373 explicit LocalArray(T *p=nullptr) : LocalPointerBase<T>(p) {}
374 /**
375 * Constructor takes ownership and reports an error if nullptr.
376 *
377 * This constructor is intended to be used with other-class constructors
378 * that may report a failure UErrorCode,
379 * so that callers need to check only for U_FAILURE(errorCode)
380 * and not also separately for isNull().
381 *
382 * @param p simple pointer to an array of T objects that is adopted
383 * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
384 * if p==nullptr and no other failure code had been set
385 * @stable ICU 56
386 */
387 LocalArray(T *p, UErrorCode &errorCode) : LocalPointerBase<T>(p) {
388 if(p==nullptr && U_SUCCESS(errorCode)) {
389 errorCode=U_MEMORY_ALLOCATION_ERROR;
390 }
391 }
392 /**
393 * Move constructor, leaves src with isNull().
394 * @param src source smart pointer
395 * @stable ICU 56
396 */
397 LocalArray(LocalArray<T> &&src) noexcept : LocalPointerBase<T>(src.ptr) {
398 src.ptr=nullptr;
399 }
400
401 /**
402 * Constructs a LocalArray from a C++11 std::unique_ptr of an array type.
403 * The LocalPointer steals the array owned by the std::unique_ptr.
404 *
405 * This constructor works via move semantics. If your std::unique_ptr is
406 * in a local variable, you must use std::move.
407 *
408 * @param p The std::unique_ptr from which the array will be stolen.
409 * @stable ICU 64
410 */
411 explicit LocalArray(std::unique_ptr<T[]> &&p)
412 : LocalPointerBase<T>(p.release()) {}
413
414 /**
415 * Destructor deletes the array it owns.
416 * @stable ICU 4.4
417 */
418 ~LocalArray() {
419 delete[] LocalPointerBase<T>::ptr;
420 }
421 /**
422 * Move assignment operator, leaves src with isNull().
423 * The behavior is undefined if *this and src are the same object.
424 * @param src source smart pointer
425 * @return *this
426 * @stable ICU 56
427 */
428 LocalArray<T> &operator=(LocalArray<T> &&src) noexcept {
429 delete[] LocalPointerBase<T>::ptr;
430 LocalPointerBase<T>::ptr=src.ptr;
431 src.ptr=nullptr;
432 return *this;
433 }
434
435 /**
436 * Move-assign from an std::unique_ptr to this LocalPointer.
437 * Steals the array from the std::unique_ptr.
438 *
439 * @param p The std::unique_ptr from which the array will be stolen.
440 * @return *this
441 * @stable ICU 64
442 */
443 LocalArray<T> &operator=(std::unique_ptr<T[]> &&p) noexcept {
444 adoptInstead(p.release());
445 return *this;
446 }
447
448 /**
449 * Swap pointers.
450 * @param other other smart pointer
451 * @stable ICU 56
452 */
453 void swap(LocalArray<T> &other) noexcept {
454 T *temp=LocalPointerBase<T>::ptr;
455 LocalPointerBase<T>::ptr=other.ptr;
456 other.ptr=temp;
457 }
458 /**
459 * Non-member LocalArray swap function.
460 * @param p1 will get p2's pointer
461 * @param p2 will get p1's pointer
462 * @stable ICU 56
463 */
464 friend inline void swap(LocalArray<T> &p1, LocalArray<T> &p2) noexcept {
465 p1.swap(p2);
466 }
467 /**
468 * Deletes the array it owns,
469 * and adopts (takes ownership of) the one passed in.
470 * @param p simple pointer to an array of T objects that is adopted
471 * @stable ICU 4.4
472 */
473 void adoptInstead(T *p) {
474 delete[] LocalPointerBase<T>::ptr;
475 LocalPointerBase<T>::ptr=p;
476 }
477 /**
478 * Deletes the array it owns,
479 * and adopts (takes ownership of) the one passed in.
480 *
481 * If U_FAILURE(errorCode), then the current array is retained and the new one deleted.
482 *
483 * If U_SUCCESS(errorCode) but the input pointer is nullptr,
484 * then U_MEMORY_ALLOCATION_ERROR is set,
485 * the current array is deleted, and nullptr is set.
486 *
487 * @param p simple pointer to an array of T objects that is adopted
488 * @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
489 * if p==nullptr and no other failure code had been set
490 * @stable ICU 56
491 */
492 void adoptInsteadAndCheckErrorCode(T *p, UErrorCode &errorCode) {
493 if(U_SUCCESS(errorCode)) {
494 delete[] LocalPointerBase<T>::ptr;
495 LocalPointerBase<T>::ptr=p;
496 if(p==nullptr) {
497 errorCode=U_MEMORY_ALLOCATION_ERROR;
498 }
499 } else {
500 delete[] p;
501 }
502 }
503 /**
504 * Array item access (writable).
505 * No index bounds check.
506 * @param i array index
507 * @return reference to the array item
508 * @stable ICU 4.4
509 */
510 T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
511
512 /**
513 * Conversion operator to a C++11 std::unique_ptr.
514 * Disowns the object and gives it to the returned std::unique_ptr.
515 *
516 * This operator works via move semantics. If your LocalPointer is
517 * in a local variable, you must use std::move.
518 *
519 * @return An std::unique_ptr owning the pointer previously owned by this
520 * icu::LocalPointer.
521 * @stable ICU 64
522 */
523 operator std::unique_ptr<T[]> () && {
524 return std::unique_ptr<T[]>(LocalPointerBase<T>::orphan());
525 }
526};
527
528/**
529 * \def U_DEFINE_LOCAL_OPEN_POINTER
530 * "Smart pointer" definition macro, deletes objects via the closeFunction.
531 * Defines a subclass of LocalPointerBase which works just
532 * like LocalPointer<Type> except that this subclass will use the closeFunction
533 * rather than the C++ delete operator.
534 *
535 * Usage example:
536 * \code
537 * LocalUCaseMapPointer csm(ucasemap_open(localeID, options, &errorCode));
538 * utf8OutLength=ucasemap_utf8ToLower(csm.getAlias(),
539 * utf8Out, (int32_t)sizeof(utf8Out),
540 * utf8In, utf8InLength, &errorCode);
541 * if(U_FAILURE(errorCode)) { return; } // no need to explicitly delete the UCaseMap
542 * \endcode
543 *
544 * @see LocalPointerBase
545 * @see LocalPointer
546 * @stable ICU 4.4
547 */
548#define U_DEFINE_LOCAL_OPEN_POINTER(LocalPointerClassName, Type, closeFunction)using LocalPointerClassName = internal::LocalOpenPointer<Type
, closeFunction>
\
549 using LocalPointerClassName = internal::LocalOpenPointer<Type, closeFunction>
550
551#ifndef U_IN_DOXYGEN
552namespace internal {
553/**
554 * Implementation, do not use directly: use U_DEFINE_LOCAL_OPEN_POINTER.
555 *
556 * @see U_DEFINE_LOCAL_OPEN_POINTER
557 * @internal
558 */
559template <typename Type, auto closeFunction>
560class LocalOpenPointer : public LocalPointerBase<Type> {
561 using LocalPointerBase<Type>::ptr;
562public:
563 using LocalPointerBase<Type>::operator*;
564 using LocalPointerBase<Type>::operator->;
565 explicit LocalOpenPointer(Type *p=nullptr) : LocalPointerBase<Type>(p) {}
566 LocalOpenPointer(LocalOpenPointer &&src) noexcept
567 : LocalPointerBase<Type>(src.ptr) {
568 src.ptr=nullptr;
569 }
570 /* TODO: Be agnostic of the deleter function signature from the user-provided std::unique_ptr? */
571 explicit LocalOpenPointer(std::unique_ptr<Type, decltype(closeFunction)> &&p)
572 : LocalPointerBase<Type>(p.release()) {}
573 ~LocalOpenPointer() { if (ptr != nullptr) { closeFunction(ptr); } }
574 LocalOpenPointer &operator=(LocalOpenPointer &&src) noexcept {
575 if (ptr != nullptr) { closeFunction(ptr); }
576 LocalPointerBase<Type>::ptr=src.ptr;
577 src.ptr=nullptr;
578 return *this;
579 }
580 /* TODO: Be agnostic of the deleter function signature from the user-provided std::unique_ptr? */
581 LocalOpenPointer &operator=(std::unique_ptr<Type, decltype(closeFunction)> &&p) {
582 adoptInstead(p.release());
583 return *this;
584 }
585 void swap(LocalOpenPointer &other) noexcept {
586 Type *temp=LocalPointerBase<Type>::ptr;
587 LocalPointerBase<Type>::ptr=other.ptr;
588 other.ptr=temp;
589 }
590 friend inline void swap(LocalOpenPointer &p1, LocalOpenPointer &p2) noexcept {
591 p1.swap(p2);
592 }
593 void adoptInstead(Type *p) {
594 if (ptr != nullptr) { closeFunction(ptr); }
595 ptr=p;
596 }
597 operator std::unique_ptr<Type, decltype(closeFunction)> () && {
598 return std::unique_ptr<Type, decltype(closeFunction)>(LocalPointerBase<Type>::orphan(), closeFunction);
599 }
600};
601} // namespace internal
602#endif
603
604U_NAMESPACE_END}
605
606#endif /* U_SHOW_CPLUSPLUS_API */
607#endif /* __LOCALPOINTER_H__ */