Bug Summary

File:root/firefox-clang/intl/icu/source/i18n/dtfmtsym.cpp
Warning:line 283, column 55
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name dtfmtsym.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-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -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 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/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -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-deprecated-this-capture -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-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 -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 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-27-100320-3286336-1 -x c++ /root/firefox-clang/intl/icu/source/i18n/dtfmtsym.cpp

/root/firefox-clang/intl/icu/source/i18n/dtfmtsym.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) 1997-2016, International Business Machines Corporation and *
6* others. All Rights Reserved. *
7*******************************************************************************
8*
9* File DTFMTSYM.CPP
10*
11* Modification History:
12*
13* Date Name Description
14* 02/19/97 aliu Converted from java.
15* 07/21/98 stephen Added getZoneIndex
16* Changed weekdays/short weekdays to be one-based
17* 06/14/99 stephen Removed SimpleDateFormat::fgTimeZoneDataSuffix
18* 11/16/99 weiv Added 'Y' and 'e' to fgPatternChars
19* 03/27/00 weiv Keeping resource bundle around!
20* 06/30/05 emmons Added eraNames, narrow month/day, standalone context
21* 10/12/05 emmons Added setters for eraNames, month/day by width/context
22*******************************************************************************
23*/
24
25#include <utility>
26
27#include "unicode/utypes.h"
28
29#if !UCONFIG_NO_FORMATTING0
30#include "unicode/ustring.h"
31#include "unicode/localpointer.h"
32#include "unicode/dtfmtsym.h"
33#include "unicode/smpdtfmt.h"
34#include "unicode/msgfmt.h"
35#include "unicode/numsys.h"
36#include "unicode/tznames.h"
37#include "cpputils.h"
38#include "umutex.h"
39#include "cmemory.h"
40#include "cstring.h"
41#include "charstr.h"
42#include "dt_impl.h"
43#include "locbased.h"
44#include "gregoimp.h"
45#include "hash.h"
46#include "uassert.h"
47#include "uresimp.h"
48#include "ureslocs.h"
49#include "uvector.h"
50#include "shareddateformatsymbols.h"
51#include "unicode/calendar.h"
52#include "unifiedcache.h"
53
54// *****************************************************************************
55// class DateFormatSymbols
56// *****************************************************************************
57
58/**
59 * These are static arrays we use only in the case where we have no
60 * resource data.
61 */
62
63#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR0
64#define PATTERN_CHARS_LEN37 38
65#else
66#define PATTERN_CHARS_LEN37 37
67#endif
68
69/**
70 * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All
71 * locales use the same these unlocalized pattern characters.
72 */
73static const char16_t gPatternChars[] = {
74 // if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR:
75 // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:
76 // else:
77 // GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB
78
79 0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45,
80 0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65,
81 0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56,
82 0x55, 0x4F, 0x58, 0x78, 0x72, 0x62, 0x42,
83#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR0
84 0x3a,
85#endif
86 0
87};
88
89/**
90 * Map of each ASCII character to its corresponding index in the table above if
91 * it is a pattern character and -1 otherwise.
92 */
93static const int8_t gLookupPatternChars[] = {
94 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
95 //
96 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
97 // ! " # $ % & ' ( ) * + , - . /
98 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
99#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR0
100 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
101 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1,
102#else
103 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
104 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
105#endif
106 // @ A B C D E F G H I J K L M N O
107 -1, 22, 36, -1, 10, 9, 11, 0, 5, -1, -1, 16, 26, 2, -1, 31,
108 // P Q R S T U V W X Y Z [ \ ] ^ _
109 -1, 27, -1, 8, -1, 30, 29, 13, 32, 18, 23, -1, -1, -1, -1, -1,
110 // ` a b c d e f g h i j k l m n o
111 -1, 14, 35, 25, 3, 19, -1, 21, 15, -1, -1, 4, -1, 6, -1, -1,
112 // p q r s t u v w x y z { | } ~
113 -1, 28, 34, 7, -1, 20, 24, 12, 33, 1, 17, -1, -1, -1, -1, -1
114};
115
116//------------------------------------------------------
117// Strings of last resort. These are only used if we have no resource
118// files. They aren't designed for actual use, just for backup.
119
120// These are the month names and abbreviations of last resort.
121static const char16_t gLastResortMonthNames[13][3] =
122{
123 {0x0030, 0x0031, 0x0000}, /* "01" */
124 {0x0030, 0x0032, 0x0000}, /* "02" */
125 {0x0030, 0x0033, 0x0000}, /* "03" */
126 {0x0030, 0x0034, 0x0000}, /* "04" */
127 {0x0030, 0x0035, 0x0000}, /* "05" */
128 {0x0030, 0x0036, 0x0000}, /* "06" */
129 {0x0030, 0x0037, 0x0000}, /* "07" */
130 {0x0030, 0x0038, 0x0000}, /* "08" */
131 {0x0030, 0x0039, 0x0000}, /* "09" */
132 {0x0031, 0x0030, 0x0000}, /* "10" */
133 {0x0031, 0x0031, 0x0000}, /* "11" */
134 {0x0031, 0x0032, 0x0000}, /* "12" */
135 {0x0031, 0x0033, 0x0000} /* "13" */
136};
137
138// These are the weekday names and abbreviations of last resort.
139static const char16_t gLastResortDayNames[8][2] =
140{
141 {0x0030, 0x0000}, /* "0" */
142 {0x0031, 0x0000}, /* "1" */
143 {0x0032, 0x0000}, /* "2" */
144 {0x0033, 0x0000}, /* "3" */
145 {0x0034, 0x0000}, /* "4" */
146 {0x0035, 0x0000}, /* "5" */
147 {0x0036, 0x0000}, /* "6" */
148 {0x0037, 0x0000} /* "7" */
149};
150
151// These are the quarter names and abbreviations of last resort.
152static const char16_t gLastResortQuarters[4][2] =
153{
154 {0x0031, 0x0000}, /* "1" */
155 {0x0032, 0x0000}, /* "2" */
156 {0x0033, 0x0000}, /* "3" */
157 {0x0034, 0x0000}, /* "4" */
158};
159
160// These are the am/pm and BC/AD markers of last resort.
161static const char16_t gLastResortAmPmMarkers[2][3] =
162{
163 {0x0041, 0x004D, 0x0000}, /* "AM" */
164 {0x0050, 0x004D, 0x0000} /* "PM" */
165};
166
167static const char16_t gLastResortEras[2][3] =
168{
169 {0x0042, 0x0043, 0x0000}, /* "BC" */
170 {0x0041, 0x0044, 0x0000} /* "AD" */
171};
172
173/* Sizes for the last resort string arrays */
174typedef enum LastResortSize {
175 kMonthNum = 13,
176 kMonthLen = 3,
177
178 kDayNum = 8,
179 kDayLen = 2,
180
181 kAmPmNum = 2,
182 kAmPmLen = 3,
183
184 kQuarterNum = 4,
185 kQuarterLen = 2,
186
187 kEraNum = 2,
188 kEraLen = 3,
189
190 kZoneNum = 5,
191 kZoneLen = 4,
192
193 kGmtHourNum = 4,
194 kGmtHourLen = 10
195} LastResortSize;
196
197U_NAMESPACE_BEGINnamespace icu_77 {
198
199SharedDateFormatSymbols::~SharedDateFormatSymbols() {
200}
201
202template<> U_I18N_API
203const SharedDateFormatSymbols *
204 LocaleCacheKey<SharedDateFormatSymbols>::createObject(
205 const void * /*unusedContext*/, UErrorCode &status) const {
206 char type[256];
207 Calendar::getCalendarTypeFromLocale(fLoc, type, UPRV_LENGTHOF(type)(int32_t)(sizeof(type)/sizeof((type)[0])), status);
208 if (U_FAILURE(status)) {
209 return nullptr;
210 }
211 SharedDateFormatSymbols *shared
212 = new SharedDateFormatSymbols(fLoc, type, status);
213 if (shared == nullptr) {
214 status = U_MEMORY_ALLOCATION_ERROR;
215 return nullptr;
216 }
217 if (U_FAILURE(status)) {
218 delete shared;
219 return nullptr;
220 }
221 shared->addRef();
222 return shared;
223}
224
225UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols)UClassID DateFormatSymbols::getStaticClassID() { static char classID
= 0; return (UClassID)&classID; } UClassID DateFormatSymbols
::getDynamicClassID() const { return DateFormatSymbols::getStaticClassID
(); }
226
227#define kSUPPLEMENTAL"supplementalData" "supplementalData"
228
229/**
230 * These are the tags we expect to see in normal resource bundle files associated
231 * with a locale and calendar
232 */
233static const char gCalendarTag[]="calendar";
234static const char gGregorianTag[]="gregorian";
235static const char gErasTag[]="eras";
236static const char gCyclicNameSetsTag[]="cyclicNameSets";
237static const char gNameSetYearsTag[]="years";
238static const char gNameSetZodiacsTag[]="zodiacs";
239static const char gMonthNamesTag[]="monthNames";
240static const char gMonthPatternsTag[]="monthPatterns";
241static const char gDayNamesTag[]="dayNames";
242static const char gNamesWideTag[]="wide";
243static const char gNamesAbbrTag[]="abbreviated";
244static const char gNamesShortTag[]="short";
245static const char gNamesNarrowTag[]="narrow";
246static const char gNamesAllTag[]="all";
247static const char gNamesFormatTag[]="format";
248static const char gNamesStandaloneTag[]="stand-alone";
249static const char gNamesNumericTag[]="numeric";
250static const char gAmPmMarkersTag[]="AmPmMarkers";
251static const char gAmPmMarkersAbbrTag[]="AmPmMarkersAbbr";
252static const char gAmPmMarkersNarrowTag[]="AmPmMarkersNarrow";
253static const char gQuartersTag[]="quarters";
254static const char gNumberElementsTag[]="NumberElements";
255static const char gSymbolsTag[]="symbols";
256static const char gTimeSeparatorTag[]="timeSeparator";
257static const char gDayPeriodTag[]="dayPeriod";
258
259// static const char gZoneStringsTag[]="zoneStrings";
260
261// static const char gLocalPatternCharsTag[]="localPatternChars";
262
263static const char gContextTransformsTag[]="contextTransforms";
264
265/**
266 * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly.
267 * Work around this.
268 */
269static inline UnicodeString* newUnicodeStringArray(size_t count) {
270 return new UnicodeString[count ? count : 1];
271}
272
273//------------------------------------------------------
274
275DateFormatSymbols * U_EXPORT2
276DateFormatSymbols::createForLocale(
277 const Locale& locale, UErrorCode &status) {
278 const SharedDateFormatSymbols *shared = nullptr;
1
'shared' initialized to a null pointer value
279 UnifiedCache::getByLocale(locale, shared, status);
2
Calling 'UnifiedCache::getByLocale'
19
Returning from 'UnifiedCache::getByLocale'
280 if (U_FAILURE(status)) {
20
Taking false branch
281 return nullptr;
282 }
283 DateFormatSymbols *result = new DateFormatSymbols(shared->get());
21
Called C++ object pointer is null
284 shared->removeRef();
285 if (result == nullptr) {
286 status = U_MEMORY_ALLOCATION_ERROR;
287 return nullptr;
288 }
289 return result;
290}
291
292DateFormatSymbols::DateFormatSymbols(const Locale& locale,
293 UErrorCode& status)
294 : UObject()
295{
296 initializeData(locale, nullptr, status);
297}
298
299DateFormatSymbols::DateFormatSymbols(UErrorCode& status)
300 : UObject()
301{
302 initializeData(Locale::getDefault(), nullptr, status, true);
303}
304
305
306DateFormatSymbols::DateFormatSymbols(const Locale& locale,
307 const char *type,
308 UErrorCode& status)
309 : UObject()
310{
311 initializeData(locale, type, status);
312}
313
314DateFormatSymbols::DateFormatSymbols(const char *type, UErrorCode& status)
315 : UObject()
316{
317 initializeData(Locale::getDefault(), type, status, true);
318}
319
320DateFormatSymbols::DateFormatSymbols(const DateFormatSymbols& other)
321 : UObject(other)
322{
323 copyData(other);
324}
325
326void
327DateFormatSymbols::assignArray(UnicodeString*& dstArray,
328 int32_t& dstCount,
329 const UnicodeString* srcArray,
330 int32_t srcCount)
331{
332 // assignArray() is only called by copyData() and initializeData(), which in turn
333 // implements the copy constructor and the assignment operator.
334 // All strings in a DateFormatSymbols object are created in one of the following
335 // three ways that all allow to safely use UnicodeString::fastCopyFrom():
336 // - readonly-aliases from resource bundles
337 // - readonly-aliases or allocated strings from constants
338 // - safely cloned strings (with owned buffers) from setXYZ() functions
339 //
340 // Note that this is true for as long as DateFormatSymbols can be constructed
341 // only from a locale bundle or set via the cloning API,
342 // *and* for as long as all the strings are in *private* fields, preventing
343 // a subclass from creating these strings in an "unsafe" way (with respect to fastCopyFrom()).
344 if(srcArray == nullptr) {
345 // Do not attempt to copy bogus input (which will crash).
346 // Note that this assignArray method already had the potential to return a null dstArray;
347 // see handling below for "if(dstArray != nullptr)".
348 dstCount = 0;
349 dstArray = nullptr;
350 return;
351 }
352 dstCount = srcCount;
353 dstArray = newUnicodeStringArray(srcCount);
354 if(dstArray != nullptr) {
355 int32_t i;
356 for(i=0; i<srcCount; ++i) {
357 dstArray[i].fastCopyFrom(srcArray[i]);
358 }
359 }
360}
361
362/**
363 * Create a copy, in fZoneStrings, of the given zone strings array. The
364 * member variables fZoneStringsRowCount and fZoneStringsColCount should
365 * be set already by the caller.
366 */
367void
368DateFormatSymbols::createZoneStrings(const UnicodeString *const * otherStrings)
369{
370 int32_t row, col;
371 UBool failed = false;
372
373 fZoneStrings = static_cast<UnicodeString**>(uprv_mallocuprv_malloc_77(fZoneStringsRowCount * sizeof(UnicodeString*)));
374 if (fZoneStrings != nullptr) {
375 for (row=0; row<fZoneStringsRowCount; ++row)
376 {
377 fZoneStrings[row] = newUnicodeStringArray(fZoneStringsColCount);
378 if (fZoneStrings[row] == nullptr) {
379 failed = true;
380 break;
381 }
382 for (col=0; col<fZoneStringsColCount; ++col) {
383 // fastCopyFrom() - see assignArray comments
384 fZoneStrings[row][col].fastCopyFrom(otherStrings[row][col]);
385 }
386 }
387 }
388 // If memory allocation failed, roll back and delete fZoneStrings
389 if (failed) {
390 for (int i = row; i >= 0; i--) {
391 delete[] fZoneStrings[i];
392 }
393 uprv_freeuprv_free_77(fZoneStrings);
394 fZoneStrings = nullptr;
395 }
396}
397
398/**
399 * Copy all of the other's data to this.
400 */
401void
402DateFormatSymbols::copyData(const DateFormatSymbols& other) {
403 UErrorCode status = U_ZERO_ERROR;
404 U_LOCALE_BASED(locBased, *this)LocaleBased locBased((*this).validLocale, (*this).actualLocale
)
;
405 locBased.setLocaleIDs(other.validLocale, other.actualLocale, status);
406 U_ASSERT(U_SUCCESS(status))(static_cast <bool> (U_SUCCESS(status)) ? void (0) : __assert_fail
("U_SUCCESS(status)", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
407 assignArray(fEras, fErasCount, other.fEras, other.fErasCount);
408 assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount);
409 assignArray(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount);
410 assignArray(fMonths, fMonthsCount, other.fMonths, other.fMonthsCount);
411 assignArray(fShortMonths, fShortMonthsCount, other.fShortMonths, other.fShortMonthsCount);
412 assignArray(fNarrowMonths, fNarrowMonthsCount, other.fNarrowMonths, other.fNarrowMonthsCount);
413 assignArray(fStandaloneMonths, fStandaloneMonthsCount, other.fStandaloneMonths, other.fStandaloneMonthsCount);
414 assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, other.fStandaloneShortMonths, other.fStandaloneShortMonthsCount);
415 assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, other.fStandaloneNarrowMonths, other.fStandaloneNarrowMonthsCount);
416 assignArray(fWeekdays, fWeekdaysCount, other.fWeekdays, other.fWeekdaysCount);
417 assignArray(fShortWeekdays, fShortWeekdaysCount, other.fShortWeekdays, other.fShortWeekdaysCount);
418 assignArray(fShorterWeekdays, fShorterWeekdaysCount, other.fShorterWeekdays, other.fShorterWeekdaysCount);
419 assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, other.fNarrowWeekdays, other.fNarrowWeekdaysCount);
420 assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, other.fStandaloneWeekdays, other.fStandaloneWeekdaysCount);
421 assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, other.fStandaloneShortWeekdays, other.fStandaloneShortWeekdaysCount);
422 assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, other.fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdaysCount);
423 assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, other.fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdaysCount);
424 assignArray(fAmPms, fAmPmsCount, other.fAmPms, other.fAmPmsCount);
425 assignArray(fNarrowAmPms, fNarrowAmPmsCount, other.fNarrowAmPms, other.fNarrowAmPmsCount );
426 fTimeSeparator.fastCopyFrom(other.fTimeSeparator); // fastCopyFrom() - see assignArray comments
427 assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount);
428 assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
429 assignArray(fNarrowQuarters, fNarrowQuartersCount, other.fNarrowQuarters, other.fNarrowQuartersCount);
430 assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
431 assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount);
432 assignArray(fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, other.fStandaloneNarrowQuarters, other.fStandaloneNarrowQuartersCount);
433 assignArray(fWideDayPeriods, fWideDayPeriodsCount,
434 other.fWideDayPeriods, other.fWideDayPeriodsCount);
435 assignArray(fNarrowDayPeriods, fNarrowDayPeriodsCount,
436 other.fNarrowDayPeriods, other.fNarrowDayPeriodsCount);
437 assignArray(fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount,
438 other.fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriodsCount);
439 assignArray(fStandaloneWideDayPeriods, fStandaloneWideDayPeriodsCount,
440 other.fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriodsCount);
441 assignArray(fStandaloneNarrowDayPeriods, fStandaloneNarrowDayPeriodsCount,
442 other.fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriodsCount);
443 assignArray(fStandaloneAbbreviatedDayPeriods, fStandaloneAbbreviatedDayPeriodsCount,
444 other.fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriodsCount);
445 if (other.fLeapMonthPatterns != nullptr) {
446 assignArray(fLeapMonthPatterns, fLeapMonthPatternsCount, other.fLeapMonthPatterns, other.fLeapMonthPatternsCount);
447 } else {
448 fLeapMonthPatterns = nullptr;
449 fLeapMonthPatternsCount = 0;
450 }
451 if (other.fShortYearNames != nullptr) {
452 assignArray(fShortYearNames, fShortYearNamesCount, other.fShortYearNames, other.fShortYearNamesCount);
453 } else {
454 fShortYearNames = nullptr;
455 fShortYearNamesCount = 0;
456 }
457 if (other.fShortZodiacNames != nullptr) {
458 assignArray(fShortZodiacNames, fShortZodiacNamesCount, other.fShortZodiacNames, other.fShortZodiacNamesCount);
459 } else {
460 fShortZodiacNames = nullptr;
461 fShortZodiacNamesCount = 0;
462 }
463
464 if (other.fZoneStrings != nullptr) {
465 fZoneStringsColCount = other.fZoneStringsColCount;
466 fZoneStringsRowCount = other.fZoneStringsRowCount;
467 createZoneStrings((const UnicodeString**)other.fZoneStrings);
468
469 } else {
470 fZoneStrings = nullptr;
471 fZoneStringsColCount = 0;
472 fZoneStringsRowCount = 0;
473 }
474 fZSFLocale = other.fZSFLocale;
475 // Other zone strings data is created on demand
476 fLocaleZoneStrings = nullptr;
477
478 // fastCopyFrom() - see assignArray comments
479 fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
480
481 uprv_memcpy(fCapitalization, other.fCapitalization, sizeof(fCapitalization))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(static_cast <bool> (fCapitalization != __null) ? void
(0) : __assert_fail ("fCapitalization != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); (
static_cast <bool> (other.fCapitalization != __null) ? void
(0) : __assert_fail ("other.fCapitalization != __null", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); clang
diagnostic pop :: memcpy(fCapitalization, other.fCapitalization
, sizeof(fCapitalization)); } while (false)
;
482}
483
484/**
485 * Assignment operator.
486 */
487DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other)
488{
489 if (this == &other) { return *this; } // self-assignment: no-op
490 dispose();
491 copyData(other);
492
493 return *this;
494}
495
496DateFormatSymbols::~DateFormatSymbols()
497{
498 dispose();
499 delete actualLocale;
500 delete validLocale;
501}
502
503void DateFormatSymbols::dispose()
504{
505 delete[] fEras;
506 delete[] fEraNames;
507 delete[] fNarrowEras;
508 delete[] fMonths;
509 delete[] fShortMonths;
510 delete[] fNarrowMonths;
511 delete[] fStandaloneMonths;
512 delete[] fStandaloneShortMonths;
513 delete[] fStandaloneNarrowMonths;
514 delete[] fWeekdays;
515 delete[] fShortWeekdays;
516 delete[] fShorterWeekdays;
517 delete[] fNarrowWeekdays;
518 delete[] fStandaloneWeekdays;
519 delete[] fStandaloneShortWeekdays;
520 delete[] fStandaloneShorterWeekdays;
521 delete[] fStandaloneNarrowWeekdays;
522 delete[] fAmPms;
523 delete[] fNarrowAmPms;
524 delete[] fQuarters;
525 delete[] fShortQuarters;
526 delete[] fNarrowQuarters;
527 delete[] fStandaloneQuarters;
528 delete[] fStandaloneShortQuarters;
529 delete[] fStandaloneNarrowQuarters;
530 delete[] fLeapMonthPatterns;
531 delete[] fShortYearNames;
532 delete[] fShortZodiacNames;
533 delete[] fAbbreviatedDayPeriods;
534 delete[] fWideDayPeriods;
535 delete[] fNarrowDayPeriods;
536 delete[] fStandaloneAbbreviatedDayPeriods;
537 delete[] fStandaloneWideDayPeriods;
538 delete[] fStandaloneNarrowDayPeriods;
539
540 delete actualLocale;
541 actualLocale = nullptr;
542 delete validLocale;
543 validLocale = nullptr;
544 disposeZoneStrings();
545}
546
547void DateFormatSymbols::disposeZoneStrings()
548{
549 if (fZoneStrings) {
550 for (int32_t row = 0; row < fZoneStringsRowCount; ++row) {
551 delete[] fZoneStrings[row];
552 }
553 uprv_freeuprv_free_77(fZoneStrings);
554 }
555 if (fLocaleZoneStrings) {
556 for (int32_t row = 0; row < fZoneStringsRowCount; ++row) {
557 delete[] fLocaleZoneStrings[row];
558 }
559 uprv_freeuprv_free_77(fLocaleZoneStrings);
560 }
561
562 fZoneStrings = nullptr;
563 fLocaleZoneStrings = nullptr;
564 fZoneStringsRowCount = 0;
565 fZoneStringsColCount = 0;
566}
567
568UBool
569DateFormatSymbols::arrayCompare(const UnicodeString* array1,
570 const UnicodeString* array2,
571 int32_t count)
572{
573 if (array1 == array2) return true;
574 while (count>0)
575 {
576 --count;
577 if (array1[count] != array2[count]) return false;
578 }
579 return true;
580}
581
582bool
583DateFormatSymbols::operator==(const DateFormatSymbols& other) const
584{
585 // First do cheap comparisons
586 if (this == &other) {
587 return true;
588 }
589 if (fErasCount == other.fErasCount &&
590 fEraNamesCount == other.fEraNamesCount &&
591 fNarrowErasCount == other.fNarrowErasCount &&
592 fMonthsCount == other.fMonthsCount &&
593 fShortMonthsCount == other.fShortMonthsCount &&
594 fNarrowMonthsCount == other.fNarrowMonthsCount &&
595 fStandaloneMonthsCount == other.fStandaloneMonthsCount &&
596 fStandaloneShortMonthsCount == other.fStandaloneShortMonthsCount &&
597 fStandaloneNarrowMonthsCount == other.fStandaloneNarrowMonthsCount &&
598 fWeekdaysCount == other.fWeekdaysCount &&
599 fShortWeekdaysCount == other.fShortWeekdaysCount &&
600 fShorterWeekdaysCount == other.fShorterWeekdaysCount &&
601 fNarrowWeekdaysCount == other.fNarrowWeekdaysCount &&
602 fStandaloneWeekdaysCount == other.fStandaloneWeekdaysCount &&
603 fStandaloneShortWeekdaysCount == other.fStandaloneShortWeekdaysCount &&
604 fStandaloneShorterWeekdaysCount == other.fStandaloneShorterWeekdaysCount &&
605 fStandaloneNarrowWeekdaysCount == other.fStandaloneNarrowWeekdaysCount &&
606 fAmPmsCount == other.fAmPmsCount &&
607 fNarrowAmPmsCount == other.fNarrowAmPmsCount &&
608 fQuartersCount == other.fQuartersCount &&
609 fShortQuartersCount == other.fShortQuartersCount &&
610 fNarrowQuartersCount == other.fNarrowQuartersCount &&
611 fStandaloneQuartersCount == other.fStandaloneQuartersCount &&
612 fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount &&
613 fStandaloneNarrowQuartersCount == other.fStandaloneNarrowQuartersCount &&
614 fLeapMonthPatternsCount == other.fLeapMonthPatternsCount &&
615 fShortYearNamesCount == other.fShortYearNamesCount &&
616 fShortZodiacNamesCount == other.fShortZodiacNamesCount &&
617 fAbbreviatedDayPeriodsCount == other.fAbbreviatedDayPeriodsCount &&
618 fWideDayPeriodsCount == other.fWideDayPeriodsCount &&
619 fNarrowDayPeriodsCount == other.fNarrowDayPeriodsCount &&
620 fStandaloneAbbreviatedDayPeriodsCount == other.fStandaloneAbbreviatedDayPeriodsCount &&
621 fStandaloneWideDayPeriodsCount == other.fStandaloneWideDayPeriodsCount &&
622 fStandaloneNarrowDayPeriodsCount == other.fStandaloneNarrowDayPeriodsCount &&
623 (uprv_memcmp(fCapitalization, other.fCapitalization, sizeof(fCapitalization)):: memcmp(fCapitalization, other.fCapitalization,sizeof(fCapitalization
))
==0))
624 {
625 // Now compare the arrays themselves
626 if (arrayCompare(fEras, other.fEras, fErasCount) &&
627 arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) &&
628 arrayCompare(fNarrowEras, other.fNarrowEras, fNarrowErasCount) &&
629 arrayCompare(fMonths, other.fMonths, fMonthsCount) &&
630 arrayCompare(fShortMonths, other.fShortMonths, fShortMonthsCount) &&
631 arrayCompare(fNarrowMonths, other.fNarrowMonths, fNarrowMonthsCount) &&
632 arrayCompare(fStandaloneMonths, other.fStandaloneMonths, fStandaloneMonthsCount) &&
633 arrayCompare(fStandaloneShortMonths, other.fStandaloneShortMonths, fStandaloneShortMonthsCount) &&
634 arrayCompare(fStandaloneNarrowMonths, other.fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount) &&
635 arrayCompare(fWeekdays, other.fWeekdays, fWeekdaysCount) &&
636 arrayCompare(fShortWeekdays, other.fShortWeekdays, fShortWeekdaysCount) &&
637 arrayCompare(fShorterWeekdays, other.fShorterWeekdays, fShorterWeekdaysCount) &&
638 arrayCompare(fNarrowWeekdays, other.fNarrowWeekdays, fNarrowWeekdaysCount) &&
639 arrayCompare(fStandaloneWeekdays, other.fStandaloneWeekdays, fStandaloneWeekdaysCount) &&
640 arrayCompare(fStandaloneShortWeekdays, other.fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount) &&
641 arrayCompare(fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount) &&
642 arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) &&
643 arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) &&
644 arrayCompare(fNarrowAmPms, other.fNarrowAmPms, fNarrowAmPmsCount) &&
645 fTimeSeparator == other.fTimeSeparator &&
646 arrayCompare(fQuarters, other.fQuarters, fQuartersCount) &&
647 arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) &&
648 arrayCompare(fNarrowQuarters, other.fNarrowQuarters, fNarrowQuartersCount) &&
649 arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) &&
650 arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) &&
651 arrayCompare(fStandaloneNarrowQuarters, other.fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount) &&
652 arrayCompare(fLeapMonthPatterns, other.fLeapMonthPatterns, fLeapMonthPatternsCount) &&
653 arrayCompare(fShortYearNames, other.fShortYearNames, fShortYearNamesCount) &&
654 arrayCompare(fShortZodiacNames, other.fShortZodiacNames, fShortZodiacNamesCount) &&
655 arrayCompare(fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount) &&
656 arrayCompare(fWideDayPeriods, other.fWideDayPeriods, fWideDayPeriodsCount) &&
657 arrayCompare(fNarrowDayPeriods, other.fNarrowDayPeriods, fNarrowDayPeriodsCount) &&
658 arrayCompare(fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriods,
659 fStandaloneAbbreviatedDayPeriodsCount) &&
660 arrayCompare(fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriods,
661 fStandaloneWideDayPeriodsCount) &&
662 arrayCompare(fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriods,
663 fStandaloneWideDayPeriodsCount))
664 {
665 // Compare the contents of fZoneStrings
666 if (fZoneStrings == nullptr && other.fZoneStrings == nullptr) {
667 if (fZSFLocale == other.fZSFLocale) {
668 return true;
669 }
670 } else if (fZoneStrings != nullptr && other.fZoneStrings != nullptr) {
671 if (fZoneStringsRowCount == other.fZoneStringsRowCount
672 && fZoneStringsColCount == other.fZoneStringsColCount) {
673 bool cmpres = true;
674 for (int32_t i = 0; (i < fZoneStringsRowCount) && cmpres; i++) {
675 cmpres = arrayCompare(fZoneStrings[i], other.fZoneStrings[i], fZoneStringsColCount);
676 }
677 return cmpres;
678 }
679 }
680 return false;
681 }
682 }
683 return false;
684}
685
686//------------------------------------------------------
687
688const UnicodeString*
689DateFormatSymbols::getEras(int32_t &count) const
690{
691 count = fErasCount;
692 return fEras;
693}
694
695const UnicodeString*
696DateFormatSymbols::getEraNames(int32_t &count) const
697{
698 count = fEraNamesCount;
699 return fEraNames;
700}
701
702const UnicodeString*
703DateFormatSymbols::getNarrowEras(int32_t &count) const
704{
705 count = fNarrowErasCount;
706 return fNarrowEras;
707}
708
709const UnicodeString*
710DateFormatSymbols::getMonths(int32_t &count) const
711{
712 count = fMonthsCount;
713 return fMonths;
714}
715
716const UnicodeString*
717DateFormatSymbols::getShortMonths(int32_t &count) const
718{
719 count = fShortMonthsCount;
720 return fShortMonths;
721}
722
723const UnicodeString*
724DateFormatSymbols::getMonths(int32_t &count, DtContextType context, DtWidthType width ) const
725{
726 UnicodeString *returnValue = nullptr;
727
728 switch (context) {
729 case FORMAT :
730 switch(width) {
731 case WIDE :
732 count = fMonthsCount;
733 returnValue = fMonths;
734 break;
735 case ABBREVIATED :
736 case SHORT : // no month data for this, defaults to ABBREVIATED
737 count = fShortMonthsCount;
738 returnValue = fShortMonths;
739 break;
740 case NARROW :
741 count = fNarrowMonthsCount;
742 returnValue = fNarrowMonths;
743 break;
744 case DT_WIDTH_COUNT :
745 break;
746 }
747 break;
748 case STANDALONE :
749 switch(width) {
750 case WIDE :
751 count = fStandaloneMonthsCount;
752 returnValue = fStandaloneMonths;
753 break;
754 case ABBREVIATED :
755 case SHORT : // no month data for this, defaults to ABBREVIATED
756 count = fStandaloneShortMonthsCount;
757 returnValue = fStandaloneShortMonths;
758 break;
759 case NARROW :
760 count = fStandaloneNarrowMonthsCount;
761 returnValue = fStandaloneNarrowMonths;
762 break;
763 case DT_WIDTH_COUNT :
764 break;
765 }
766 break;
767 case DT_CONTEXT_COUNT :
768 break;
769 }
770 return returnValue;
771}
772
773const UnicodeString*
774DateFormatSymbols::getWeekdays(int32_t &count) const
775{
776 count = fWeekdaysCount;
777 return fWeekdays;
778}
779
780const UnicodeString*
781DateFormatSymbols::getShortWeekdays(int32_t &count) const
782{
783 count = fShortWeekdaysCount;
784 return fShortWeekdays;
785}
786
787const UnicodeString*
788DateFormatSymbols::getWeekdays(int32_t &count, DtContextType context, DtWidthType width) const
789{
790 UnicodeString *returnValue = nullptr;
791 switch (context) {
792 case FORMAT :
793 switch(width) {
794 case WIDE :
795 count = fWeekdaysCount;
796 returnValue = fWeekdays;
797 break;
798 case ABBREVIATED :
799 count = fShortWeekdaysCount;
800 returnValue = fShortWeekdays;
801 break;
802 case SHORT :
803 count = fShorterWeekdaysCount;
804 returnValue = fShorterWeekdays;
805 break;
806 case NARROW :
807 count = fNarrowWeekdaysCount;
808 returnValue = fNarrowWeekdays;
809 break;
810 case DT_WIDTH_COUNT :
811 break;
812 }
813 break;
814 case STANDALONE :
815 switch(width) {
816 case WIDE :
817 count = fStandaloneWeekdaysCount;
818 returnValue = fStandaloneWeekdays;
819 break;
820 case ABBREVIATED :
821 count = fStandaloneShortWeekdaysCount;
822 returnValue = fStandaloneShortWeekdays;
823 break;
824 case SHORT :
825 count = fStandaloneShorterWeekdaysCount;
826 returnValue = fStandaloneShorterWeekdays;
827 break;
828 case NARROW :
829 count = fStandaloneNarrowWeekdaysCount;
830 returnValue = fStandaloneNarrowWeekdays;
831 break;
832 case DT_WIDTH_COUNT :
833 break;
834 }
835 break;
836 case DT_CONTEXT_COUNT :
837 break;
838 }
839 return returnValue;
840}
841
842const UnicodeString*
843DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthType width ) const
844{
845 UnicodeString *returnValue = nullptr;
846
847 switch (context) {
848 case FORMAT :
849 switch(width) {
850 case WIDE :
851 count = fQuartersCount;
852 returnValue = fQuarters;
853 break;
854 case ABBREVIATED :
855 case SHORT : // no quarter data for this, defaults to ABBREVIATED
856 count = fShortQuartersCount;
857 returnValue = fShortQuarters;
858 break;
859 case NARROW :
860 count = fNarrowQuartersCount;
861 returnValue = fNarrowQuarters;
862 break;
863 case DT_WIDTH_COUNT :
864 break;
865 }
866 break;
867 case STANDALONE :
868 switch(width) {
869 case WIDE :
870 count = fStandaloneQuartersCount;
871 returnValue = fStandaloneQuarters;
872 break;
873 case ABBREVIATED :
874 case SHORT : // no quarter data for this, defaults to ABBREVIATED
875 count = fStandaloneShortQuartersCount;
876 returnValue = fStandaloneShortQuarters;
877 break;
878 case NARROW :
879 count = fStandaloneNarrowQuartersCount;
880 returnValue = fStandaloneNarrowQuarters;
881 break;
882 case DT_WIDTH_COUNT :
883 break;
884 }
885 break;
886 case DT_CONTEXT_COUNT :
887 break;
888 }
889 return returnValue;
890}
891
892UnicodeString&
893DateFormatSymbols::getTimeSeparatorString(UnicodeString& result) const
894{
895 // fastCopyFrom() - see assignArray comments
896 return result.fastCopyFrom(fTimeSeparator);
897}
898
899const UnicodeString*
900DateFormatSymbols::getAmPmStrings(int32_t &count) const
901{
902 count = fAmPmsCount;
903 return fAmPms;
904}
905
906const UnicodeString*
907DateFormatSymbols::getLeapMonthPatterns(int32_t &count) const
908{
909 count = fLeapMonthPatternsCount;
910 return fLeapMonthPatterns;
911}
912
913const UnicodeString*
914DateFormatSymbols::getYearNames(int32_t& count,
915 DtContextType /*ignored*/, DtWidthType /*ignored*/) const
916{
917 count = fShortYearNamesCount;
918 return fShortYearNames;
919}
920
921void
922DateFormatSymbols::setYearNames(const UnicodeString* yearNames, int32_t count,
923 DtContextType context, DtWidthType width)
924{
925 if (context == FORMAT && width == ABBREVIATED) {
926 delete[] fShortYearNames;
927 fShortYearNames = newUnicodeStringArray(count);
928 uprv_arrayCopy(yearNames, fShortYearNames, count);
929 fShortYearNamesCount = count;
930 }
931}
932
933const UnicodeString*
934DateFormatSymbols::getZodiacNames(int32_t& count,
935 DtContextType /*ignored*/, DtWidthType /*ignored*/) const
936{
937 count = fShortZodiacNamesCount;
938 return fShortZodiacNames;
939}
940
941void
942DateFormatSymbols::setZodiacNames(const UnicodeString* zodiacNames, int32_t count,
943 DtContextType context, DtWidthType width)
944{
945 if (context == FORMAT && width == ABBREVIATED) {
946 delete[] fShortZodiacNames;
947 fShortZodiacNames = newUnicodeStringArray(count);
948 uprv_arrayCopy(zodiacNames, fShortZodiacNames, count);
949 fShortZodiacNamesCount = count;
950 }
951}
952
953//------------------------------------------------------
954
955void
956DateFormatSymbols::setEras(const UnicodeString* erasArray, int32_t count)
957{
958 // delete the old list if we own it
959 delete[] fEras;
960
961 // we always own the new list, which we create here (we duplicate rather
962 // than adopting the list passed in)
963 fEras = newUnicodeStringArray(count);
964 uprv_arrayCopy(erasArray,fEras, count);
965 fErasCount = count;
966}
967
968void
969DateFormatSymbols::setEraNames(const UnicodeString* eraNamesArray, int32_t count)
970{
971 // delete the old list if we own it
972 delete[] fEraNames;
973
974 // we always own the new list, which we create here (we duplicate rather
975 // than adopting the list passed in)
976 fEraNames = newUnicodeStringArray(count);
977 uprv_arrayCopy(eraNamesArray,fEraNames, count);
978 fEraNamesCount = count;
979}
980
981void
982DateFormatSymbols::setNarrowEras(const UnicodeString* narrowErasArray, int32_t count)
983{
984 // delete the old list if we own it
985 delete[] fNarrowEras;
986
987 // we always own the new list, which we create here (we duplicate rather
988 // than adopting the list passed in)
989 fNarrowEras = newUnicodeStringArray(count);
990 uprv_arrayCopy(narrowErasArray,fNarrowEras, count);
991 fNarrowErasCount = count;
992}
993
994void
995DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count)
996{
997 // delete the old list if we own it
998 delete[] fMonths;
999
1000 // we always own the new list, which we create here (we duplicate rather
1001 // than adopting the list passed in)
1002 fMonths = newUnicodeStringArray(count);
1003 uprv_arrayCopy( monthsArray,fMonths,count);
1004 fMonthsCount = count;
1005}
1006
1007void
1008DateFormatSymbols::setShortMonths(const UnicodeString* shortMonthsArray, int32_t count)
1009{
1010 // delete the old list if we own it
1011 delete[] fShortMonths;
1012
1013 // we always own the new list, which we create here (we duplicate rather
1014 // than adopting the list passed in)
1015 fShortMonths = newUnicodeStringArray(count);
1016 uprv_arrayCopy(shortMonthsArray,fShortMonths, count);
1017 fShortMonthsCount = count;
1018}
1019
1020void
1021DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, DtContextType context, DtWidthType width)
1022{
1023 // delete the old list if we own it
1024 // we always own the new list, which we create here (we duplicate rather
1025 // than adopting the list passed in)
1026
1027 switch (context) {
1028 case FORMAT :
1029 switch (width) {
1030 case WIDE :
1031 delete[] fMonths;
1032 fMonths = newUnicodeStringArray(count);
1033 uprv_arrayCopy( monthsArray,fMonths,count);
1034 fMonthsCount = count;
1035 break;
1036 case ABBREVIATED :
1037 delete[] fShortMonths;
1038 fShortMonths = newUnicodeStringArray(count);
1039 uprv_arrayCopy( monthsArray,fShortMonths,count);
1040 fShortMonthsCount = count;
1041 break;
1042 case NARROW :
1043 delete[] fNarrowMonths;
1044 fNarrowMonths = newUnicodeStringArray(count);
1045 uprv_arrayCopy( monthsArray,fNarrowMonths,count);
1046 fNarrowMonthsCount = count;
1047 break;
1048 default :
1049 break;
1050 }
1051 break;
1052 case STANDALONE :
1053 switch (width) {
1054 case WIDE :
1055 delete[] fStandaloneMonths;
1056 fStandaloneMonths = newUnicodeStringArray(count);
1057 uprv_arrayCopy( monthsArray,fStandaloneMonths,count);
1058 fStandaloneMonthsCount = count;
1059 break;
1060 case ABBREVIATED :
1061 delete[] fStandaloneShortMonths;
1062 fStandaloneShortMonths = newUnicodeStringArray(count);
1063 uprv_arrayCopy( monthsArray,fStandaloneShortMonths,count);
1064 fStandaloneShortMonthsCount = count;
1065 break;
1066 case NARROW :
1067 delete[] fStandaloneNarrowMonths;
1068 fStandaloneNarrowMonths = newUnicodeStringArray(count);
1069 uprv_arrayCopy( monthsArray,fStandaloneNarrowMonths,count);
1070 fStandaloneNarrowMonthsCount = count;
1071 break;
1072 default :
1073 break;
1074 }
1075 break;
1076 case DT_CONTEXT_COUNT :
1077 break;
1078 }
1079}
1080
1081void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count)
1082{
1083 // delete the old list if we own it
1084 delete[] fWeekdays;
1085
1086 // we always own the new list, which we create here (we duplicate rather
1087 // than adopting the list passed in)
1088 fWeekdays = newUnicodeStringArray(count);
1089 uprv_arrayCopy(weekdaysArray,fWeekdays,count);
1090 fWeekdaysCount = count;
1091}
1092
1093void
1094DateFormatSymbols::setShortWeekdays(const UnicodeString* shortWeekdaysArray, int32_t count)
1095{
1096 // delete the old list if we own it
1097 delete[] fShortWeekdays;
1098
1099 // we always own the new list, which we create here (we duplicate rather
1100 // than adopting the list passed in)
1101 fShortWeekdays = newUnicodeStringArray(count);
1102 uprv_arrayCopy(shortWeekdaysArray, fShortWeekdays, count);
1103 fShortWeekdaysCount = count;
1104}
1105
1106void
1107DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count, DtContextType context, DtWidthType width)
1108{
1109 // delete the old list if we own it
1110 // we always own the new list, which we create here (we duplicate rather
1111 // than adopting the list passed in)
1112
1113 switch (context) {
1114 case FORMAT :
1115 switch (width) {
1116 case WIDE :
1117 delete[] fWeekdays;
1118 fWeekdays = newUnicodeStringArray(count);
1119 uprv_arrayCopy(weekdaysArray, fWeekdays, count);
1120 fWeekdaysCount = count;
1121 break;
1122 case ABBREVIATED :
1123 delete[] fShortWeekdays;
1124 fShortWeekdays = newUnicodeStringArray(count);
1125 uprv_arrayCopy(weekdaysArray, fShortWeekdays, count);
1126 fShortWeekdaysCount = count;
1127 break;
1128 case SHORT :
1129 delete[] fShorterWeekdays;
1130 fShorterWeekdays = newUnicodeStringArray(count);
1131 uprv_arrayCopy(weekdaysArray, fShorterWeekdays, count);
1132 fShorterWeekdaysCount = count;
1133 break;
1134 case NARROW :
1135 delete[] fNarrowWeekdays;
1136 fNarrowWeekdays = newUnicodeStringArray(count);
1137 uprv_arrayCopy(weekdaysArray, fNarrowWeekdays, count);
1138 fNarrowWeekdaysCount = count;
1139 break;
1140 case DT_WIDTH_COUNT :
1141 break;
1142 }
1143 break;
1144 case STANDALONE :
1145 switch (width) {
1146 case WIDE :
1147 delete[] fStandaloneWeekdays;
1148 fStandaloneWeekdays = newUnicodeStringArray(count);
1149 uprv_arrayCopy(weekdaysArray, fStandaloneWeekdays, count);
1150 fStandaloneWeekdaysCount = count;
1151 break;
1152 case ABBREVIATED :
1153 delete[] fStandaloneShortWeekdays;
1154 fStandaloneShortWeekdays = newUnicodeStringArray(count);
1155 uprv_arrayCopy(weekdaysArray, fStandaloneShortWeekdays, count);
1156 fStandaloneShortWeekdaysCount = count;
1157 break;
1158 case SHORT :
1159 delete[] fStandaloneShorterWeekdays;
1160 fStandaloneShorterWeekdays = newUnicodeStringArray(count);
1161 uprv_arrayCopy(weekdaysArray, fStandaloneShorterWeekdays, count);
1162 fStandaloneShorterWeekdaysCount = count;
1163 break;
1164 case NARROW :
1165 delete[] fStandaloneNarrowWeekdays;
1166 fStandaloneNarrowWeekdays = newUnicodeStringArray(count);
1167 uprv_arrayCopy(weekdaysArray, fStandaloneNarrowWeekdays, count);
1168 fStandaloneNarrowWeekdaysCount = count;
1169 break;
1170 case DT_WIDTH_COUNT :
1171 break;
1172 }
1173 break;
1174 case DT_CONTEXT_COUNT :
1175 break;
1176 }
1177}
1178
1179void
1180DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count, DtContextType context, DtWidthType width)
1181{
1182 // delete the old list if we own it
1183 // we always own the new list, which we create here (we duplicate rather
1184 // than adopting the list passed in)
1185
1186 switch (context) {
1187 case FORMAT :
1188 switch (width) {
1189 case WIDE :
1190 delete[] fQuarters;
1191 fQuarters = newUnicodeStringArray(count);
1192 uprv_arrayCopy( quartersArray,fQuarters,count);
1193 fQuartersCount = count;
1194 break;
1195 case ABBREVIATED :
1196 delete[] fShortQuarters;
1197 fShortQuarters = newUnicodeStringArray(count);
1198 uprv_arrayCopy( quartersArray,fShortQuarters,count);
1199 fShortQuartersCount = count;
1200 break;
1201 case NARROW :
1202 delete[] fNarrowQuarters;
1203 fNarrowQuarters = newUnicodeStringArray(count);
1204 uprv_arrayCopy( quartersArray,fNarrowQuarters,count);
1205 fNarrowQuartersCount = count;
1206 break;
1207 default :
1208 break;
1209 }
1210 break;
1211 case STANDALONE :
1212 switch (width) {
1213 case WIDE :
1214 delete[] fStandaloneQuarters;
1215 fStandaloneQuarters = newUnicodeStringArray(count);
1216 uprv_arrayCopy( quartersArray,fStandaloneQuarters,count);
1217 fStandaloneQuartersCount = count;
1218 break;
1219 case ABBREVIATED :
1220 delete[] fStandaloneShortQuarters;
1221 fStandaloneShortQuarters = newUnicodeStringArray(count);
1222 uprv_arrayCopy( quartersArray,fStandaloneShortQuarters,count);
1223 fStandaloneShortQuartersCount = count;
1224 break;
1225 case NARROW :
1226 delete[] fStandaloneNarrowQuarters;
1227 fStandaloneNarrowQuarters = newUnicodeStringArray(count);
1228 uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count);
1229 fStandaloneNarrowQuartersCount = count;
1230 break;
1231 default :
1232 break;
1233 }
1234 break;
1235 case DT_CONTEXT_COUNT :
1236 break;
1237 }
1238}
1239
1240void
1241DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count)
1242{
1243 // delete the old list if we own it
1244 delete[] fAmPms;
1245
1246 // we always own the new list, which we create here (we duplicate rather
1247 // than adopting the list passed in)
1248 fAmPms = newUnicodeStringArray(count);
1249 uprv_arrayCopy(amPmsArray,fAmPms,count);
1250 fAmPmsCount = count;
1251}
1252
1253void
1254DateFormatSymbols::setTimeSeparatorString(const UnicodeString& newTimeSeparator)
1255{
1256 fTimeSeparator = newTimeSeparator;
1257}
1258
1259const UnicodeString**
1260DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
1261{
1262 const UnicodeString **result = nullptr;
1263 static UMutex LOCK;
1264
1265 umtx_lockumtx_lock_77(&LOCK);
1266 if (fZoneStrings == nullptr) {
1267 if (fLocaleZoneStrings == nullptr) {
1268 const_cast<DateFormatSymbols*>(this)->initZoneStringsArray();
1269 }
1270 result = (const UnicodeString**)fLocaleZoneStrings;
1271 } else {
1272 result = (const UnicodeString**)fZoneStrings;
1273 }
1274 rowCount = fZoneStringsRowCount;
1275 columnCount = fZoneStringsColCount;
1276 umtx_unlockumtx_unlock_77(&LOCK);
1277
1278 return result;
1279}
1280
1281// For now, we include all zones
1282#define ZONE_SETUCAL_ZONE_TYPE_ANY UCAL_ZONE_TYPE_ANY
1283
1284// This code must be called within a synchronized block
1285void
1286DateFormatSymbols::initZoneStringsArray() {
1287 if (fZoneStrings != nullptr || fLocaleZoneStrings != nullptr) {
1288 return;
1289 }
1290
1291 UErrorCode status = U_ZERO_ERROR;
1292
1293 StringEnumeration *tzids = nullptr;
1294 UnicodeString ** zarray = nullptr;
1295 TimeZoneNames *tzNames = nullptr;
1296 int32_t rows = 0;
1297
1298 static const UTimeZoneNameType TYPES[] = {
1299 UTZNM_LONG_STANDARD, UTZNM_SHORT_STANDARD,
1300 UTZNM_LONG_DAYLIGHT, UTZNM_SHORT_DAYLIGHT
1301 };
1302 static const int32_t NUM_TYPES = 4;
1303
1304 do { // dummy do-while
1305
1306 tzids = TimeZone::createTimeZoneIDEnumeration(ZONE_SETUCAL_ZONE_TYPE_ANY, nullptr, nullptr, status);
1307 rows = tzids->count(status);
1308 if (U_FAILURE(status)) {
1309 break;
1310 }
1311
1312 // Allocate array
1313 int32_t size = rows * sizeof(UnicodeString*);
1314 zarray = static_cast<UnicodeString**>(uprv_mallocuprv_malloc_77(size));
1315 if (zarray == nullptr) {
1316 status = U_MEMORY_ALLOCATION_ERROR;
1317 break;
1318 }
1319 uprv_memset(zarray, 0, size):: memset(zarray, 0, size);
1320
1321 tzNames = TimeZoneNames::createInstance(fZSFLocale, status);
1322 tzNames->loadAllDisplayNames(status);
1323 if (U_FAILURE(status)) { break; }
1324
1325 const UnicodeString *tzid;
1326 int32_t i = 0;
1327 UDate now = Calendar::getNow();
1328 UnicodeString tzDispName;
1329
1330 while ((tzid = tzids->snext(status)) != nullptr) {
1331 if (U_FAILURE(status)) {
1332 break;
1333 }
1334
1335 zarray[i] = new UnicodeString[5];
1336 if (zarray[i] == nullptr) {
1337 status = U_MEMORY_ALLOCATION_ERROR;
1338 break;
1339 }
1340
1341 zarray[i][0].setTo(*tzid);
1342 tzNames->getDisplayNames(*tzid, TYPES, NUM_TYPES, now, zarray[i]+1, status);
1343 i++;
1344 }
1345
1346 } while (false);
1347
1348 if (U_FAILURE(status)) {
1349 if (zarray) {
1350 for (int32_t i = 0; i < rows; i++) {
1351 if (zarray[i]) {
1352 delete[] zarray[i];
1353 }
1354 }
1355 uprv_freeuprv_free_77(zarray);
1356 zarray = nullptr;
1357 }
1358 }
1359
1360 delete tzNames;
1361 delete tzids;
1362
1363 fLocaleZoneStrings = zarray;
1364 fZoneStringsRowCount = rows;
1365 fZoneStringsColCount = 1 + NUM_TYPES;
1366}
1367
1368void
1369DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t rowCount, int32_t columnCount)
1370{
1371 // since deleting a 2-d array is a pain in the butt, we offload that task to
1372 // a separate function
1373 disposeZoneStrings();
1374 // we always own the new list, which we create here (we duplicate rather
1375 // than adopting the list passed in)
1376 fZoneStringsRowCount = rowCount;
1377 fZoneStringsColCount = columnCount;
1378 createZoneStrings(const_cast<const UnicodeString**>(strings));
1379}
1380
1381//------------------------------------------------------
1382
1383const char16_t * U_EXPORT2
1384DateFormatSymbols::getPatternUChars()
1385{
1386 return gPatternChars;
1387}
1388
1389UDateFormatField U_EXPORT2
1390DateFormatSymbols::getPatternCharIndex(char16_t c) {
1391 if (c >= UPRV_LENGTHOF(gLookupPatternChars)(int32_t)(sizeof(gLookupPatternChars)/sizeof((gLookupPatternChars
)[0]))
) {
1392 return UDAT_FIELD_COUNT;
1393 }
1394 const auto idx = gLookupPatternChars[c];
1395 return idx == -1 ? UDAT_FIELD_COUNT : static_cast<UDateFormatField>(idx);
1396}
1397
1398static const uint64_t kNumericFieldsAlways =
1399 (static_cast<uint64_t>(1) << UDAT_YEAR_FIELD) | // y
1400 (static_cast<uint64_t>(1) << UDAT_DATE_FIELD) | // d
1401 (static_cast<uint64_t>(1) << UDAT_HOUR_OF_DAY1_FIELD) | // k
1402 (static_cast<uint64_t>(1) << UDAT_HOUR_OF_DAY0_FIELD) | // H
1403 (static_cast<uint64_t>(1) << UDAT_MINUTE_FIELD) | // m
1404 (static_cast<uint64_t>(1) << UDAT_SECOND_FIELD) | // s
1405 (static_cast<uint64_t>(1) << UDAT_FRACTIONAL_SECOND_FIELD) | // S
1406 (static_cast<uint64_t>(1) << UDAT_DAY_OF_YEAR_FIELD) | // D
1407 (static_cast<uint64_t>(1) << UDAT_DAY_OF_WEEK_IN_MONTH_FIELD) | // F
1408 (static_cast<uint64_t>(1) << UDAT_WEEK_OF_YEAR_FIELD) | // w
1409 (static_cast<uint64_t>(1) << UDAT_WEEK_OF_MONTH_FIELD) | // W
1410 (static_cast<uint64_t>(1) << UDAT_HOUR1_FIELD) | // h
1411 (static_cast<uint64_t>(1) << UDAT_HOUR0_FIELD) | // K
1412 (static_cast<uint64_t>(1) << UDAT_YEAR_WOY_FIELD) | // Y
1413 (static_cast<uint64_t>(1) << UDAT_EXTENDED_YEAR_FIELD) | // u
1414 (static_cast<uint64_t>(1) << UDAT_JULIAN_DAY_FIELD) | // g
1415 (static_cast<uint64_t>(1) << UDAT_MILLISECONDS_IN_DAY_FIELD) | // A
1416 (static_cast<uint64_t>(1) << UDAT_RELATED_YEAR_FIELD); // r
1417
1418static const uint64_t kNumericFieldsForCount12 =
1419 (static_cast<uint64_t>(1) << UDAT_MONTH_FIELD) | // M or MM
1420 (static_cast<uint64_t>(1) << UDAT_DOW_LOCAL_FIELD) | // e or ee
1421 (static_cast<uint64_t>(1) << UDAT_STANDALONE_DAY_FIELD) | // c or cc
1422 (static_cast<uint64_t>(1) << UDAT_STANDALONE_MONTH_FIELD) | // L or LL
1423 (static_cast<uint64_t>(1) << UDAT_QUARTER_FIELD) | // Q or QQ
1424 (static_cast<uint64_t>(1) << UDAT_STANDALONE_QUARTER_FIELD); // q or qq
1425
1426UBool U_EXPORT2
1427DateFormatSymbols::isNumericField(UDateFormatField f, int32_t count) {
1428 if (f == UDAT_FIELD_COUNT) {
1429 return false;
1430 }
1431 uint64_t flag = static_cast<uint64_t>(1) << f;
1432 return ((kNumericFieldsAlways & flag) != 0 || ((kNumericFieldsForCount12 & flag) != 0 && count < 3));
1433}
1434
1435UBool U_EXPORT2
1436DateFormatSymbols::isNumericPatternChar(char16_t c, int32_t count) {
1437 return isNumericField(getPatternCharIndex(c), count);
1438}
1439
1440//------------------------------------------------------
1441
1442UnicodeString&
1443DateFormatSymbols::getLocalPatternChars(UnicodeString& result) const
1444{
1445 // fastCopyFrom() - see assignArray comments
1446 return result.fastCopyFrom(fLocalPatternChars);
1447}
1448
1449//------------------------------------------------------
1450
1451void
1452DateFormatSymbols::setLocalPatternChars(const UnicodeString& newLocalPatternChars)
1453{
1454 fLocalPatternChars = newLocalPatternChars;
1455}
1456
1457//------------------------------------------------------
1458
1459namespace {
1460
1461// Constants declarations
1462const char16_t kCalendarAliasPrefixUChar[] = {
1463 SOLIDUS((char16_t)0x002F), CAP_L((char16_t)0x004C), CAP_O((char16_t)0x004F), CAP_C((char16_t)0x0043), CAP_A((char16_t)0x0041), CAP_L((char16_t)0x004C), CAP_E((char16_t)0x0045), SOLIDUS((char16_t)0x002F),
1464 LOW_C((char16_t)0x0063), LOW_A((char16_t)0x0061), LOW_L((char16_t)0x006C), LOW_E((char16_t)0x0065), LOW_N((char16_t)0x006E), LOW_D((char16_t)0x0064), LOW_A((char16_t)0x0061), LOW_R((char16_t)0x0072), SOLIDUS((char16_t)0x002F)
1465};
1466const char16_t kGregorianTagUChar[] = {
1467 LOW_G((char16_t)0x0067), LOW_R((char16_t)0x0072), LOW_E((char16_t)0x0065), LOW_G((char16_t)0x0067), LOW_O((char16_t)0x006F), LOW_R((char16_t)0x0072), LOW_I((char16_t)0x0069), LOW_A((char16_t)0x0061), LOW_N((char16_t)0x006E)
1468};
1469const char16_t kVariantTagUChar[] = {
1470 PERCENT((char16_t)0x0025), LOW_V((char16_t)0x0076), LOW_A((char16_t)0x0061), LOW_R((char16_t)0x0072), LOW_I((char16_t)0x0069), LOW_A((char16_t)0x0061), LOW_N((char16_t)0x006E), LOW_T((char16_t)0x0074)
1471};
1472const char16_t kLeapTagUChar[] = {
1473 LOW_L((char16_t)0x006C), LOW_E((char16_t)0x0065), LOW_A((char16_t)0x0061), LOW_P((char16_t)0x0070)
1474};
1475const char16_t kCyclicNameSetsTagUChar[] = {
1476 LOW_C((char16_t)0x0063), LOW_Y((char16_t)0x0079), LOW_C((char16_t)0x0063), LOW_L((char16_t)0x006C), LOW_I((char16_t)0x0069), LOW_C((char16_t)0x0063), CAP_N((char16_t)0x004E), LOW_A((char16_t)0x0061), LOW_M((char16_t)0x006D), LOW_E((char16_t)0x0065), CAP_S((char16_t)0x0053), LOW_E((char16_t)0x0065), LOW_T((char16_t)0x0074), LOW_S((char16_t)0x0073)
1477};
1478const char16_t kYearsTagUChar[] = {
1479 SOLIDUS((char16_t)0x002F), LOW_Y((char16_t)0x0079), LOW_E((char16_t)0x0065), LOW_A((char16_t)0x0061), LOW_R((char16_t)0x0072), LOW_S((char16_t)0x0073)
1480};
1481const char16_t kZodiacsUChar[] = {
1482 SOLIDUS((char16_t)0x002F), LOW_Z((char16_t)0x007A), LOW_O((char16_t)0x006F), LOW_D((char16_t)0x0064), LOW_I((char16_t)0x0069), LOW_A((char16_t)0x0061), LOW_C((char16_t)0x0063), LOW_S((char16_t)0x0073)
1483};
1484const char16_t kDayPartsTagUChar[] = {
1485 SOLIDUS((char16_t)0x002F), LOW_D((char16_t)0x0064), LOW_A((char16_t)0x0061), LOW_Y((char16_t)0x0079), CAP_P((char16_t)0x0050), LOW_A((char16_t)0x0061), LOW_R((char16_t)0x0072), LOW_T((char16_t)0x0074), LOW_S((char16_t)0x0073)
1486};
1487const char16_t kFormatTagUChar[] = {
1488 SOLIDUS((char16_t)0x002F), LOW_F((char16_t)0x0066), LOW_O((char16_t)0x006F), LOW_R((char16_t)0x0072), LOW_M((char16_t)0x006D), LOW_A((char16_t)0x0061), LOW_T((char16_t)0x0074)
1489};
1490const char16_t kAbbrTagUChar[] = {
1491 SOLIDUS((char16_t)0x002F), LOW_A((char16_t)0x0061), LOW_B((char16_t)0x0062), LOW_B((char16_t)0x0062), LOW_R((char16_t)0x0072), LOW_E((char16_t)0x0065), LOW_V((char16_t)0x0076), LOW_I((char16_t)0x0069), LOW_A((char16_t)0x0061), LOW_T((char16_t)0x0074), LOW_E((char16_t)0x0065), LOW_D((char16_t)0x0064)
1492};
1493
1494// ResourceSink to enumerate all calendar resources
1495struct CalendarDataSink : public ResourceSink {
1496
1497 // Enum which specifies the type of alias received, or no alias
1498 enum AliasType {
1499 SAME_CALENDAR,
1500 DIFFERENT_CALENDAR,
1501 GREGORIAN,
1502 NONE
1503 };
1504
1505 // Data structures to store resources from the current resource bundle
1506 Hashtable arrays;
1507 Hashtable arraySizes;
1508 Hashtable maps;
1509 /**
1510 * Whenever there are aliases, the same object will be added twice to 'map'.
1511 * To avoid double deletion, 'maps' won't take ownership of the objects. Instead,
1512 * 'mapRefs' will own them and will delete them when CalendarDataSink is deleted.
1513 */
1514 MemoryPool<Hashtable> mapRefs;
1515
1516 // Paths and the aliases they point to
1517 UVector aliasPathPairs;
1518
1519 // Current and next calendar resource table which should be loaded
1520 UnicodeString currentCalendarType;
1521 UnicodeString nextCalendarType;
1522
1523 // Resources to visit when enumerating fallback calendars
1524 LocalPointer<UVector> resourcesToVisit;
1525
1526 // Alias' relative path populated whenever an alias is read
1527 UnicodeString aliasRelativePath;
1528
1529 // Initializes CalendarDataSink with default values
1530 CalendarDataSink(UErrorCode& status)
1531 : arrays(false, status), arraySizes(false, status), maps(false, status),
1532 mapRefs(),
1533 aliasPathPairs(uprv_deleteUObjectuprv_deleteUObject_77, uhash_compareUnicodeStringuhash_compareUnicodeString_77, status),
1534 currentCalendarType(), nextCalendarType(),
1535 resourcesToVisit(nullptr), aliasRelativePath() {
1536 if (U_FAILURE(status)) { return; }
1537 }
1538 virtual ~CalendarDataSink();
1539
1540 // Configure the CalendarSink to visit all the resources
1541 void visitAllResources() {
1542 resourcesToVisit.adoptInstead(nullptr);
1543 }
1544
1545 // Actions to be done before enumerating
1546 void preEnumerate(const UnicodeString &calendarType) {
1547 currentCalendarType = calendarType;
1548 nextCalendarType.setToBogus();
1549 aliasPathPairs.removeAllElements();
1550 }
1551
1552 virtual void put(const char *key, ResourceValue &value, UBool, UErrorCode &errorCode) override {
1553 if (U_FAILURE(errorCode)) { return; }
1554 U_ASSERT(!currentCalendarType.isEmpty())(static_cast <bool> (!currentCalendarType.isEmpty()) ? void
(0) : __assert_fail ("!currentCalendarType.isEmpty()", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
1555
1556 // Stores the resources to visit on the next calendar.
1557 LocalPointer<UVector> resourcesToVisitNext(nullptr);
1558 ResourceTable calendarData = value.getTable(errorCode);
1559 if (U_FAILURE(errorCode)) { return; }
1560
1561 // Enumerate all resources for this calendar
1562 for (int i = 0; calendarData.getKeyAndValue(i, key, value); i++) {
1563 UnicodeString keyUString(key, -1, US_INVicu::UnicodeString::kInvariant);
1564
1565 // == Handle aliases ==
1566 AliasType aliasType = processAliasFromValue(keyUString, value, errorCode);
1567 if (U_FAILURE(errorCode)) { return; }
1568 if (aliasType == GREGORIAN) {
1569 // Ignore aliases to the gregorian calendar, all of its resources will be loaded anyway.
1570 continue;
1571
1572 } else if (aliasType == DIFFERENT_CALENDAR) {
1573 // Whenever an alias to the next calendar (except gregorian) is encountered, register the
1574 // calendar type it's pointing to
1575 if (resourcesToVisitNext.isNull()) {
1576 resourcesToVisitNext
1577 .adoptInsteadAndCheckErrorCode(new UVector(uprv_deleteUObjectuprv_deleteUObject_77, uhash_compareUnicodeStringuhash_compareUnicodeString_77, errorCode),
1578 errorCode);
1579 if (U_FAILURE(errorCode)) { return; }
1580 }
1581 LocalPointer<UnicodeString> aliasRelativePathCopy(aliasRelativePath.clone(), errorCode);
1582 resourcesToVisitNext->adoptElement(aliasRelativePathCopy.orphan(), errorCode);
1583 if (U_FAILURE(errorCode)) { return; }
1584 continue;
1585
1586 } else if (aliasType == SAME_CALENDAR) {
1587 // Register same-calendar alias
1588 if (arrays.get(aliasRelativePath) == nullptr && maps.get(aliasRelativePath) == nullptr) {
1589 LocalPointer<UnicodeString> aliasRelativePathCopy(aliasRelativePath.clone(), errorCode);
1590 aliasPathPairs.adoptElement(aliasRelativePathCopy.orphan(), errorCode);
1591 if (U_FAILURE(errorCode)) { return; }
1592 LocalPointer<UnicodeString> keyUStringCopy(keyUString.clone(), errorCode);
1593 aliasPathPairs.adoptElement(keyUStringCopy.orphan(), errorCode);
1594 if (U_FAILURE(errorCode)) { return; }
1595 }
1596 continue;
1597 }
1598
1599 // Only visit the resources that were referenced by an alias on the previous calendar
1600 // (AmPmMarkersAbbr is an exception).
1601 if (!resourcesToVisit.isNull() && !resourcesToVisit->isEmpty() && !resourcesToVisit->contains(&keyUString)
1602 && uprv_strcmp(key, gAmPmMarkersAbbrTag):: strcmp(key, gAmPmMarkersAbbrTag) != 0) { continue; }
1603
1604 // == Handle data ==
1605 if (uprv_strcmp(key, gAmPmMarkersTag):: strcmp(key, gAmPmMarkersTag) == 0
1606 || uprv_strcmp(key, gAmPmMarkersAbbrTag):: strcmp(key, gAmPmMarkersAbbrTag) == 0
1607 || uprv_strcmp(key, gAmPmMarkersNarrowTag):: strcmp(key, gAmPmMarkersNarrowTag) == 0) {
1608 if (arrays.get(keyUString) == nullptr) {
1609 ResourceArray resourceArray = value.getArray(errorCode);
1610 int32_t arraySize = resourceArray.getSize();
1611 LocalArray<UnicodeString> stringArray(new UnicodeString[arraySize], errorCode);
1612 value.getStringArray(stringArray.getAlias(), arraySize, errorCode);
1613 arrays.put(keyUString, stringArray.orphan(), errorCode);
1614 arraySizes.puti(keyUString, arraySize, errorCode);
1615 if (U_FAILURE(errorCode)) { return; }
1616 }
1617 } else if (uprv_strcmp(key, gErasTag):: strcmp(key, gErasTag) == 0
1618 || uprv_strcmp(key, gDayNamesTag):: strcmp(key, gDayNamesTag) == 0
1619 || uprv_strcmp(key, gMonthNamesTag):: strcmp(key, gMonthNamesTag) == 0
1620 || uprv_strcmp(key, gQuartersTag):: strcmp(key, gQuartersTag) == 0
1621 || uprv_strcmp(key, gDayPeriodTag):: strcmp(key, gDayPeriodTag) == 0
1622 || uprv_strcmp(key, gMonthPatternsTag):: strcmp(key, gMonthPatternsTag) == 0
1623 || uprv_strcmp(key, gCyclicNameSetsTag):: strcmp(key, gCyclicNameSetsTag) == 0) {
1624 processResource(keyUString, key, value, errorCode);
1625 }
1626 }
1627
1628 // Apply same-calendar aliases
1629 UBool modified;
1630 do {
1631 modified = false;
1632 for (int32_t i = 0; i < aliasPathPairs.size();) {
1633 UBool mod = false;
1634 UnicodeString* alias = static_cast<UnicodeString*>(aliasPathPairs[i]);
1635 UnicodeString *aliasArray;
1636 Hashtable *aliasMap;
1637 if ((aliasArray = static_cast<UnicodeString*>(arrays.get(*alias))) != nullptr) {
1638 UnicodeString* path = static_cast<UnicodeString*>(aliasPathPairs[i + 1]);
1639 if (arrays.get(*path) == nullptr) {
1640 // Clone the array
1641 int32_t aliasArraySize = arraySizes.geti(*alias);
1642 LocalArray<UnicodeString> aliasArrayCopy(new UnicodeString[aliasArraySize], errorCode);
1643 if (U_FAILURE(errorCode)) { return; }
1644 uprv_arrayCopy(aliasArray, aliasArrayCopy.getAlias(), aliasArraySize);
1645 // Put the array on the 'arrays' map
1646 arrays.put(*path, aliasArrayCopy.orphan(), errorCode);
1647 arraySizes.puti(*path, aliasArraySize, errorCode);
1648 }
1649 if (U_FAILURE(errorCode)) { return; }
1650 mod = true;
1651 } else if ((aliasMap = static_cast<Hashtable*>(maps.get(*alias))) != nullptr) {
1652 UnicodeString* path = static_cast<UnicodeString*>(aliasPathPairs[i + 1]);
1653 if (maps.get(*path) == nullptr) {
1654 maps.put(*path, aliasMap, errorCode);
1655 }
1656 if (U_FAILURE(errorCode)) { return; }
1657 mod = true;
1658 }
1659 if (mod) {
1660 aliasPathPairs.removeElementAt(i + 1);
1661 aliasPathPairs.removeElementAt(i);
1662 modified = true;
1663 } else {
1664 i += 2;
1665 }
1666 }
1667 } while (modified && !aliasPathPairs.isEmpty());
1668
1669 // Set the resources to visit on the next calendar
1670 if (!resourcesToVisitNext.isNull()) {
1671 resourcesToVisit = std::move(resourcesToVisitNext);
1672 }
1673 }
1674
1675 // Process the nested resource bundle tables
1676 void processResource(UnicodeString &path, const char *key, ResourceValue &value, UErrorCode &errorCode) {
1677 if (U_FAILURE(errorCode)) return;
1678
1679 ResourceTable table = value.getTable(errorCode);
1680 if (U_FAILURE(errorCode)) return;
1681 Hashtable* stringMap = nullptr;
1682
1683 // Iterate over all the elements of the table and add them to the map
1684 for (int i = 0; table.getKeyAndValue(i, key, value); i++) {
1685 UnicodeString keyUString(key, -1, US_INVicu::UnicodeString::kInvariant);
1686
1687 // Ignore '%variant' keys
1688 if (keyUString.endsWith(kVariantTagUChar, UPRV_LENGTHOF(kVariantTagUChar)(int32_t)(sizeof(kVariantTagUChar)/sizeof((kVariantTagUChar)[
0]))
)) {
1689 continue;
1690 }
1691
1692 // == Handle String elements ==
1693 if (value.getType() == URES_STRING) {
1694 // We are on a leaf, store the map elements into the stringMap
1695 if (i == 0) {
1696 // mapRefs will keep ownership of 'stringMap':
1697 stringMap = mapRefs.create(false, errorCode);
1698 if (stringMap == nullptr) {
1699 errorCode = U_MEMORY_ALLOCATION_ERROR;
1700 return;
1701 }
1702 maps.put(path, stringMap, errorCode);
1703 if (U_FAILURE(errorCode)) { return; }
1704 stringMap->setValueDeleter(uprv_deleteUObjectuprv_deleteUObject_77);
1705 }
1706 U_ASSERT(stringMap != nullptr)(static_cast <bool> (stringMap != nullptr) ? void (0) :
__assert_fail ("stringMap != nullptr", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
1707 int32_t valueStringSize;
1708 const char16_t *valueString = value.getString(valueStringSize, errorCode);
1709 if (U_FAILURE(errorCode)) { return; }
1710 LocalPointer<UnicodeString> valueUString(new UnicodeString(true, valueString, valueStringSize), errorCode);
1711 stringMap->put(keyUString, valueUString.orphan(), errorCode);
1712 if (U_FAILURE(errorCode)) { return; }
1713 continue;
1714 }
1715 U_ASSERT(stringMap == nullptr)(static_cast <bool> (stringMap == nullptr) ? void (0) :
__assert_fail ("stringMap == nullptr", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
1716
1717 // Store the current path's length and append the current key to the path.
1718 int32_t pathLength = path.length();
1719 path.append(SOLIDUS((char16_t)0x002F)).append(keyUString);
1720
1721 // In cyclicNameSets ignore everything but years/format/abbreviated
1722 // and zodiacs/format/abbreviated
1723 if (path.startsWith(kCyclicNameSetsTagUChar, UPRV_LENGTHOF(kCyclicNameSetsTagUChar)(int32_t)(sizeof(kCyclicNameSetsTagUChar)/sizeof((kCyclicNameSetsTagUChar
)[0]))
)) {
1724 UBool skip = true;
1725 int32_t startIndex = UPRV_LENGTHOF(kCyclicNameSetsTagUChar)(int32_t)(sizeof(kCyclicNameSetsTagUChar)/sizeof((kCyclicNameSetsTagUChar
)[0]))
;
1726 int32_t length = 0;
1727 if (startIndex == path.length()
1728 || path.compare(startIndex, (length = UPRV_LENGTHOF(kZodiacsUChar)(int32_t)(sizeof(kZodiacsUChar)/sizeof((kZodiacsUChar)[0]))), kZodiacsUChar, 0, UPRV_LENGTHOF(kZodiacsUChar)(int32_t)(sizeof(kZodiacsUChar)/sizeof((kZodiacsUChar)[0]))) == 0
1729 || path.compare(startIndex, (length = UPRV_LENGTHOF(kYearsTagUChar)(int32_t)(sizeof(kYearsTagUChar)/sizeof((kYearsTagUChar)[0]))), kYearsTagUChar, 0, UPRV_LENGTHOF(kYearsTagUChar)(int32_t)(sizeof(kYearsTagUChar)/sizeof((kYearsTagUChar)[0]))) == 0
1730 || path.compare(startIndex, (length = UPRV_LENGTHOF(kDayPartsTagUChar)(int32_t)(sizeof(kDayPartsTagUChar)/sizeof((kDayPartsTagUChar
)[0]))
), kDayPartsTagUChar, 0, UPRV_LENGTHOF(kDayPartsTagUChar)(int32_t)(sizeof(kDayPartsTagUChar)/sizeof((kDayPartsTagUChar
)[0]))
) == 0) {
1731 startIndex += length;
1732 length = 0;
1733 if (startIndex == path.length()
1734 || path.compare(startIndex, (length = UPRV_LENGTHOF(kFormatTagUChar)(int32_t)(sizeof(kFormatTagUChar)/sizeof((kFormatTagUChar)[0]
))
), kFormatTagUChar, 0, UPRV_LENGTHOF(kFormatTagUChar)(int32_t)(sizeof(kFormatTagUChar)/sizeof((kFormatTagUChar)[0]
))
) == 0) {
1735 startIndex += length;
1736 length = 0;
1737 if (startIndex == path.length()
1738 || path.compare(startIndex, (length = UPRV_LENGTHOF(kAbbrTagUChar)(int32_t)(sizeof(kAbbrTagUChar)/sizeof((kAbbrTagUChar)[0]))), kAbbrTagUChar, 0, UPRV_LENGTHOF(kAbbrTagUChar)(int32_t)(sizeof(kAbbrTagUChar)/sizeof((kAbbrTagUChar)[0]))) == 0) {
1739 skip = false;
1740 }
1741 }
1742 }
1743 if (skip) {
1744 // Drop the latest key on the path and continue
1745 path.retainBetween(0, pathLength);
1746 continue;
1747 }
1748 }
1749
1750 // == Handle aliases ==
1751 if (arrays.get(path) != nullptr || maps.get(path) != nullptr) {
1752 // Drop the latest key on the path and continue
1753 path.retainBetween(0, pathLength);
1754 continue;
1755 }
1756
1757 AliasType aliasType = processAliasFromValue(path, value, errorCode);
1758 if (U_FAILURE(errorCode)) { return; }
1759 if (aliasType == SAME_CALENDAR) {
1760 // Store the alias path and the current path on aliasPathPairs
1761 LocalPointer<UnicodeString> aliasRelativePathCopy(aliasRelativePath.clone(), errorCode);
1762 aliasPathPairs.adoptElement(aliasRelativePathCopy.orphan(), errorCode);
1763 if (U_FAILURE(errorCode)) { return; }
1764 LocalPointer<UnicodeString> pathCopy(path.clone(), errorCode);
1765 aliasPathPairs.adoptElement(pathCopy.orphan(), errorCode);
1766 if (U_FAILURE(errorCode)) { return; }
1767
1768 // Drop the latest key on the path and continue
1769 path.retainBetween(0, pathLength);
1770 continue;
1771 }
1772 U_ASSERT(aliasType == NONE)(static_cast <bool> (aliasType == NONE) ? void (0) : __assert_fail
("aliasType == NONE", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1773
1774 // == Handle data ==
1775 if (value.getType() == URES_ARRAY) {
1776 // We are on a leaf, store the array
1777 ResourceArray rDataArray = value.getArray(errorCode);
1778 int32_t dataArraySize = rDataArray.getSize();
1779 LocalArray<UnicodeString> dataArray(new UnicodeString[dataArraySize], errorCode);
1780 value.getStringArray(dataArray.getAlias(), dataArraySize, errorCode);
1781 arrays.put(path, dataArray.orphan(), errorCode);
1782 arraySizes.puti(path, dataArraySize, errorCode);
1783 if (U_FAILURE(errorCode)) { return; }
1784 } else if (value.getType() == URES_TABLE) {
1785 // We are not on a leaf, recursively process the subtable.
1786 processResource(path, key, value, errorCode);
1787 if (U_FAILURE(errorCode)) { return; }
1788 }
1789
1790 // Drop the latest key on the path
1791 path.retainBetween(0, pathLength);
1792 }
1793 }
1794
1795 // Populates an AliasIdentifier with the alias information contained on the UResource.Value.
1796 AliasType processAliasFromValue(UnicodeString &currentRelativePath, ResourceValue &value,
1797 UErrorCode &errorCode) {
1798 if (U_FAILURE(errorCode)) { return NONE; }
1799
1800 if (value.getType() == URES_ALIAS) {
1801 int32_t aliasPathSize;
1802 const char16_t* aliasPathUChar = value.getAliasString(aliasPathSize, errorCode);
1803 if (U_FAILURE(errorCode)) { return NONE; }
1804 UnicodeString aliasPath(aliasPathUChar, aliasPathSize);
1805 const int32_t aliasPrefixLength = UPRV_LENGTHOF(kCalendarAliasPrefixUChar)(int32_t)(sizeof(kCalendarAliasPrefixUChar)/sizeof((kCalendarAliasPrefixUChar
)[0]))
;
1806 if (aliasPath.startsWith(kCalendarAliasPrefixUChar, aliasPrefixLength)
1807 && aliasPath.length() > aliasPrefixLength) {
1808 int32_t typeLimit = aliasPath.indexOf(SOLIDUS((char16_t)0x002F), aliasPrefixLength);
1809 if (typeLimit > aliasPrefixLength) {
1810 const UnicodeString aliasCalendarType =
1811 aliasPath.tempSubStringBetween(aliasPrefixLength, typeLimit);
1812 aliasRelativePath.setTo(aliasPath, typeLimit + 1, aliasPath.length());
1813
1814 if (currentCalendarType == aliasCalendarType
1815 && currentRelativePath != aliasRelativePath) {
1816 // If we have an alias to the same calendar, the path to the resource must be different
1817 return SAME_CALENDAR;
1818
1819 } else if (currentCalendarType != aliasCalendarType
1820 && currentRelativePath == aliasRelativePath) {
1821 // If we have an alias to a different calendar, the path to the resource must be the same
1822 if (aliasCalendarType.compare(kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)(int32_t)(sizeof(kGregorianTagUChar)/sizeof((kGregorianTagUChar
)[0]))
) == 0) {
1823 return GREGORIAN;
1824 } else if (nextCalendarType.isBogus()) {
1825 nextCalendarType = aliasCalendarType;
1826 return DIFFERENT_CALENDAR;
1827 } else if (nextCalendarType == aliasCalendarType) {
1828 return DIFFERENT_CALENDAR;
1829 }
1830 }
1831 }
1832 }
1833 errorCode = U_INTERNAL_PROGRAM_ERROR;
1834 return NONE;
1835 }
1836 return NONE;
1837 }
1838
1839 // Deleter function to be used by 'arrays'
1840 static void U_CALLCONV deleteUnicodeStringArray(void *uArray) {
1841 delete[] static_cast<UnicodeString *>(uArray);
1842 }
1843};
1844// Virtual destructors have to be defined out of line
1845CalendarDataSink::~CalendarDataSink() {
1846 arrays.setValueDeleter(deleteUnicodeStringArray);
1847}
1848}
1849
1850//------------------------------------------------------
1851
1852static void
1853initField(UnicodeString **field, int32_t& length, const char16_t *data, LastResortSize numStr, LastResortSize strLen, UErrorCode &status) {
1854 if (U_SUCCESS(status)) {
1855 length = numStr;
1856 *field = newUnicodeStringArray(static_cast<size_t>(numStr));
1857 if (*field) {
1858 for(int32_t i = 0; i<length; i++) {
1859 // readonly aliases - all "data" strings are constant
1860 // -1 as length for variable-length strings (gLastResortDayNames[0] is empty)
1861 (*(field) + i)->setTo(true, data + (i * (static_cast<int32_t>(strLen))), -1);
1862 }
1863 }
1864 else {
1865 length = 0;
1866 status = U_MEMORY_ALLOCATION_ERROR;
1867 }
1868 }
1869}
1870
1871static void
1872initField(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, UErrorCode &status) {
1873 if (U_SUCCESS(status)) {
1874 UnicodeString keyUString(key.data(), -1, US_INVicu::UnicodeString::kInvariant);
1875 UnicodeString* array = static_cast<UnicodeString*>(sink.arrays.get(keyUString));
1876
1877 if (array != nullptr) {
1878 length = sink.arraySizes.geti(keyUString);
1879 *field = array;
1880 // DateFormatSymbols takes ownership of the array:
1881 sink.arrays.remove(keyUString);
1882 } else {
1883 length = 0;
1884 status = U_MISSING_RESOURCE_ERROR;
1885 }
1886 }
1887}
1888
1889static void
1890initField(UnicodeString **field, int32_t& length, CalendarDataSink &sink, CharString &key, int32_t arrayOffset, UErrorCode &status) {
1891 if (U_SUCCESS(status)) {
1892 UnicodeString keyUString(key.data(), -1, US_INVicu::UnicodeString::kInvariant);
1893 UnicodeString* array = static_cast<UnicodeString*>(sink.arrays.get(keyUString));
1894
1895 if (array != nullptr) {
1896 int32_t arrayLength = sink.arraySizes.geti(keyUString);
1897 length = arrayLength + arrayOffset;
1898 *field = new UnicodeString[length];
1899 if (*field == nullptr) {
1900 status = U_MEMORY_ALLOCATION_ERROR;
1901 return;
1902 }
1903 uprv_arrayCopy(array, 0, *field, arrayOffset, arrayLength);
1904 } else {
1905 length = 0;
1906 status = U_MISSING_RESOURCE_ERROR;
1907 }
1908 }
1909}
1910
1911static void
1912initLeapMonthPattern(UnicodeString *field, int32_t index, CalendarDataSink &sink, CharString &path, UErrorCode &status) {
1913 field[index].remove();
1914 if (U_SUCCESS(status)) {
1915 UnicodeString pathUString(path.data(), -1, US_INVicu::UnicodeString::kInvariant);
1916 Hashtable *leapMonthTable = static_cast<Hashtable*>(sink.maps.get(pathUString));
1917 if (leapMonthTable != nullptr) {
1918 UnicodeString leapLabel(false, kLeapTagUChar, UPRV_LENGTHOF(kLeapTagUChar)(int32_t)(sizeof(kLeapTagUChar)/sizeof((kLeapTagUChar)[0])));
1919 UnicodeString *leapMonthPattern = static_cast<UnicodeString*>(leapMonthTable->get(leapLabel));
1920 if (leapMonthPattern != nullptr) {
1921 field[index].fastCopyFrom(*leapMonthPattern);
1922 } else {
1923 field[index].setToBogus();
1924 }
1925 return;
1926 }
1927 status = U_MISSING_RESOURCE_ERROR;
1928 }
1929}
1930
1931static CharString
1932&buildResourcePath(CharString &path, const char* segment1, UErrorCode &errorCode) {
1933 return path.clear().append(segment1, -1, errorCode);
1934}
1935
1936static CharString
1937&buildResourcePath(CharString &path, const char* segment1, const char* segment2,
1938 UErrorCode &errorCode) {
1939 return buildResourcePath(path, segment1, errorCode).append('/', errorCode)
1940 .append(segment2, -1, errorCode);
1941}
1942
1943static CharString
1944&buildResourcePath(CharString &path, const char* segment1, const char* segment2,
1945 const char* segment3, UErrorCode &errorCode) {
1946 return buildResourcePath(path, segment1, segment2, errorCode).append('/', errorCode)
1947 .append(segment3, -1, errorCode);
1948}
1949
1950static CharString
1951&buildResourcePath(CharString &path, const char* segment1, const char* segment2,
1952 const char* segment3, const char* segment4, UErrorCode &errorCode) {
1953 return buildResourcePath(path, segment1, segment2, segment3, errorCode).append('/', errorCode)
1954 .append(segment4, -1, errorCode);
1955}
1956
1957typedef struct {
1958 const char * usageTypeName;
1959 DateFormatSymbols::ECapitalizationContextUsageType usageTypeEnumValue;
1960} ContextUsageTypeNameToEnumValue;
1961
1962static const ContextUsageTypeNameToEnumValue contextUsageTypeMap[] = {
1963 // Entries must be sorted by usageTypeName; entry with nullptr name terminates list.
1964 { "day-format-except-narrow", DateFormatSymbols::kCapContextUsageDayFormat },
1965 { "day-narrow", DateFormatSymbols::kCapContextUsageDayNarrow },
1966 { "day-standalone-except-narrow", DateFormatSymbols::kCapContextUsageDayStandalone },
1967 { "era-abbr", DateFormatSymbols::kCapContextUsageEraAbbrev },
1968 { "era-name", DateFormatSymbols::kCapContextUsageEraWide },
1969 { "era-narrow", DateFormatSymbols::kCapContextUsageEraNarrow },
1970 { "metazone-long", DateFormatSymbols::kCapContextUsageMetazoneLong },
1971 { "metazone-short", DateFormatSymbols::kCapContextUsageMetazoneShort },
1972 { "month-format-except-narrow", DateFormatSymbols::kCapContextUsageMonthFormat },
1973 { "month-narrow", DateFormatSymbols::kCapContextUsageMonthNarrow },
1974 { "month-standalone-except-narrow", DateFormatSymbols::kCapContextUsageMonthStandalone },
1975 { "zone-long", DateFormatSymbols::kCapContextUsageZoneLong },
1976 { "zone-short", DateFormatSymbols::kCapContextUsageZoneShort },
1977 { nullptr, static_cast<DateFormatSymbols::ECapitalizationContextUsageType>(0) },
1978};
1979
1980// Resource keys to look up localized strings for day periods.
1981// The first one must be midnight and the second must be noon, so that their indices coincide
1982// with the am/pm field. Formatting and parsing code for day periods relies on this coincidence.
1983static const char *dayPeriodKeys[] = {"midnight", "noon",
1984 "morning1", "afternoon1", "evening1", "night1",
1985 "morning2", "afternoon2", "evening2", "night2"};
1986
1987UnicodeString* loadDayPeriodStrings(CalendarDataSink &sink, CharString &path,
1988 int32_t &stringCount, UErrorCode &status) {
1989 if (U_FAILURE(status)) { return nullptr; }
1990
1991 UnicodeString pathUString(path.data(), -1, US_INVicu::UnicodeString::kInvariant);
1992 Hashtable* map = static_cast<Hashtable*>(sink.maps.get(pathUString));
1993
1994 stringCount = UPRV_LENGTHOF(dayPeriodKeys)(int32_t)(sizeof(dayPeriodKeys)/sizeof((dayPeriodKeys)[0]));
1995 UnicodeString *strings = new UnicodeString[stringCount];
1996 if (strings == nullptr) {
1997 status = U_MEMORY_ALLOCATION_ERROR;
1998 return nullptr;
1999 }
2000
2001 if (map != nullptr) {
2002 for (int32_t i = 0; i < stringCount; ++i) {
2003 UnicodeString dayPeriodKey(dayPeriodKeys[i], -1, US_INVicu::UnicodeString::kInvariant);
2004 UnicodeString *dayPeriod = static_cast<UnicodeString*>(map->get(dayPeriodKey));
2005 if (dayPeriod != nullptr) {
2006 strings[i].fastCopyFrom(*dayPeriod);
2007 } else {
2008 strings[i].setToBogus();
2009 }
2010 }
2011 } else {
2012 for (int32_t i = 0; i < stringCount; i++) {
2013 strings[i].setToBogus();
2014 }
2015 }
2016 return strings;
2017}
2018
2019
2020void
2021DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData)
2022{
2023 int32_t len = 0;
2024 /* In case something goes wrong, initialize all of the data to nullptr. */
2025 fEras = nullptr;
2026 fErasCount = 0;
2027 fEraNames = nullptr;
2028 fEraNamesCount = 0;
2029 fNarrowEras = nullptr;
2030 fNarrowErasCount = 0;
2031 fMonths = nullptr;
2032 fMonthsCount=0;
2033 fShortMonths = nullptr;
2034 fShortMonthsCount=0;
2035 fNarrowMonths = nullptr;
2036 fNarrowMonthsCount=0;
2037 fStandaloneMonths = nullptr;
2038 fStandaloneMonthsCount=0;
2039 fStandaloneShortMonths = nullptr;
2040 fStandaloneShortMonthsCount=0;
2041 fStandaloneNarrowMonths = nullptr;
2042 fStandaloneNarrowMonthsCount=0;
2043 fWeekdays = nullptr;
2044 fWeekdaysCount=0;
2045 fShortWeekdays = nullptr;
2046 fShortWeekdaysCount=0;
2047 fShorterWeekdays = nullptr;
2048 fShorterWeekdaysCount=0;
2049 fNarrowWeekdays = nullptr;
2050 fNarrowWeekdaysCount=0;
2051 fStandaloneWeekdays = nullptr;
2052 fStandaloneWeekdaysCount=0;
2053 fStandaloneShortWeekdays = nullptr;
2054 fStandaloneShortWeekdaysCount=0;
2055 fStandaloneShorterWeekdays = nullptr;
2056 fStandaloneShorterWeekdaysCount=0;
2057 fStandaloneNarrowWeekdays = nullptr;
2058 fStandaloneNarrowWeekdaysCount=0;
2059 fAmPms = nullptr;
2060 fAmPmsCount=0;
2061 fNarrowAmPms = nullptr;
2062 fNarrowAmPmsCount=0;
2063 fTimeSeparator.setToBogus();
2064 fQuarters = nullptr;
2065 fQuartersCount = 0;
2066 fShortQuarters = nullptr;
2067 fShortQuartersCount = 0;
2068 fNarrowQuarters = nullptr;
2069 fNarrowQuartersCount = 0;
2070 fStandaloneQuarters = nullptr;
2071 fStandaloneQuartersCount = 0;
2072 fStandaloneShortQuarters = nullptr;
2073 fStandaloneShortQuartersCount = 0;
2074 fStandaloneNarrowQuarters = nullptr;
2075 fStandaloneNarrowQuartersCount = 0;
2076 fLeapMonthPatterns = nullptr;
2077 fLeapMonthPatternsCount = 0;
2078 fShortYearNames = nullptr;
2079 fShortYearNamesCount = 0;
2080 fShortZodiacNames = nullptr;
2081 fShortZodiacNamesCount = 0;
2082 fZoneStringsRowCount = 0;
2083 fZoneStringsColCount = 0;
2084 fZoneStrings = nullptr;
2085 fLocaleZoneStrings = nullptr;
2086 fAbbreviatedDayPeriods = nullptr;
2087 fAbbreviatedDayPeriodsCount = 0;
2088 fWideDayPeriods = nullptr;
2089 fWideDayPeriodsCount = 0;
2090 fNarrowDayPeriods = nullptr;
2091 fNarrowDayPeriodsCount = 0;
2092 fStandaloneAbbreviatedDayPeriods = nullptr;
2093 fStandaloneAbbreviatedDayPeriodsCount = 0;
2094 fStandaloneWideDayPeriods = nullptr;
2095 fStandaloneWideDayPeriodsCount = 0;
2096 fStandaloneNarrowDayPeriods = nullptr;
2097 fStandaloneNarrowDayPeriodsCount = 0;
2098 uprv_memset(fCapitalization, 0, sizeof(fCapitalization)):: memset(fCapitalization, 0, sizeof(fCapitalization));
2099
2100 // We need to preserve the requested locale for
2101 // lazy ZoneStringFormat instantiation. ZoneStringFormat
2102 // is region sensitive, thus, bundle locale bundle's locale
2103 // is not sufficient.
2104 fZSFLocale = locale;
2105
2106 if (U_FAILURE(status)) return;
2107
2108 // Create a CalendarDataSink to process this data and the resource bundles
2109 CalendarDataSink calendarSink(status);
2110 LocalUResourceBundlePointer rb(ures_openures_open_77(nullptr, locale.getBaseName(), &status));
2111 LocalUResourceBundlePointer cb(ures_getByKeyures_getByKey_77(rb.getAlias(), gCalendarTag, nullptr, &status));
2112
2113 if (U_FAILURE(status)) return;
2114
2115 // Iterate over the resource bundle data following the fallbacks through different calendar types
2116 UnicodeString calendarType((type != nullptr && *type != '\0')? type : gGregorianTag, -1, US_INVicu::UnicodeString::kInvariant);
2117 while (!calendarType.isBogus()) {
2118 CharString calendarTypeBuffer;
2119 calendarTypeBuffer.appendInvariantChars(calendarType, status);
2120 if (U_FAILURE(status)) { return; }
2121 const char *calendarTypeCArray = calendarTypeBuffer.data();
2122
2123 // Enumerate this calendar type. If the calendar is not found fallback to gregorian
2124 UErrorCode oldStatus = status;
2125 LocalUResourceBundlePointer ctb(ures_getByKeyWithFallbackures_getByKeyWithFallback_77(cb.getAlias(), calendarTypeCArray, nullptr, &status));
2126 if (status == U_MISSING_RESOURCE_ERROR) {
2127 if (uprv_strcmp(calendarTypeCArray, gGregorianTag):: strcmp(calendarTypeCArray, gGregorianTag) != 0) {
2128 calendarType.setTo(false, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)(int32_t)(sizeof(kGregorianTagUChar)/sizeof((kGregorianTagUChar
)[0]))
);
2129 calendarSink.visitAllResources();
2130 status = oldStatus;
2131 continue;
2132 }
2133 return;
2134 }
2135
2136 calendarSink.preEnumerate(calendarType);
2137 ures_getAllItemsWithFallbackures_getAllItemsWithFallback_77(ctb.getAlias(), "", calendarSink, status);
2138 if (U_FAILURE(status)) break;
2139
2140 // Stop loading when gregorian was loaded
2141 if (uprv_strcmp(calendarTypeCArray, gGregorianTag):: strcmp(calendarTypeCArray, gGregorianTag) == 0) {
2142 break;
2143 }
2144
2145 // Get the next calendar type to process from the sink
2146 calendarType = calendarSink.nextCalendarType;
2147
2148 // Gregorian is always the last fallback
2149 if (calendarType.isBogus()) {
2150 calendarType.setTo(false, kGregorianTagUChar, UPRV_LENGTHOF(kGregorianTagUChar)(int32_t)(sizeof(kGregorianTagUChar)/sizeof((kGregorianTagUChar
)[0]))
);
2151 calendarSink.visitAllResources();
2152 }
2153 }
2154
2155 // CharString object to build paths
2156 CharString path;
2157
2158 // Load Leap Month Patterns
2159 UErrorCode tempStatus = status;
2160 fLeapMonthPatterns = newUnicodeStringArray(kMonthPatternsCount);
2161 if (fLeapMonthPatterns) {
2162 initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatWide, calendarSink,
2163 buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesWideTag, tempStatus), tempStatus);
2164 initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatAbbrev, calendarSink,
2165 buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus);
2166 initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternFormatNarrow, calendarSink,
2167 buildResourcePath(path, gMonthPatternsTag, gNamesFormatTag, gNamesNarrowTag, tempStatus), tempStatus);
2168 initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneWide, calendarSink,
2169 buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesWideTag, tempStatus), tempStatus);
2170 initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneAbbrev, calendarSink,
2171 buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesAbbrTag, tempStatus), tempStatus);
2172 initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternStandaloneNarrow, calendarSink,
2173 buildResourcePath(path, gMonthPatternsTag, gNamesStandaloneTag, gNamesNarrowTag, tempStatus), tempStatus);
2174 initLeapMonthPattern(fLeapMonthPatterns, kLeapMonthPatternNumeric, calendarSink,
2175 buildResourcePath(path, gMonthPatternsTag, gNamesNumericTag, gNamesAllTag, tempStatus), tempStatus);
2176 if (U_SUCCESS(tempStatus)) {
2177 // Hack to fix bad C inheritance for dangi monthPatterns (OK in J); this should be handled by aliases in root, but isn't.
2178 // The ordering of the following statements is important.
2179 if (fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].isEmpty()) {
2180 fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]);
2181 }
2182 if (fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].isEmpty()) {
2183 fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].setTo(fLeapMonthPatterns[kLeapMonthPatternStandaloneNarrow]);
2184 }
2185 if (fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].isEmpty()) {
2186 fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]);
2187 }
2188 if (fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].isEmpty()) {
2189 fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev]);
2190 }
2191 // end of hack
2192 fLeapMonthPatternsCount = kMonthPatternsCount;
2193 } else {
2194 delete[] fLeapMonthPatterns;
2195 fLeapMonthPatterns = nullptr;
2196 }
2197 }
2198
2199 // Load cyclic names sets
2200 tempStatus = status;
2201 initField(&fShortYearNames, fShortYearNamesCount, calendarSink,
2202 buildResourcePath(path, gCyclicNameSetsTag, gNameSetYearsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus);
2203 initField(&fShortZodiacNames, fShortZodiacNamesCount, calendarSink,
2204 buildResourcePath(path, gCyclicNameSetsTag, gNameSetZodiacsTag, gNamesFormatTag, gNamesAbbrTag, tempStatus), tempStatus);
2205
2206 // Load context transforms and capitalization
2207 tempStatus = U_ZERO_ERROR;
2208 LocalUResourceBundlePointer localeBundle(ures_openures_open_77(nullptr, locale.getName(), &tempStatus));
2209 if (U_SUCCESS(tempStatus)) {
2210 LocalUResourceBundlePointer contextTransforms(ures_getByKeyWithFallbackures_getByKeyWithFallback_77(localeBundle.getAlias(), gContextTransformsTag, nullptr, &tempStatus));
2211 if (U_SUCCESS(tempStatus)) {
2212 for (LocalUResourceBundlePointer contextTransformUsage;
2213 contextTransformUsage.adoptInstead(ures_getNextResourceures_getNextResource_77(contextTransforms.getAlias(), nullptr, &tempStatus)),
2214 contextTransformUsage.isValid();) {
2215 const int32_t * intVector = ures_getIntVectorures_getIntVector_77(contextTransformUsage.getAlias(), &len, &status);
2216 if (U_SUCCESS(tempStatus) && intVector != nullptr && len >= 2) {
2217 const char* usageType = ures_getKeyures_getKey_77(contextTransformUsage.getAlias());
2218 if (usageType != nullptr) {
2219 const ContextUsageTypeNameToEnumValue * typeMapPtr = contextUsageTypeMap;
2220 int32_t compResult = 0;
2221 // linear search; list is short and we cannot be sure that bsearch is available
2222 while ( typeMapPtr->usageTypeName != nullptr && (compResult = uprv_strcmp(usageType, typeMapPtr->usageTypeName):: strcmp(usageType, typeMapPtr->usageTypeName)) > 0 ) {
2223 ++typeMapPtr;
2224 }
2225 if (typeMapPtr->usageTypeName != nullptr && compResult == 0) {
2226 fCapitalization[typeMapPtr->usageTypeEnumValue][0] = static_cast<UBool>(intVector[0]);
2227 fCapitalization[typeMapPtr->usageTypeEnumValue][1] = static_cast<UBool>(intVector[1]);
2228 }
2229 }
2230 }
2231 tempStatus = U_ZERO_ERROR;
2232 }
2233 }
2234
2235 tempStatus = U_ZERO_ERROR;
2236 const LocalPointer<NumberingSystem> numberingSystem(
2237 NumberingSystem::createInstance(locale, tempStatus), tempStatus);
2238 if (U_SUCCESS(tempStatus)) {
2239 // These functions all fail gracefully if passed nullptr pointers and
2240 // do nothing unless U_SUCCESS(tempStatus), so it's only necessary
2241 // to check for errors once after all calls are made.
2242 const LocalUResourceBundlePointer numberElementsData(ures_getByKeyWithFallbackures_getByKeyWithFallback_77(
2243 localeBundle.getAlias(), gNumberElementsTag, nullptr, &tempStatus));
2244 const LocalUResourceBundlePointer nsNameData(ures_getByKeyWithFallbackures_getByKeyWithFallback_77(
2245 numberElementsData.getAlias(), numberingSystem->getName(), nullptr, &tempStatus));
2246 const LocalUResourceBundlePointer symbolsData(ures_getByKeyWithFallbackures_getByKeyWithFallback_77(
2247 nsNameData.getAlias(), gSymbolsTag, nullptr, &tempStatus));
2248 fTimeSeparator = ures_getUnicodeStringByKey(
2249 symbolsData.getAlias(), gTimeSeparatorTag, &tempStatus);
2250 if (U_FAILURE(tempStatus)) {
2251 fTimeSeparator.setToBogus();
2252 }
2253 }
2254
2255 }
2256
2257 if (fTimeSeparator.isBogus()) {
2258 fTimeSeparator.setTo(DateFormatSymbols::DEFAULT_TIME_SEPARATOR);
2259 }
2260
2261 // Load day periods
2262 fAbbreviatedDayPeriods = loadDayPeriodStrings(calendarSink,
2263 buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesAbbrTag, status),
2264 fAbbreviatedDayPeriodsCount, status);
2265
2266 fWideDayPeriods = loadDayPeriodStrings(calendarSink,
2267 buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesWideTag, status),
2268 fWideDayPeriodsCount, status);
2269 fNarrowDayPeriods = loadDayPeriodStrings(calendarSink,
2270 buildResourcePath(path, gDayPeriodTag, gNamesFormatTag, gNamesNarrowTag, status),
2271 fNarrowDayPeriodsCount, status);
2272
2273 fStandaloneAbbreviatedDayPeriods = loadDayPeriodStrings(calendarSink,
2274 buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesAbbrTag, status),
2275 fStandaloneAbbreviatedDayPeriodsCount, status);
2276
2277 fStandaloneWideDayPeriods = loadDayPeriodStrings(calendarSink,
2278 buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesWideTag, status),
2279 fStandaloneWideDayPeriodsCount, status);
2280 fStandaloneNarrowDayPeriods = loadDayPeriodStrings(calendarSink,
2281 buildResourcePath(path, gDayPeriodTag, gNamesStandaloneTag, gNamesNarrowTag, status),
2282 fStandaloneNarrowDayPeriodsCount, status);
2283
2284 // Fill in for missing/bogus items (dayPeriods are a map so single items might be missing)
2285 if (U_SUCCESS(status)) {
2286 for (int32_t dpidx = 0; dpidx < fAbbreviatedDayPeriodsCount; ++dpidx) {
2287 if (dpidx < fWideDayPeriodsCount && fWideDayPeriods != nullptr && fWideDayPeriods[dpidx].isBogus()) {
2288 fWideDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
2289 }
2290 if (dpidx < fNarrowDayPeriodsCount && fNarrowDayPeriods != nullptr && fNarrowDayPeriods[dpidx].isBogus()) {
2291 fNarrowDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
2292 }
2293 if (dpidx < fStandaloneAbbreviatedDayPeriodsCount && fStandaloneAbbreviatedDayPeriods != nullptr && fStandaloneAbbreviatedDayPeriods[dpidx].isBogus()) {
2294 fStandaloneAbbreviatedDayPeriods[dpidx].fastCopyFrom(fAbbreviatedDayPeriods[dpidx]);
2295 }
2296 if (dpidx < fStandaloneWideDayPeriodsCount && fStandaloneWideDayPeriods != nullptr && fStandaloneWideDayPeriods[dpidx].isBogus()) {
2297 fStandaloneWideDayPeriods[dpidx].fastCopyFrom(fStandaloneAbbreviatedDayPeriods[dpidx]);
2298 }
2299 if (dpidx < fStandaloneNarrowDayPeriodsCount && fStandaloneNarrowDayPeriods != nullptr && fStandaloneNarrowDayPeriods[dpidx].isBogus()) {
2300 fStandaloneNarrowDayPeriods[dpidx].fastCopyFrom(fStandaloneAbbreviatedDayPeriods[dpidx]);
2301 }
2302 }
2303 }
2304
2305 U_LOCALE_BASED(locBased, *this)LocaleBased locBased((*this).validLocale, (*this).actualLocale
)
;
2306 // if we make it to here, the resource data is cool, and we can get everything out
2307 // of it that we need except for the time-zone and localized-pattern data, which
2308 // are stored in a separate file
2309 locBased.setLocaleIDs(ures_getLocaleByTypeures_getLocaleByType_77(cb.getAlias(), ULOC_VALID_LOCALE, &status),
2310 ures_getLocaleByTypeures_getLocaleByType_77(cb.getAlias(), ULOC_ACTUAL_LOCALE, &status), status);
2311
2312 // Load eras
2313 initField(&fEras, fErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesAbbrTag, status), status);
2314 UErrorCode oldStatus = status;
2315 initField(&fEraNames, fEraNamesCount, calendarSink, buildResourcePath(path, gErasTag, gNamesWideTag, status), status);
2316 if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3
2317 status = oldStatus;
2318 assignArray(fEraNames, fEraNamesCount, fEras, fErasCount);
2319 }
2320 // current ICU4J falls back to abbreviated if narrow eras are missing, so we will too
2321 oldStatus = status;
2322 initField(&fNarrowEras, fNarrowErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesNarrowTag, status), status);
2323 if (status == U_MISSING_RESOURCE_ERROR) { // Workaround because eras/wide was omitted from CLDR 1.3
2324 status = oldStatus;
2325 assignArray(fNarrowEras, fNarrowErasCount, fEras, fErasCount);
2326 }
2327
2328 // Load month names
2329 initField(&fMonths, fMonthsCount, calendarSink,
2330 buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesWideTag, status), status);
2331 initField(&fShortMonths, fShortMonthsCount, calendarSink,
2332 buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesAbbrTag, status), status);
2333 initField(&fStandaloneMonths, fStandaloneMonthsCount, calendarSink,
2334 buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status);
2335 if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide not available, use format/wide */
2336 status = U_ZERO_ERROR;
2337 assignArray(fStandaloneMonths, fStandaloneMonthsCount, fMonths, fMonthsCount);
2338 }
2339 initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calendarSink,
2340 buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
2341 if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated not available, use format/abbreviated */
2342 status = U_ZERO_ERROR;
2343 assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, fShortMonths, fShortMonthsCount);
2344 }
2345
2346 UErrorCode narrowMonthsEC = status;
2347 UErrorCode standaloneNarrowMonthsEC = status;
2348 initField(&fNarrowMonths, fNarrowMonthsCount, calendarSink,
2349 buildResourcePath(path, gMonthNamesTag, gNamesFormatTag, gNamesNarrowTag, narrowMonthsEC), narrowMonthsEC);
2350 initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calendarSink,
2351 buildResourcePath(path, gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, narrowMonthsEC), standaloneNarrowMonthsEC);
2352 if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC != U_MISSING_RESOURCE_ERROR) {
2353 // If format/narrow not available, use standalone/narrow
2354 assignArray(fNarrowMonths, fNarrowMonthsCount, fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount);
2355 } else if (narrowMonthsEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) {
2356 // If standalone/narrow not available, use format/narrow
2357 assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fNarrowMonths, fNarrowMonthsCount);
2358 } else if (narrowMonthsEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowMonthsEC == U_MISSING_RESOURCE_ERROR) {
2359 // If neither is available, use format/abbreviated
2360 assignArray(fNarrowMonths, fNarrowMonthsCount, fShortMonths, fShortMonthsCount);
2361 assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fShortMonths, fShortMonthsCount);
2362 }
2363
2364 // Load AM/PM markers; if wide or narrow not available, use short
2365 UErrorCode ampmStatus = U_ZERO_ERROR;
2366 initField(&fAmPms, fAmPmsCount, calendarSink,
2367 buildResourcePath(path, gAmPmMarkersTag, ampmStatus), ampmStatus);
2368 if (U_FAILURE(ampmStatus)) {
2369 initField(&fAmPms, fAmPmsCount, calendarSink,
2370 buildResourcePath(path, gAmPmMarkersAbbrTag, status), status);
2371 }
2372 ampmStatus = U_ZERO_ERROR;
2373 initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink,
2374 buildResourcePath(path, gAmPmMarkersNarrowTag, ampmStatus), ampmStatus);
2375 if (U_FAILURE(ampmStatus)) {
2376 initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink,
2377 buildResourcePath(path, gAmPmMarkersAbbrTag, status), status);
2378 }
2379 if(status == U_MISSING_RESOURCE_ERROR) {
2380 status = U_ZERO_ERROR;
2381 assignArray(fNarrowAmPms, fNarrowAmPmsCount, fAmPms, fAmPmsCount);
2382 }
2383
2384 // Load quarters
2385 initField(&fQuarters, fQuartersCount, calendarSink,
2386 buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesWideTag, status), status);
2387 initField(&fShortQuarters, fShortQuartersCount, calendarSink,
2388 buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesAbbrTag, status), status);
2389 if(status == U_MISSING_RESOURCE_ERROR) {
2390 status = U_ZERO_ERROR;
2391 assignArray(fShortQuarters, fShortQuartersCount, fQuarters, fQuartersCount);
2392 }
2393
2394 initField(&fStandaloneQuarters, fStandaloneQuartersCount, calendarSink,
2395 buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesWideTag, status), status);
2396 if(status == U_MISSING_RESOURCE_ERROR) {
2397 status = U_ZERO_ERROR;
2398 assignArray(fStandaloneQuarters, fStandaloneQuartersCount, fQuarters, fQuartersCount);
2399 }
2400 initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calendarSink,
2401 buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
2402 if(status == U_MISSING_RESOURCE_ERROR) {
2403 status = U_ZERO_ERROR;
2404 assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, fShortQuarters, fShortQuartersCount);
2405 }
2406
2407 // unlike the fields above, narrow format quarters fall back on narrow standalone quarters
2408 initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, calendarSink,
2409 buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
2410 initField(&fNarrowQuarters, fNarrowQuartersCount, calendarSink,
2411 buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesNarrowTag, status), status);
2412 if(status == U_MISSING_RESOURCE_ERROR) {
2413 status = U_ZERO_ERROR;
2414 assignArray(fNarrowQuarters, fNarrowQuartersCount, fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount);
2415 }
2416
2417 // ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597)
2418 /*
2419 // fastCopyFrom()/setTo() - see assignArray comments
2420 resStr = ures_getStringByKey(fResourceBundle, gLocalPatternCharsTag, &len, &status);
2421 fLocalPatternChars.setTo(true, resStr, len);
2422 // If the locale data does not include new pattern chars, use the defaults
2423 // TODO: Consider making this an error, since this may add conflicting characters.
2424 if (len < PATTERN_CHARS_LEN) {
2425 fLocalPatternChars.append(UnicodeString(true, &gPatternChars[len], PATTERN_CHARS_LEN-len));
2426 }
2427 */
2428 fLocalPatternChars.setTo(true, gPatternChars, PATTERN_CHARS_LEN37);
2429
2430 // Format wide weekdays -> fWeekdays
2431 // {sfb} fixed to handle 1-based weekdays
2432 initField(&fWeekdays, fWeekdaysCount, calendarSink,
2433 buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesWideTag, status), 1, status);
2434
2435 // Format abbreviated weekdays -> fShortWeekdays
2436 initField(&fShortWeekdays, fShortWeekdaysCount, calendarSink,
2437 buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesAbbrTag, status), 1, status);
2438
2439 // Format short weekdays -> fShorterWeekdays (fall back to abbreviated)
2440 initField(&fShorterWeekdays, fShorterWeekdaysCount, calendarSink,
2441 buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesShortTag, status), 1, status);
2442 if (status == U_MISSING_RESOURCE_ERROR) {
2443 status = U_ZERO_ERROR;
2444 assignArray(fShorterWeekdays, fShorterWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
2445 }
2446
2447 // Stand-alone wide weekdays -> fStandaloneWeekdays
2448 initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, calendarSink,
2449 buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesWideTag, status), 1, status);
2450 if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/wide is not available, use format/wide */
2451 status = U_ZERO_ERROR;
2452 assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, fWeekdays, fWeekdaysCount);
2453 }
2454
2455 // Stand-alone abbreviated weekdays -> fStandaloneShortWeekdays
2456 initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, calendarSink,
2457 buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), 1, status);
2458 if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/abbreviated is not available, use format/abbreviated */
2459 status = U_ZERO_ERROR;
2460 assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
2461 }
2462
2463 // Stand-alone short weekdays -> fStandaloneShorterWeekdays (fall back to format abbreviated)
2464 initField(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, calendarSink,
2465 buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesShortTag, status), 1, status);
2466 if (status == U_MISSING_RESOURCE_ERROR) { /* If standalone/short is not available, use format/short */
2467 status = U_ZERO_ERROR;
2468 assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, fShorterWeekdays, fShorterWeekdaysCount);
2469 }
2470
2471 // Format narrow weekdays -> fNarrowWeekdays
2472 UErrorCode narrowWeeksEC = status;
2473 initField(&fNarrowWeekdays, fNarrowWeekdaysCount, calendarSink,
2474 buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesNarrowTag, status), 1, narrowWeeksEC);
2475 // Stand-alone narrow weekdays -> fStandaloneNarrowWeekdays
2476 UErrorCode standaloneNarrowWeeksEC = status;
2477 initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, calendarSink,
2478 buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), 1, standaloneNarrowWeeksEC);
2479
2480 if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC != U_MISSING_RESOURCE_ERROR) {
2481 // If format/narrow not available, use standalone/narrow
2482 assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount);
2483 } else if (narrowWeeksEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR) {
2484 // If standalone/narrow not available, use format/narrow
2485 assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fNarrowWeekdays, fNarrowWeekdaysCount);
2486 } else if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR ) {
2487 // If neither is available, use format/abbreviated
2488 assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
2489 assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount);
2490 }
2491
2492 // Last resort fallback in case previous data wasn't loaded
2493 if (U_FAILURE(status))
2494 {
2495 if (useLastResortData)
2496 {
2497 // Handle the case in which there is no resource data present.
2498 // We don't have to generate usable patterns in this situation;
2499 // we just need to produce something that will be semi-intelligible
2500 // in most locales.
2501
2502 status = U_USING_FALLBACK_WARNING;
2503 //TODO(fabalbon): make sure we are storing las resort data for all fields in here.
2504 initField(&fEras, fErasCount, reinterpret_cast<const char16_t*>(gLastResortEras), kEraNum, kEraLen, status);
2505 initField(&fEraNames, fEraNamesCount, reinterpret_cast<const char16_t*>(gLastResortEras), kEraNum, kEraLen, status);
2506 initField(&fNarrowEras, fNarrowErasCount, reinterpret_cast<const char16_t*>(gLastResortEras), kEraNum, kEraLen, status);
2507 initField(&fMonths, fMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
2508 initField(&fShortMonths, fShortMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
2509 initField(&fNarrowMonths, fNarrowMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
2510 initField(&fStandaloneMonths, fStandaloneMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
2511 initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
2512 initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, reinterpret_cast<const char16_t*>(gLastResortMonthNames), kMonthNum, kMonthLen, status);
2513 initField(&fWeekdays, fWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
2514 initField(&fShortWeekdays, fShortWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
2515 initField(&fShorterWeekdays, fShorterWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
2516 initField(&fNarrowWeekdays, fNarrowWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
2517 initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
2518 initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
2519 initField(&fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
2520 initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, reinterpret_cast<const char16_t*>(gLastResortDayNames), kDayNum, kDayLen, status);
2521 initField(&fAmPms, fAmPmsCount, reinterpret_cast<const char16_t*>(gLastResortAmPmMarkers), kAmPmNum, kAmPmLen, status);
2522 initField(&fNarrowAmPms, fNarrowAmPmsCount, reinterpret_cast<const char16_t*>(gLastResortAmPmMarkers), kAmPmNum, kAmPmLen, status);
2523 initField(&fQuarters, fQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
2524 initField(&fShortQuarters, fShortQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
2525 initField(&fNarrowQuarters, fNarrowQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
2526 initField(&fStandaloneQuarters, fStandaloneQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
2527 initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
2528 initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, reinterpret_cast<const char16_t*>(gLastResortQuarters), kQuarterNum, kQuarterLen, status);
2529 fLocalPatternChars.setTo(true, gPatternChars, PATTERN_CHARS_LEN37);
2530 }
2531 }
2532}
2533
2534Locale
2535DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
2536 return LocaleBased::getLocale(validLocale, actualLocale, type, status);
2537}
2538
2539U_NAMESPACE_END}
2540
2541#endif /* #if !UCONFIG_NO_FORMATTING */
2542
2543//eof

/root/firefox-clang/intl/icu/source/common/unifiedcache.h

1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5* Copyright (C) 2015, International Business Machines Corporation and
6* others. All Rights Reserved.
7******************************************************************************
8*
9* File UNIFIEDCACHE.H - The ICU Unified cache.
10******************************************************************************
11*/
12
13#ifndef __UNIFIED_CACHE_H__
14#define __UNIFIED_CACHE_H__
15
16#include "utypeinfo.h" // for 'typeid' to work
17
18#include "unicode/uobject.h"
19#include "unicode/locid.h"
20#include "sharedobject.h"
21#include "unicode/unistr.h"
22#include "cstring.h"
23#include "ustr_imp.h"
24
25struct UHashtable;
26struct UHashElement;
27
28U_NAMESPACE_BEGINnamespace icu_77 {
29
30class UnifiedCache;
31
32/**
33 * A base class for all cache keys.
34 */
35class U_COMMON_API CacheKeyBase : public UObject {
36 public:
37 CacheKeyBase() : fCreationStatus(U_ZERO_ERROR), fIsPrimary(false) {}
38
39 /**
40 * Copy constructor. Needed to support cloning.
41 */
42 CacheKeyBase(const CacheKeyBase &other)
43 : UObject(other), fCreationStatus(other.fCreationStatus), fIsPrimary(false) { }
44 virtual ~CacheKeyBase();
45
46 /**
47 * Returns the hash code for this object.
48 */
49 virtual int32_t hashCode() const = 0;
50
51 /**
52 * Clones this object polymorphically. Caller owns returned value.
53 */
54 virtual CacheKeyBase *clone() const = 0;
55
56 /**
57 * Create a new object for this key. Called by cache on cache miss.
58 * createObject must add a reference to the object it returns. Note
59 * that getting an object from the cache and returning it without calling
60 * removeRef on it satisfies this requirement. It can also return nullptr
61 * and set status to an error.
62 *
63 * @param creationContext the context in which the object is being
64 * created. May be nullptr.
65 * @param status Implementations can return a failure here.
66 * In addition, implementations may return a
67 * non nullptr object and set a warning status.
68 */
69 virtual const SharedObject *createObject(
70 const void *creationContext, UErrorCode &status) const = 0;
71
72 /**
73 * Writes a description of this key to buffer and returns buffer. Written
74 * description is nullptr terminated.
75 */
76 virtual char *writeDescription(char *buffer, int32_t bufSize) const = 0;
77
78 friend inline bool operator==(const CacheKeyBase& lhs,
79 const CacheKeyBase& rhs) {
80 return lhs.equals(rhs);
81 }
82
83 friend inline bool operator!=(const CacheKeyBase& lhs,
84 const CacheKeyBase& rhs) {
85 return !lhs.equals(rhs);
86 }
87
88 protected:
89 virtual bool equals(const CacheKeyBase& other) const = 0;
90
91 private:
92 mutable UErrorCode fCreationStatus;
93 mutable UBool fIsPrimary;
94 friend class UnifiedCache;
95};
96
97
98
99/**
100 * Templated version of CacheKeyBase.
101 * A key of type LocaleCacheKey<T> maps to a value of type T.
102 */
103template<typename T>
104class CacheKey : public CacheKeyBase {
105 public:
106 virtual ~CacheKey() { }
107 /**
108 * The template parameter, T, determines the hash code returned.
109 */
110 virtual int32_t hashCode() const override {
111 const char *s = typeid(T).name();
112 return ustr_hashCharsNustr_hashCharsN_77(s, static_cast<int32_t>(uprv_strlen(s):: strlen(s)));
113 }
114
115 /**
116 * Use the value type, T, as the description.
117 */
118 virtual char *writeDescription(char *buffer, int32_t bufLen) const override {
119 const char *s = typeid(T).name();
120 uprv_strncpy(buffer, s, bufLen):: strncpy(buffer, s, bufLen);
121 buffer[bufLen - 1] = 0;
122 return buffer;
123 }
124
125 protected:
126 /**
127 * Two objects are equal if they are of the same type.
128 */
129 virtual bool equals(const CacheKeyBase &other) const override {
130 return this == &other || typeid(*this) == typeid(other);
131 }
132};
133
134/**
135 * Cache key based on locale.
136 * A key of type LocaleCacheKey<T> maps to a value of type T.
137 */
138template<typename T>
139class LocaleCacheKey : public CacheKey<T> {
140 protected:
141 Locale fLoc;
142 virtual bool equals(const CacheKeyBase &other) const override {
143 if (!CacheKey<T>::equals(other)) {
144 return false;
145 }
146 // We know this and other are of same class because equals() on
147 // CacheKey returned true.
148 return operator==(static_cast<const LocaleCacheKey<T> &>(other));
149 }
150 public:
151 LocaleCacheKey(const Locale &loc) : fLoc(loc) {}
152 LocaleCacheKey(const LocaleCacheKey<T> &other)
153 : CacheKey<T>(other), fLoc(other.fLoc) { }
154 virtual ~LocaleCacheKey() { }
155 virtual int32_t hashCode() const override {
156 return (int32_t)(37u * (uint32_t)CacheKey<T>::hashCode() + (uint32_t)fLoc.hashCode());
157 }
158 inline bool operator == (const LocaleCacheKey<T> &other) const {
159 return fLoc == other.fLoc;
160 }
161 virtual CacheKeyBase *clone() const override {
162 return new LocaleCacheKey<T>(*this);
163 }
164 virtual const T *createObject(
165 const void *creationContext, UErrorCode &status) const override;
166 /**
167 * Use the locale id as the description.
168 */
169 virtual char *writeDescription(char *buffer, int32_t bufLen) const override {
170 const char *s = fLoc.getName();
171 uprv_strncpy(buffer, s, bufLen):: strncpy(buffer, s, bufLen);
172 buffer[bufLen - 1] = 0;
173 return buffer;
174 }
175
176};
177
178/**
179 * The unified cache. A singleton type.
180 * Design doc here:
181 * https://docs.google.com/document/d/1RwGQJs4N4tawNbf809iYDRCvXoMKqDJihxzYt1ysmd8/edit?usp=sharing
182 */
183class U_COMMON_API UnifiedCache : public UnifiedCacheBase {
184 public:
185 /**
186 * @internal
187 * Do not call directly. Instead use UnifiedCache::getInstance() as
188 * there should be only one UnifiedCache in an application.
189 */
190 UnifiedCache(UErrorCode &status);
191
192 /**
193 * Return a pointer to the global cache instance.
194 */
195 static UnifiedCache *getInstance(UErrorCode &status);
196
197 /**
198 * Fetches a value from the cache by key. Equivalent to
199 * get(key, nullptr, ptr, status);
200 */
201 template<typename T>
202 void get(
203 const CacheKey<T>& key,
204 const T *&ptr,
205 UErrorCode &status) const {
206 get(key, nullptr, ptr, status);
5
Calling 'UnifiedCache::get'
15
Returning from 'UnifiedCache::get'
207 }
16
Returning without writing to 'ptr'
208
209 /**
210 * Fetches value from the cache by key.
211 *
212 * @param key the cache key.
213 * @param creationContext passed verbatim to createObject method of key
214 * @param ptr On entry, ptr must be nullptr or be included if
215 * the reference count of the object it points
216 * to. On exit, ptr points to the fetched object
217 * from the cache or is left unchanged on
218 * failure. Caller must call removeRef on ptr
219 * if set to a non nullptr value.
220 * @param status Any error returned here. May be set to a
221 * warning value even if ptr is set.
222 */
223 template<typename T>
224 void get(
225 const CacheKey<T>& key,
226 const void *creationContext,
227 const T *&ptr,
228 UErrorCode &status) const {
229 if (U_FAILURE(status)) {
6
Taking false branch
230 return;
231 }
232 UErrorCode creationStatus = U_ZERO_ERROR;
233 const SharedObject *value = nullptr;
234 _get(key, value, creationContext, creationStatus);
235 const T *tvalue = (const T *) value;
236 if (U_SUCCESS(creationStatus)) {
7
Taking true branch
237 SharedObject::copyPtr(tvalue, ptr);
8
Calling 'SharedObject::copyPtr'
12
Returning from 'SharedObject::copyPtr'
238 }
239 SharedObject::clearPtr(tvalue);
240 // Take care not to overwrite a warning status passed in with
241 // another warning or U_ZERO_ERROR.
242 if (status == U_ZERO_ERROR || U_FAILURE(creationStatus)) {
13
Assuming 'status' is equal to U_ZERO_ERROR
243 status = creationStatus;
244 }
245 }
14
Returning without writing to 'ptr'
246
247#ifdef UNIFIED_CACHE_DEBUG
248 /**
249 * Dumps the contents of this cache to standard error. Used for testing of
250 * cache only.
251 */
252 void dumpContents() const;
253#endif
254
255 /**
256 * Convenience method to get a value of type T from cache for a
257 * particular locale with creationContext == nullptr.
258 * @param loc the locale
259 * @param ptr On entry, must be nullptr or included in the ref count
260 * of the object to which it points.
261 * On exit, fetched value stored here or is left
262 * unchanged on failure. Caller must call removeRef on
263 * ptr if set to a non nullptr value.
264 * @param status Any error returned here. May be set to a
265 * warning value even if ptr is set.
266 */
267 template<typename T>
268 static void getByLocale(
269 const Locale &loc, const T *&ptr, UErrorCode &status) {
270 const UnifiedCache *cache = getInstance(status);
271 if (U_FAILURE(status)) {
3
Taking false branch
272 return;
273 }
274 cache->get(LocaleCacheKey<T>(loc), ptr, status);
4
Calling 'UnifiedCache::get'
17
Returning from 'UnifiedCache::get'
275 }
18
Returning without writing to 'ptr'
276
277#ifdef UNIFIED_CACHE_DEBUG
278 /**
279 * Dumps the cache contents to stderr. For testing only.
280 */
281 static void dump();
282#endif
283
284 /**
285 * Returns the number of keys in this cache. For testing only.
286 */
287 int32_t keyCount() const;
288
289 /**
290 * Removes any values from cache that are not referenced outside
291 * the cache.
292 */
293 void flush() const;
294
295 /**
296 * Configures at what point eviction of unused entries will begin.
297 * Eviction is triggered whenever the number of evictable keys exceeds
298 * BOTH count AND (number of in-use items) * (percentageOfInUseItems / 100).
299 * Once the number of unused entries drops below one of these,
300 * eviction ceases. Because eviction happens incrementally,
301 * the actual unused entry count may exceed both these numbers
302 * from time to time.
303 *
304 * A cache entry is defined as unused if it is not essential to guarantee
305 * that for a given key X, the cache returns the same reference to the
306 * same value as long as the client already holds a reference to that
307 * value.
308 *
309 * If this method is never called, the default settings are 1000 and 100%.
310 *
311 * Although this method is thread-safe, it is designed to be called at
312 * application startup. If it is called in the middle of execution, it
313 * will have no immediate effect on the cache. However over time, the
314 * cache will perform eviction slices in an attempt to honor the new
315 * settings.
316 *
317 * If a client already holds references to many different unique values
318 * in the cache such that the number of those unique values far exceeds
319 * "count" then the cache may not be able to maintain this maximum.
320 * However, if this happens, the cache still guarantees that the number of
321 * unused entries will remain only a small percentage of the total cache
322 * size.
323 *
324 * If the parameters passed are negative, setEvctionPolicy sets status to
325 * U_ILLEGAL_ARGUMENT_ERROR.
326 */
327 void setEvictionPolicy(
328 int32_t count, int32_t percentageOfInUseItems, UErrorCode &status);
329
330
331 /**
332 * Returns how many entries have been auto evicted during the lifetime
333 * of this cache. This only includes auto evicted entries, not
334 * entries evicted because of a call to flush().
335 */
336 int64_t autoEvictedCount() const;
337
338 /**
339 * Returns the unused entry count in this cache. For testing only,
340 * Regular clients will not need this.
341 */
342 int32_t unusedCount() const;
343
344 virtual void handleUnreferencedObject() const override;
345 virtual ~UnifiedCache();
346
347 private:
348 UHashtable *fHashtable;
349 mutable int32_t fEvictPos;
350 mutable int32_t fNumValuesTotal;
351 mutable int32_t fNumValuesInUse;
352 int32_t fMaxUnused;
353 int32_t fMaxPercentageOfInUse;
354 mutable int64_t fAutoEvictedCount;
355 SharedObject *fNoValue;
356
357 UnifiedCache(const UnifiedCache &other) = delete;
358 UnifiedCache &operator=(const UnifiedCache &other) = delete;
359
360 /**
361 * Flushes the contents of the cache. If cache values hold references to other
362 * cache values then _flush should be called in a loop until it returns false.
363 *
364 * On entry, gCacheMutex must be held.
365 * On exit, those values with are evictable are flushed.
366 *
367 * @param all if false flush evictable items only, which are those with no external
368 * references, plus those that can be safely recreated.<br>
369 * if true, flush all elements. Any values (sharedObjects) with remaining
370 * hard (external) references are not deleted, but are detached from
371 * the cache, so that a subsequent removeRefs can delete them.
372 * _flush is not thread safe when all is true.
373 * @return true if any value in cache was flushed or false otherwise.
374 */
375 UBool _flush(UBool all) const;
376
377 /**
378 * Gets value out of cache.
379 * On entry. gCacheMutex must not be held. value must be nullptr. status
380 * must be U_ZERO_ERROR.
381 * On exit. value and status set to what is in cache at key or on cache
382 * miss the key's createObject() is called and value and status are set to
383 * the result of that. In this latter case, best effort is made to add the
384 * value and status to the cache. If createObject() fails to create a value,
385 * fNoValue is stored in cache, and value is set to nullptr. Caller must call
386 * removeRef on value if non nullptr.
387 */
388 void _get(
389 const CacheKeyBase &key,
390 const SharedObject *&value,
391 const void *creationContext,
392 UErrorCode &status) const;
393
394 /**
395 * Attempts to fetch value and status for key from cache.
396 * On entry, gCacheMutex must not be held value must be nullptr and status must
397 * be U_ZERO_ERROR.
398 * On exit, either returns false (In this
399 * case caller should try to create the object) or returns true with value
400 * pointing to the fetched value and status set to fetched status. When
401 * false is returned status may be set to failure if an in progress hash
402 * entry could not be made but value will remain unchanged. When true is
403 * returned, caller must call removeRef() on value.
404 */
405 UBool _poll(
406 const CacheKeyBase &key,
407 const SharedObject *&value,
408 UErrorCode &status) const;
409
410 /**
411 * Places a new value and creationStatus in the cache for the given key.
412 * On entry, gCacheMutex must be held. key must not exist in the cache.
413 * On exit, value and creation status placed under key. Soft reference added
414 * to value on successful add. On error sets status.
415 */
416 void _putNew(
417 const CacheKeyBase &key,
418 const SharedObject *value,
419 const UErrorCode creationStatus,
420 UErrorCode &status) const;
421
422 /**
423 * Places value and status at key if there is no value at key or if cache
424 * entry for key is in progress. Otherwise, it leaves the current value and
425 * status there.
426 *
427 * On entry. gCacheMutex must not be held. Value must be
428 * included in the reference count of the object to which it points.
429 *
430 * On exit, value and status are changed to what was already in the cache if
431 * something was there and not in progress. Otherwise, value and status are left
432 * unchanged in which case they are placed in the cache on a best-effort basis.
433 * Caller must call removeRef() on value.
434 */
435 void _putIfAbsentAndGet(
436 const CacheKeyBase &key,
437 const SharedObject *&value,
438 UErrorCode &status) const;
439
440 /**
441 * Returns the next element in the cache round robin style.
442 * Returns nullptr if the cache is empty.
443 * On entry, gCacheMutex must be held.
444 */
445 const UHashElement *_nextElement() const;
446
447 /**
448 * Return the number of cache items that would need to be evicted
449 * to bring usage into conformance with eviction policy.
450 *
451 * An item corresponds to an entry in the hash table, a hash table element.
452 *
453 * On entry, gCacheMutex must be held.
454 */
455 int32_t _computeCountOfItemsToEvict() const;
456
457 /**
458 * Run an eviction slice.
459 * On entry, gCacheMutex must be held.
460 * _runEvictionSlice runs a slice of the evict pipeline by examining the next
461 * 10 entries in the cache round robin style evicting them if they are eligible.
462 */
463 void _runEvictionSlice() const;
464
465 /**
466 * Register a primary cache entry. A primary key is the first key to create
467 * a given SharedObject value. Subsequent keys whose create function
468 * produce references to an already existing SharedObject are not primary -
469 * they can be evicted and subsequently recreated.
470 *
471 * On entry, gCacheMutex must be held.
472 * On exit, items in use count incremented, entry is marked as a primary
473 * entry, and value registered with cache so that subsequent calls to
474 * addRef() and removeRef() on it correctly interact with the cache.
475 */
476 void _registerPrimary(const CacheKeyBase *theKey, const SharedObject *value) const;
477
478 /**
479 * Store a value and creation error status in given hash entry.
480 * On entry, gCacheMutex must be held. Hash entry element must be in progress.
481 * value must be non nullptr.
482 * On Exit, soft reference added to value. value and status stored in hash
483 * entry. Soft reference removed from previous stored value. Waiting
484 * threads notified.
485 */
486 void _put(
487 const UHashElement *element,
488 const SharedObject *value,
489 const UErrorCode status) const;
490 /**
491 * Remove a soft reference, and delete the SharedObject if no references remain.
492 * To be used from within the UnifiedCache implementation only.
493 * gCacheMutex must be held by caller.
494 * @param value the SharedObject to be acted on.
495 */
496 void removeSoftRef(const SharedObject *value) const;
497
498 /**
499 * Increment the hard reference count of the given SharedObject.
500 * gCacheMutex must be held by the caller.
501 * Update numValuesEvictable on transitions between zero and one reference.
502 *
503 * @param value The SharedObject to be referenced.
504 * @return the hard reference count after the addition.
505 */
506 int32_t addHardRef(const SharedObject *value) const;
507
508 /**
509 * Decrement the hard reference count of the given SharedObject.
510 * gCacheMutex must be held by the caller.
511 * Update numValuesEvictable on transitions between one and zero reference.
512 *
513 * @param value The SharedObject to be referenced.
514 * @return the hard reference count after the removal.
515 */
516 int32_t removeHardRef(const SharedObject *value) const;
517
518
519#ifdef UNIFIED_CACHE_DEBUG
520 void _dumpContents() const;
521#endif
522
523 /**
524 * Fetch value and error code from a particular hash entry.
525 * On entry, gCacheMutex must be held. value must be either nullptr or must be
526 * included in the ref count of the object to which it points.
527 * On exit, value and status set to what is in the hash entry. Caller must
528 * eventually call removeRef on value.
529 * If hash entry is in progress, value will be set to gNoValue and status will
530 * be set to U_ZERO_ERROR.
531 */
532 void _fetch(const UHashElement *element, const SharedObject *&value,
533 UErrorCode &status) const;
534
535 /**
536 * Determine if given hash entry is in progress.
537 * On entry, gCacheMutex must be held.
538 */
539 UBool _inProgress(const UHashElement *element) const;
540
541 /**
542 * Determine if given hash entry is in progress.
543 * On entry, gCacheMutex must be held.
544 */
545 UBool _inProgress(const SharedObject *theValue, UErrorCode creationStatus) const;
546
547 /**
548 * Determine if given hash entry is eligible for eviction.
549 * On entry, gCacheMutex must be held.
550 */
551 UBool _isEvictable(const UHashElement *element) const;
552};
553
554U_NAMESPACE_END}
555
556#endif

/root/firefox-clang/intl/icu/source/common/sharedobject.h

1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5* Copyright (C) 2015-2016, International Business Machines
6* Corporation and others. All Rights Reserved.
7******************************************************************************
8* sharedobject.h
9*/
10
11#ifndef __SHAREDOBJECT_H__
12#define __SHAREDOBJECT_H__
13
14
15#include "unicode/uobject.h"
16#include "umutex.h"
17
18U_NAMESPACE_BEGINnamespace icu_77 {
19
20class SharedObject;
21
22/**
23 * Base class for unified cache exposing enough methods to SharedObject
24 * instances to allow their addRef() and removeRef() methods to
25 * update cache metrics. No other part of ICU, except for SharedObject,
26 * should directly call the methods of this base class.
27 */
28class U_COMMON_API UnifiedCacheBase : public UObject {
29public:
30 UnifiedCacheBase() { }
31
32 /**
33 * Notify the cache implementation that an object was seen transitioning to
34 * zero hard references. The cache may use this to keep track the number of
35 * unreferenced SharedObjects, and to trigger evictions.
36 */
37 virtual void handleUnreferencedObject() const = 0;
38
39 virtual ~UnifiedCacheBase();
40private:
41 UnifiedCacheBase(const UnifiedCacheBase &) = delete;
42 UnifiedCacheBase &operator=(const UnifiedCacheBase &) = delete;
43};
44
45/**
46 * Base class for shared, reference-counted, auto-deleted objects.
47 * Subclasses can be immutable.
48 * If they are mutable, then they must implement their copy constructor
49 * so that copyOnWrite() works.
50 *
51 * Either stack-allocate, use LocalPointer, or use addRef()/removeRef().
52 * Sharing requires reference-counting.
53 */
54class U_COMMON_API SharedObject : public UObject {
55public:
56 /** Initializes totalRefCount, softRefCount to 0. */
57 SharedObject() :
58 softRefCount(0),
59 hardRefCount(0),
60 cachePtr(nullptr) {}
61
62 /** Initializes totalRefCount, softRefCount to 0. */
63 SharedObject(const SharedObject &other) :
64 UObject(other),
65 softRefCount(0),
66 hardRefCount(0),
67 cachePtr(nullptr) {}
68
69 virtual ~SharedObject();
70
71 /**
72 * Increments the number of hard references to this object. Thread-safe.
73 * Not for use from within the Unified Cache implementation.
74 */
75 void addRef() const;
76
77 /**
78 * Decrements the number of hard references to this object, and
79 * arrange for possible cache-eviction and/or deletion if ref
80 * count goes to zero. Thread-safe.
81 *
82 * Not for use from within the UnifiedCache implementation.
83 */
84 void removeRef() const;
85
86 /**
87 * Returns the number of hard references for this object.
88 * Uses a memory barrier.
89 */
90 int32_t getRefCount() const;
91
92 /**
93 * If noHardReferences() == true then this object has no hard references.
94 * Must be called only from within the internals of UnifiedCache.
95 */
96 inline UBool noHardReferences() const { return getRefCount() == 0; }
97
98 /**
99 * If hasHardReferences() == true then this object has hard references.
100 * Must be called only from within the internals of UnifiedCache.
101 */
102 inline UBool hasHardReferences() const { return getRefCount() != 0; }
103
104 /**
105 * Deletes this object if it has no references.
106 * Available for non-cached SharedObjects only. Ownership of cached objects
107 * is with the UnifiedCache, which is solely responsible for eviction and deletion.
108 */
109 void deleteIfZeroRefCount() const;
110
111
112 /**
113 * Returns a writable version of ptr.
114 * If there is exactly one owner, then ptr itself is returned as a
115 * non-const pointer.
116 * If there are multiple owners, then ptr is replaced with a
117 * copy-constructed clone,
118 * and that is returned.
119 * Returns nullptr if cloning failed.
120 *
121 * T must be a subclass of SharedObject.
122 */
123 template<typename T>
124 static T *copyOnWrite(const T *&ptr) {
125 const T *p = ptr;
126 if(p->getRefCount() <= 1) { return const_cast<T *>(p); }
127 T *p2 = new T(*p);
128 if(p2 == nullptr) { return nullptr; }
129 p->removeRef();
130 ptr = p2;
131 p2->addRef();
132 return p2;
133 }
134
135 /**
136 * Makes dest an owner of the object pointed to by src while adjusting
137 * reference counts and deleting the previous object dest pointed to
138 * if necessary. Before this call is made, dest must either be nullptr or
139 * be included in the reference count of the object it points to.
140 *
141 * T must be a subclass of SharedObject.
142 */
143 template<typename T>
144 static void copyPtr(const T *src, const T *&dest) {
145 if(src != dest) {
9
Assuming 'src' is equal to 'dest'
10
Taking false branch
146 if(dest != nullptr) { dest->removeRef(); }
147 dest = src;
148 if(src != nullptr) { src->addRef(); }
149 }
150 }
11
Returning without writing to 'dest'
151
152 /**
153 * Equivalent to copyPtr(nullptr, dest).
154 */
155 template<typename T>
156 static void clearPtr(const T *&ptr) {
157 if (ptr != nullptr) {
158 ptr->removeRef();
159 ptr = nullptr;
160 }
161 }
162
163private:
164 /**
165 * The number of references from the UnifiedCache, which is
166 * the number of times that the sharedObject is stored as a hash table value.
167 * For use by UnifiedCache implementation code only.
168 * All access is synchronized by UnifiedCache's gCacheMutex
169 */
170 mutable int32_t softRefCount;
171 friend class UnifiedCache;
172
173 /**
174 * Reference count, excluding references from within the UnifiedCache implementation.
175 */
176 mutable u_atomic_int32_t hardRefCount;
177
178 mutable const UnifiedCacheBase *cachePtr;
179
180};
181
182U_NAMESPACE_END}
183
184#endif