OLD | NEW |
1 /* | 1 /* |
2 ********************************************************************** | 2 ********************************************************************** |
3 * Copyright (c) 2004-2015, International Business Machines | 3 * Copyright (c) 2004-2015, International Business Machines |
4 * Corporation and others. All Rights Reserved. | 4 * Corporation and others. All Rights Reserved. |
5 ********************************************************************** | 5 ********************************************************************** |
6 * Author: Alan Liu | 6 * Author: Alan Liu |
7 * Created: April 20, 2004 | 7 * Created: April 20, 2004 |
8 * Since: ICU 3.0 | 8 * Since: ICU 3.0 |
9 ********************************************************************** | 9 ********************************************************************** |
10 */ | 10 */ |
11 #include "utypeinfo.h" // for 'typeid' to work | 11 #include "utypeinfo.h" // for 'typeid' to work |
12 #include "unicode/utypes.h" | 12 #include "unicode/utypes.h" |
13 | 13 |
14 #if !UCONFIG_NO_FORMATTING | 14 #if !UCONFIG_NO_FORMATTING |
15 | 15 |
16 #include "unicode/measfmt.h" | 16 #include "unicode/measfmt.h" |
17 #include "unicode/numfmt.h" | 17 #include "unicode/numfmt.h" |
18 #include "currfmt.h" | 18 #include "currfmt.h" |
19 #include "unicode/localpointer.h" | 19 #include "unicode/localpointer.h" |
| 20 #include "resource.h" |
20 #include "simplepatternformatter.h" | 21 #include "simplepatternformatter.h" |
21 #include "quantityformatter.h" | 22 #include "quantityformatter.h" |
22 #include "unicode/plurrule.h" | 23 #include "unicode/plurrule.h" |
23 #include "unicode/decimfmt.h" | 24 #include "unicode/decimfmt.h" |
24 #include "uresimp.h" | 25 #include "uresimp.h" |
25 #include "unicode/ures.h" | 26 #include "unicode/ures.h" |
26 #include "ureslocs.h" | 27 #include "ureslocs.h" |
27 #include "cstring.h" | 28 #include "cstring.h" |
28 #include "mutex.h" | 29 #include "mutex.h" |
29 #include "ucln_in.h" | 30 #include "ucln_in.h" |
30 #include "unicode/listformatter.h" | 31 #include "unicode/listformatter.h" |
31 #include "charstr.h" | 32 #include "charstr.h" |
32 #include "unicode/putil.h" | 33 #include "unicode/putil.h" |
33 #include "unicode/smpdtfmt.h" | 34 #include "unicode/smpdtfmt.h" |
34 #include "uassert.h" | 35 #include "uassert.h" |
35 | 36 |
36 #include "sharednumberformat.h" | 37 #include "sharednumberformat.h" |
37 #include "sharedpluralrules.h" | 38 #include "sharedpluralrules.h" |
| 39 #include "standardplural.h" |
38 #include "unifiedcache.h" | 40 #include "unifiedcache.h" |
39 | 41 |
40 #define MEAS_UNIT_COUNT 129 | 42 #define MEAS_UNIT_COUNT 129 |
41 #define WIDTH_INDEX_COUNT (UMEASFMT_WIDTH_NARROW + 1) | 43 #define WIDTH_INDEX_COUNT (UMEASFMT_WIDTH_NARROW + 1) |
42 | 44 |
43 U_NAMESPACE_BEGIN | 45 U_NAMESPACE_BEGIN |
44 | 46 |
45 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat) | 47 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat) |
46 | 48 |
47 // Used to format durations like 5:47 or 21:35:42. | 49 // Used to format durations like 5:47 or 21:35:42. |
(...skipping 21 matching lines...) Expand all Loading... |
69 const TimeZone *gmt = TimeZone::getGMT(); | 71 const TimeZone *gmt = TimeZone::getGMT(); |
70 hourMinute.setTimeZone(*gmt); | 72 hourMinute.setTimeZone(*gmt); |
71 minuteSecond.setTimeZone(*gmt); | 73 minuteSecond.setTimeZone(*gmt); |
72 hourMinuteSecond.setTimeZone(*gmt); | 74 hourMinuteSecond.setTimeZone(*gmt); |
73 } | 75 } |
74 private: | 76 private: |
75 NumericDateFormatters(const NumericDateFormatters &other); | 77 NumericDateFormatters(const NumericDateFormatters &other); |
76 NumericDateFormatters &operator=(const NumericDateFormatters &other); | 78 NumericDateFormatters &operator=(const NumericDateFormatters &other); |
77 }; | 79 }; |
78 | 80 |
79 // Instances contain all MeasureFormat specific data for a particular locale. | 81 static UMeasureFormatWidth getRegularWidth(UMeasureFormatWidth width) { |
80 // This data is cached. It is never copied, but is shared via shared pointers. | 82 if (width >= WIDTH_INDEX_COUNT) { |
| 83 return UMEASFMT_WIDTH_NARROW; |
| 84 } |
| 85 return width; |
| 86 } |
| 87 |
| 88 /** |
| 89 * Instances contain all MeasureFormat specific data for a particular locale. |
| 90 * This data is cached. It is never copied, but is shared via shared pointers. |
| 91 * |
| 92 * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of |
| 93 * complete sets of unit & per patterns, |
| 94 * to correspond to the resource data and its aliases. |
| 95 * |
| 96 * TODO: Maybe store more sparsely in general, with pointers rather than potenti
ally-empty objects. |
| 97 */ |
81 class MeasureFormatCacheData : public SharedObject { | 98 class MeasureFormatCacheData : public SharedObject { |
82 public: | 99 public: |
83 QuantityFormatter formatters[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT]; | 100 static const int32_t PER_UNIT_INDEX = StandardPlural::COUNT; |
| 101 static const int32_t PATTERN_COUNT = PER_UNIT_INDEX + 1; |
| 102 |
| 103 /** |
| 104 * Redirection data from root-bundle, top-level sideways aliases. |
| 105 * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root |
| 106 * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data |
| 107 */ |
| 108 UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT]; |
| 109 /** Measure unit -> format width -> array of patterns ("{0} meters") (plural
s + PER_UNIT_INDEX) */ |
| 110 SimplePatternFormatter *patterns[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT][PATTERN
_COUNT]; |
84 SimplePatternFormatter perFormatters[WIDTH_INDEX_COUNT]; | 111 SimplePatternFormatter perFormatters[WIDTH_INDEX_COUNT]; |
85 | 112 |
86 MeasureFormatCacheData(); | 113 MeasureFormatCacheData(); |
| 114 virtual ~MeasureFormatCacheData(); |
| 115 |
| 116 UBool hasPerFormatter(int32_t width) const { |
| 117 // TODO: Create a more obvious way to test if the per-formatter has been
set? |
| 118 // Use pointers, check for NULL? Or add an isValid() method? |
| 119 return perFormatters[width].getPlaceholderCount() == 2; |
| 120 } |
| 121 |
87 void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) { | 122 void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) { |
88 delete currencyFormats[widthIndex]; | 123 delete currencyFormats[widthIndex]; |
89 currencyFormats[widthIndex] = nfToAdopt; | 124 currencyFormats[widthIndex] = nfToAdopt; |
90 } | 125 } |
91 const NumberFormat *getCurrencyFormat(int32_t widthIndex) const { | 126 const NumberFormat *getCurrencyFormat(UMeasureFormatWidth width) const { |
92 return currencyFormats[widthIndex]; | 127 return currencyFormats[getRegularWidth(width)]; |
93 } | 128 } |
94 void adoptIntegerFormat(NumberFormat *nfToAdopt) { | 129 void adoptIntegerFormat(NumberFormat *nfToAdopt) { |
95 delete integerFormat; | 130 delete integerFormat; |
96 integerFormat = nfToAdopt; | 131 integerFormat = nfToAdopt; |
97 } | 132 } |
98 const NumberFormat *getIntegerFormat() const { | 133 const NumberFormat *getIntegerFormat() const { |
99 return integerFormat; | 134 return integerFormat; |
100 } | 135 } |
101 void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) { | 136 void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) { |
102 delete numericDateFormatters; | 137 delete numericDateFormatters; |
103 numericDateFormatters = formattersToAdopt; | 138 numericDateFormatters = formattersToAdopt; |
104 } | 139 } |
105 const NumericDateFormatters *getNumericDateFormatters() const { | 140 const NumericDateFormatters *getNumericDateFormatters() const { |
106 return numericDateFormatters; | 141 return numericDateFormatters; |
107 } | 142 } |
108 void adoptPerUnitFormatter( | 143 |
109 int32_t index, | |
110 int32_t widthIndex, | |
111 SimplePatternFormatter *formatterToAdopt) { | |
112 delete perUnitFormatters[index][widthIndex]; | |
113 perUnitFormatters[index][widthIndex] = formatterToAdopt; | |
114 } | |
115 const SimplePatternFormatter * const * getPerUnitFormattersByIndex( | |
116 int32_t index) const { | |
117 return perUnitFormatters[index]; | |
118 } | |
119 virtual ~MeasureFormatCacheData(); | |
120 private: | 144 private: |
121 NumberFormat *currencyFormats[WIDTH_INDEX_COUNT]; | 145 NumberFormat *currencyFormats[WIDTH_INDEX_COUNT]; |
122 NumberFormat *integerFormat; | 146 NumberFormat *integerFormat; |
123 NumericDateFormatters *numericDateFormatters; | 147 NumericDateFormatters *numericDateFormatters; |
124 SimplePatternFormatter *perUnitFormatters[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT
]; | |
125 MeasureFormatCacheData(const MeasureFormatCacheData &other); | 148 MeasureFormatCacheData(const MeasureFormatCacheData &other); |
126 MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other); | 149 MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other); |
127 }; | 150 }; |
128 | 151 |
129 MeasureFormatCacheData::MeasureFormatCacheData() { | 152 MeasureFormatCacheData::MeasureFormatCacheData() { |
| 153 for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) { |
| 154 widthFallback[i] = UMEASFMT_WIDTH_COUNT; |
| 155 } |
130 for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) { | 156 for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) { |
131 currencyFormats[i] = NULL; | 157 currencyFormats[i] = NULL; |
132 } | 158 } |
133 for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) { | 159 uprv_memset(patterns, 0, sizeof(patterns)); |
134 for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) { | |
135 perUnitFormatters[i][j] = NULL; | |
136 } | |
137 } | |
138 integerFormat = NULL; | 160 integerFormat = NULL; |
139 numericDateFormatters = NULL; | 161 numericDateFormatters = NULL; |
140 } | 162 } |
141 | 163 |
142 MeasureFormatCacheData::~MeasureFormatCacheData() { | 164 MeasureFormatCacheData::~MeasureFormatCacheData() { |
143 for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) { | 165 for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) { |
144 delete currencyFormats[i]; | 166 delete currencyFormats[i]; |
145 } | 167 } |
146 for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) { | 168 for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) { |
147 for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) { | 169 for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) { |
148 delete perUnitFormatters[i][j]; | 170 for (int32_t k = 0; k < PATTERN_COUNT; ++k) { |
| 171 delete patterns[i][j][k]; |
| 172 } |
149 } | 173 } |
150 } | 174 } |
151 delete integerFormat; | 175 delete integerFormat; |
152 delete numericDateFormatters; | 176 delete numericDateFormatters; |
153 } | 177 } |
154 | 178 |
155 static int32_t widthToIndex(UMeasureFormatWidth width) { | |
156 if (width >= WIDTH_INDEX_COUNT) { | |
157 return WIDTH_INDEX_COUNT - 1; | |
158 } | |
159 return width; | |
160 } | |
161 | |
162 static UBool isCurrency(const MeasureUnit &unit) { | 179 static UBool isCurrency(const MeasureUnit &unit) { |
163 return (uprv_strcmp(unit.getType(), "currency") == 0); | 180 return (uprv_strcmp(unit.getType(), "currency") == 0); |
164 } | 181 } |
165 | 182 |
166 static UBool getString( | 183 static UBool getString( |
167 const UResourceBundle *resource, | 184 const UResourceBundle *resource, |
168 UnicodeString &result, | 185 UnicodeString &result, |
169 UErrorCode &status) { | 186 UErrorCode &status) { |
170 int32_t len = 0; | 187 int32_t len = 0; |
171 const UChar *resStr = ures_getString(resource, &len, &status); | 188 const UChar *resStr = ures_getString(resource, &len, &status); |
172 if (U_FAILURE(status)) { | 189 if (U_FAILURE(status)) { |
173 return FALSE; | 190 return FALSE; |
174 } | 191 } |
175 result.setTo(TRUE, resStr, len); | 192 result.setTo(TRUE, resStr, len); |
176 return TRUE; | 193 return TRUE; |
177 } | 194 } |
178 | 195 |
| 196 namespace { |
| 197 |
| 198 static const UChar g_LOCALE_units[] = { |
| 199 0x2F, 0x4C, 0x4F, 0x43, 0x41, 0x4C, 0x45, 0x2F, |
| 200 0x75, 0x6E, 0x69, 0x74, 0x73 |
| 201 }; |
| 202 static const UChar gShort[] = { 0x53, 0x68, 0x6F, 0x72, 0x74 }; |
| 203 static const UChar gNarrow[] = { 0x4E, 0x61, 0x72, 0x72, 0x6F, 0x77 }; |
| 204 |
| 205 /** |
| 206 * Sink for enumerating all of the measurement unit display names. |
| 207 * Contains inner sink classes, each one corresponding to a type of resource tab
le. |
| 208 * The outer sink handles the top-level units, unitsNarrow, and unitsShort table
s. |
| 209 * |
| 210 * More specific bundles (en_GB) are enumerated before their parents (en_001, en
, root): |
| 211 * Only store a value if it is still missing, that is, it has not been overridde
n. |
| 212 * |
| 213 * C++: Each inner sink class has a reference to the main outer sink. |
| 214 * Java: Use non-static inner classes instead. |
| 215 */ |
| 216 struct UnitDataSink : public ResourceTableSink { |
| 217 /** |
| 218 * Sink for a table of display patterns. For example, |
| 219 * unitsShort/duration/hour contains other{"{0} hrs"}. |
| 220 */ |
| 221 struct UnitPatternSink : public ResourceTableSink { |
| 222 UnitPatternSink(UnitDataSink &sink) : outer(sink) {} |
| 223 ~UnitPatternSink(); |
| 224 |
| 225 void setFormatterIfAbsent(int32_t index, const ResourceValue &value, |
| 226 int32_t minPlaceholders, UErrorCode &errorCode
) { |
| 227 SimplePatternFormatter **patterns = |
| 228 &outer.cacheData.patterns[outer.unitIndex][outer.width][0]; |
| 229 if (U_SUCCESS(errorCode) && patterns[index] == NULL) { |
| 230 patterns[index] = new SimplePatternFormatter( |
| 231 value.getUnicodeString(errorCode), minPlaceholders, 1, er
rorCode); |
| 232 if (U_SUCCESS(errorCode) && patterns[index] == NULL) { |
| 233 errorCode = U_MEMORY_ALLOCATION_ERROR; |
| 234 } |
| 235 } |
| 236 } |
| 237 |
| 238 virtual void put(const char *key, const ResourceValue &value, UErrorCode
&errorCode) { |
| 239 if (U_FAILURE(errorCode)) { return; } |
| 240 if (uprv_strcmp(key, "dnam") == 0) { |
| 241 // Skip the unit display name for now. |
| 242 } else if (uprv_strcmp(key, "per") == 0) { |
| 243 // For example, "{0}/h". |
| 244 setFormatterIfAbsent(MeasureFormatCacheData::PER_UNIT_INDEX, val
ue, 1, errorCode); |
| 245 } else { |
| 246 // The key must be one of the plural form strings. For example: |
| 247 // one{"{0} hr"} |
| 248 // other{"{0} hrs"} |
| 249 setFormatterIfAbsent(StandardPlural::indexFromString(key, errorC
ode), value, 0, |
| 250 errorCode); |
| 251 } |
| 252 } |
| 253 UnitDataSink &outer; |
| 254 } patternSink; |
| 255 |
| 256 /** |
| 257 * Sink for a table of per-unit tables. For example, |
| 258 * unitsShort/duration contains tables for duration-unit subtypes day & hour
. |
| 259 */ |
| 260 struct UnitSubtypeSink : public ResourceTableSink { |
| 261 UnitSubtypeSink(UnitDataSink &sink) : outer(sink) {} |
| 262 ~UnitSubtypeSink(); |
| 263 virtual ResourceTableSink *getOrCreateTableSink( |
| 264 const char *key, int32_t /* initialSize */, UErrorCode &errorCod
e) { |
| 265 if (U_FAILURE(errorCode)) { return NULL; } |
| 266 outer.unitIndex = MeasureUnit::internalGetIndexForTypeAndSubtype(out
er.type, key); |
| 267 if (outer.unitIndex >= 0) { |
| 268 return &outer.patternSink; |
| 269 } |
| 270 return NULL; |
| 271 } |
| 272 UnitDataSink &outer; |
| 273 } subtypeSink; |
| 274 |
| 275 /** |
| 276 * Sink for compound x-per-y display pattern. For example, |
| 277 * unitsShort/compound/per may be "{0}/{1}". |
| 278 */ |
| 279 struct UnitCompoundSink : public ResourceTableSink { |
| 280 UnitCompoundSink(UnitDataSink &sink) : outer(sink) {} |
| 281 ~UnitCompoundSink(); |
| 282 virtual void put(const char *key, const ResourceValue &value, UErrorCode
&errorCode) { |
| 283 if (U_SUCCESS(errorCode) && uprv_strcmp(key, "per") == 0) { |
| 284 outer.cacheData.perFormatters[outer.width]. |
| 285 compileMinMaxPlaceholders(value.getUnicodeString(errorCo
de), 2, 2, errorCode); |
| 286 } |
| 287 } |
| 288 UnitDataSink &outer; |
| 289 } compoundSink; |
| 290 |
| 291 /** |
| 292 * Sink for a table of unit type tables. For example, |
| 293 * unitsShort contains tables for area & duration. |
| 294 * It also contains a table for the compound/per pattern. |
| 295 */ |
| 296 struct UnitTypeSink : public ResourceTableSink { |
| 297 UnitTypeSink(UnitDataSink &sink) : outer(sink) {} |
| 298 ~UnitTypeSink(); |
| 299 virtual ResourceTableSink *getOrCreateTableSink( |
| 300 const char *key, int32_t /* initialSize */, UErrorCode &errorCod
e) { |
| 301 if (U_FAILURE(errorCode)) { return NULL; } |
| 302 if (uprv_strcmp(key, "currency") == 0) { |
| 303 // Skip. |
| 304 } else if (uprv_strcmp(key, "compound") == 0) { |
| 305 if (!outer.cacheData.hasPerFormatter(outer.width)) { |
| 306 return &outer.compoundSink; |
| 307 } |
| 308 } else { |
| 309 outer.type = key; |
| 310 return &outer.subtypeSink; |
| 311 } |
| 312 return NULL; |
| 313 } |
| 314 UnitDataSink &outer; |
| 315 } typeSink; |
| 316 |
| 317 UnitDataSink(MeasureFormatCacheData &outputData) |
| 318 : patternSink(*this), subtypeSink(*this), compoundSink(*this), typeS
ink(*this), |
| 319 cacheData(outputData), |
| 320 width(UMEASFMT_WIDTH_COUNT), type(NULL), unitIndex(0) {} |
| 321 ~UnitDataSink(); |
| 322 virtual void put(const char *key, const ResourceValue &value, UErrorCode &er
rorCode) { |
| 323 // Handle aliases like |
| 324 // units:alias{"/LOCALE/unitsShort"} |
| 325 // which should only occur in the root bundle. |
| 326 if (U_FAILURE(errorCode) || value.getType() != URES_ALIAS) { return; } |
| 327 UMeasureFormatWidth sourceWidth = widthFromKey(key); |
| 328 if (sourceWidth == UMEASFMT_WIDTH_COUNT) { |
| 329 // Alias from something we don't care about. |
| 330 return; |
| 331 } |
| 332 UMeasureFormatWidth targetWidth = widthFromAlias(value, errorCode); |
| 333 if (targetWidth == UMEASFMT_WIDTH_COUNT) { |
| 334 // We do not recognize what to fall back to. |
| 335 errorCode = U_INVALID_FORMAT_ERROR; |
| 336 return; |
| 337 } |
| 338 // Check that we do not fall back to another fallback. |
| 339 if (cacheData.widthFallback[targetWidth] != UMEASFMT_WIDTH_COUNT) { |
| 340 errorCode = U_INVALID_FORMAT_ERROR; |
| 341 return; |
| 342 } |
| 343 cacheData.widthFallback[sourceWidth] = targetWidth; |
| 344 } |
| 345 virtual ResourceTableSink *getOrCreateTableSink( |
| 346 const char *key, int32_t /* initialSize */, UErrorCode &errorCode) { |
| 347 if (U_SUCCESS(errorCode) && (width = widthFromKey(key)) != UMEASFMT_WIDT
H_COUNT) { |
| 348 return &typeSink; |
| 349 } |
| 350 return NULL; |
| 351 } |
| 352 |
| 353 static UMeasureFormatWidth widthFromKey(const char *key) { |
| 354 if (uprv_strncmp(key, "units", 5) == 0) { |
| 355 key += 5; |
| 356 if (*key == 0) { |
| 357 return UMEASFMT_WIDTH_WIDE; |
| 358 } else if (uprv_strcmp(key, "Short") == 0) { |
| 359 return UMEASFMT_WIDTH_SHORT; |
| 360 } else if (uprv_strcmp(key, "Narrow") == 0) { |
| 361 return UMEASFMT_WIDTH_NARROW; |
| 362 } |
| 363 } |
| 364 return UMEASFMT_WIDTH_COUNT; |
| 365 } |
| 366 |
| 367 static UMeasureFormatWidth widthFromAlias(const ResourceValue &value, UError
Code &errorCode) { |
| 368 int32_t length; |
| 369 const UChar *s = value.getAliasString(length, errorCode); |
| 370 // For example: "/LOCALE/unitsShort" |
| 371 if (U_SUCCESS(errorCode) && length >= 13 && u_memcmp(s, g_LOCALE_units,
13) == 0) { |
| 372 s += 13; |
| 373 length -= 13; |
| 374 if (*s == 0) { |
| 375 return UMEASFMT_WIDTH_WIDE; |
| 376 } else if (u_strCompare(s, length, gShort, 5, FALSE) == 0) { |
| 377 return UMEASFMT_WIDTH_SHORT; |
| 378 } else if (u_strCompare(s, length, gNarrow, 6, FALSE) == 0) { |
| 379 return UMEASFMT_WIDTH_NARROW; |
| 380 } |
| 381 } |
| 382 return UMEASFMT_WIDTH_COUNT; |
| 383 } |
| 384 |
| 385 // Output data. |
| 386 MeasureFormatCacheData &cacheData; |
| 387 |
| 388 // Path to current data. |
| 389 UMeasureFormatWidth width; |
| 390 const char *type; |
| 391 int32_t unitIndex; |
| 392 }; |
| 393 |
| 394 // Virtual destructors must be defined out of line. |
| 395 UnitDataSink::UnitPatternSink::~UnitPatternSink() {} |
| 396 UnitDataSink::UnitSubtypeSink::~UnitSubtypeSink() {} |
| 397 UnitDataSink::UnitCompoundSink::~UnitCompoundSink() {} |
| 398 UnitDataSink::UnitTypeSink::~UnitTypeSink() {} |
| 399 UnitDataSink::~UnitDataSink() {} |
| 400 |
| 401 } // namespace |
179 | 402 |
180 static UBool loadMeasureUnitData( | 403 static UBool loadMeasureUnitData( |
181 const UResourceBundle *resource, | 404 const UResourceBundle *resource, |
182 MeasureFormatCacheData &cacheData, | 405 MeasureFormatCacheData &cacheData, |
183 UErrorCode &status) { | 406 UErrorCode &status) { |
184 if (U_FAILURE(status)) { | 407 UnitDataSink sink(cacheData); |
185 return FALSE; | 408 ures_getAllTableItemsWithFallback(resource, "", sink, status); |
186 } | |
187 static const char *widthPath[] = {"units", "unitsShort", "unitsNarrow"}; | |
188 MeasureUnit *units = NULL; | |
189 int32_t unitCount = MeasureUnit::getAvailable(units, 0, status); | |
190 while (status == U_BUFFER_OVERFLOW_ERROR) { | |
191 status = U_ZERO_ERROR; | |
192 delete [] units; | |
193 units = new MeasureUnit[unitCount]; | |
194 if (units == NULL) { | |
195 status = U_MEMORY_ALLOCATION_ERROR; | |
196 return FALSE; | |
197 } | |
198 unitCount = MeasureUnit::getAvailable(units, unitCount, status); | |
199 } | |
200 for (int32_t currentWidth = 0; currentWidth < WIDTH_INDEX_COUNT; ++currentWi
dth) { | |
201 // Be sure status is clear since next resource bundle lookup may fail. | |
202 if (U_FAILURE(status)) { | |
203 delete [] units; | |
204 return FALSE; | |
205 } | |
206 LocalUResourceBundlePointer widthBundle( | |
207 ures_getByKeyWithFallback( | |
208 resource, widthPath[currentWidth], NULL, &status)); | |
209 // We may not have data for all widths in all locales. | |
210 if (status == U_MISSING_RESOURCE_ERROR) { | |
211 status = U_ZERO_ERROR; | |
212 continue; | |
213 } | |
214 { | |
215 // compound per | |
216 LocalUResourceBundlePointer compoundPerBundle( | |
217 ures_getByKeyWithFallback( | |
218 widthBundle.getAlias(), | |
219 "compound/per", | |
220 NULL, | |
221 &status)); | |
222 if (U_FAILURE(status)) { | |
223 status = U_ZERO_ERROR; | |
224 } else { | |
225 UnicodeString perPattern; | |
226 getString(compoundPerBundle.getAlias(), perPattern, status); | |
227 cacheData.perFormatters[currentWidth].compile(perPattern, status
); | |
228 } | |
229 } | |
230 for (int32_t currentUnit = 0; currentUnit < unitCount; ++currentUnit) { | |
231 // Be sure status is clear next lookup may fail. | |
232 if (U_FAILURE(status)) { | |
233 delete [] units; | |
234 return FALSE; | |
235 } | |
236 if (isCurrency(units[currentUnit])) { | |
237 continue; | |
238 } | |
239 CharString pathBuffer; | |
240 pathBuffer.append(units[currentUnit].getType(), status) | |
241 .append("/", status) | |
242 .append(units[currentUnit].getSubtype(), status); | |
243 LocalUResourceBundlePointer unitBundle( | |
244 ures_getByKeyWithFallback( | |
245 widthBundle.getAlias(), | |
246 pathBuffer.data(), | |
247 NULL, | |
248 &status)); | |
249 // We may not have data for all units in all widths | |
250 if (status == U_MISSING_RESOURCE_ERROR) { | |
251 status = U_ZERO_ERROR; | |
252 continue; | |
253 } | |
254 // We must have the unit bundle to proceed | |
255 if (U_FAILURE(status)) { | |
256 delete [] units; | |
257 return FALSE; | |
258 } | |
259 int32_t size = ures_getSize(unitBundle.getAlias()); | |
260 for (int32_t plIndex = 0; plIndex < size; ++plIndex) { | |
261 LocalUResourceBundlePointer pluralBundle( | |
262 ures_getByIndex( | |
263 unitBundle.getAlias(), plIndex, NULL, &status)); | |
264 if (U_FAILURE(status)) { | |
265 delete [] units; | |
266 return FALSE; | |
267 } | |
268 const char * resKey = ures_getKey(pluralBundle.getAlias()); | |
269 if (uprv_strcmp(resKey, "dnam") == 0) { | |
270 continue; // skip display name & per pattern (new in CLDR 26
/ ICU 54) for now, not part of plurals | |
271 } | |
272 if (uprv_strcmp(resKey, "per") == 0) { | |
273 UnicodeString perPattern; | |
274 getString(pluralBundle.getAlias(), perPattern, status); | |
275 cacheData.adoptPerUnitFormatter( | |
276 units[currentUnit].getIndex(), | |
277 currentWidth, | |
278 new SimplePatternFormatter(perPattern)); | |
279 continue; | |
280 } | |
281 UnicodeString rawPattern; | |
282 getString(pluralBundle.getAlias(), rawPattern, status); | |
283 cacheData.formatters[units[currentUnit].getIndex()][currentWidth
].add( | |
284 resKey, | |
285 rawPattern, | |
286 status); | |
287 } | |
288 } | |
289 } | |
290 delete [] units; | |
291 return U_SUCCESS(status); | 409 return U_SUCCESS(status); |
292 } | 410 } |
293 | 411 |
294 static UnicodeString loadNumericDateFormatterPattern( | 412 static UnicodeString loadNumericDateFormatterPattern( |
295 const UResourceBundle *resource, | 413 const UResourceBundle *resource, |
296 const char *pattern, | 414 const char *pattern, |
297 UErrorCode &status) { | 415 UErrorCode &status) { |
298 UnicodeString result; | 416 UnicodeString result; |
299 if (U_FAILURE(status)) { | 417 if (U_FAILURE(status)) { |
300 return result; | 418 return result; |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 MeasureFormat::MeasureFormat(const MeasureFormat &other) : | 597 MeasureFormat::MeasureFormat(const MeasureFormat &other) : |
480 Format(other), | 598 Format(other), |
481 cache(other.cache), | 599 cache(other.cache), |
482 numberFormat(other.numberFormat), | 600 numberFormat(other.numberFormat), |
483 pluralRules(other.pluralRules), | 601 pluralRules(other.pluralRules), |
484 width(other.width), | 602 width(other.width), |
485 listFormatter(NULL) { | 603 listFormatter(NULL) { |
486 cache->addRef(); | 604 cache->addRef(); |
487 numberFormat->addRef(); | 605 numberFormat->addRef(); |
488 pluralRules->addRef(); | 606 pluralRules->addRef(); |
489 listFormatter = new ListFormatter(*other.listFormatter); | 607 if (other.listFormatter != NULL) { |
| 608 listFormatter = new ListFormatter(*other.listFormatter); |
| 609 } |
490 } | 610 } |
491 | 611 |
492 MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) { | 612 MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) { |
493 if (this == &other) { | 613 if (this == &other) { |
494 return *this; | 614 return *this; |
495 } | 615 } |
496 Format::operator=(other); | 616 Format::operator=(other); |
497 SharedObject::copyPtr(other.cache, cache); | 617 SharedObject::copyPtr(other.cache, cache); |
498 SharedObject::copyPtr(other.numberFormat, numberFormat); | 618 SharedObject::copyPtr(other.numberFormat, numberFormat); |
499 SharedObject::copyPtr(other.pluralRules, pluralRules); | 619 SharedObject::copyPtr(other.pluralRules, pluralRules); |
500 width = other.width; | 620 width = other.width; |
501 delete listFormatter; | 621 delete listFormatter; |
502 listFormatter = new ListFormatter(*other.listFormatter); | 622 if (other.listFormatter != NULL) { |
| 623 listFormatter = new ListFormatter(*other.listFormatter); |
| 624 } else { |
| 625 listFormatter = NULL; |
| 626 } |
503 return *this; | 627 return *this; |
504 } | 628 } |
505 | 629 |
506 MeasureFormat::MeasureFormat() : | 630 MeasureFormat::MeasureFormat() : |
507 cache(NULL), | 631 cache(NULL), |
508 numberFormat(NULL), | 632 numberFormat(NULL), |
509 pluralRules(NULL), | 633 pluralRules(NULL), |
510 width(UMEASFMT_WIDTH_SHORT), | 634 width(UMEASFMT_WIDTH_SHORT), |
511 listFormatter(NULL) { | 635 listFormatter(NULL) { |
512 } | 636 } |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 } else { | 831 } else { |
708 adoptNumberFormat(nf.orphan(), status); | 832 adoptNumberFormat(nf.orphan(), status); |
709 if (U_FAILURE(status)) { | 833 if (U_FAILURE(status)) { |
710 return; | 834 return; |
711 } | 835 } |
712 } | 836 } |
713 width = w; | 837 width = w; |
714 delete listFormatter; | 838 delete listFormatter; |
715 listFormatter = ListFormatter::createInstance( | 839 listFormatter = ListFormatter::createInstance( |
716 locale, | 840 locale, |
717 listStyles[widthToIndex(width)], | 841 listStyles[getRegularWidth(width)], |
718 status); | 842 status); |
719 } | 843 } |
720 | 844 |
721 void MeasureFormat::adoptNumberFormat( | 845 void MeasureFormat::adoptNumberFormat( |
722 NumberFormat *nfToAdopt, UErrorCode &status) { | 846 NumberFormat *nfToAdopt, UErrorCode &status) { |
723 LocalPointer<NumberFormat> nf(nfToAdopt); | 847 LocalPointer<NumberFormat> nf(nfToAdopt); |
724 if (U_FAILURE(status)) { | 848 if (U_FAILURE(status)) { |
725 return; | 849 return; |
726 } | 850 } |
727 SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias()); | 851 SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias()); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 FieldPosition &pos, | 888 FieldPosition &pos, |
765 UErrorCode &status) const { | 889 UErrorCode &status) const { |
766 if (U_FAILURE(status)) { | 890 if (U_FAILURE(status)) { |
767 return appendTo; | 891 return appendTo; |
768 } | 892 } |
769 const Formattable& amtNumber = measure.getNumber(); | 893 const Formattable& amtNumber = measure.getNumber(); |
770 const MeasureUnit& amtUnit = measure.getUnit(); | 894 const MeasureUnit& amtUnit = measure.getUnit(); |
771 if (isCurrency(amtUnit)) { | 895 if (isCurrency(amtUnit)) { |
772 UChar isoCode[4]; | 896 UChar isoCode[4]; |
773 u_charsToUChars(amtUnit.getSubtype(), isoCode, 4); | 897 u_charsToUChars(amtUnit.getSubtype(), isoCode, 4); |
774 return cache->getCurrencyFormat(widthToIndex(width))->format( | 898 return cache->getCurrencyFormat(width)->format( |
775 new CurrencyAmount(amtNumber, isoCode, status), | 899 new CurrencyAmount(amtNumber, isoCode, status), |
776 appendTo, | 900 appendTo, |
777 pos, | 901 pos, |
778 status); | 902 status); |
779 } | 903 } |
780 const QuantityFormatter *quantityFormatter = getQuantityFormatter( | 904 UnicodeString formattedNumber; |
781 amtUnit.getIndex(), widthToIndex(width), status); | 905 StandardPlural::Form pluralForm = QuantityFormatter::selectPlural( |
782 if (U_FAILURE(status)) { | 906 amtNumber, nf, **pluralRules, formattedNumber, pos, status); |
783 return appendTo; | 907 const SimplePatternFormatter *formatter = getPluralFormatter(amtUnit, width,
pluralForm, status); |
784 } | 908 return QuantityFormatter::format(*formatter, formattedNumber, appendTo, pos,
status); |
785 return quantityFormatter->format( | |
786 amtNumber, | |
787 nf, | |
788 **pluralRules, | |
789 appendTo, | |
790 pos, | |
791 status); | |
792 } | 909 } |
793 | 910 |
794 // Formats hours-minutes-seconds as 5:37:23 or similar. | 911 // Formats hours-minutes-seconds as 5:37:23 or similar. |
795 UnicodeString &MeasureFormat::formatNumeric( | 912 UnicodeString &MeasureFormat::formatNumeric( |
796 const Formattable *hms, // always length 3 | 913 const Formattable *hms, // always length 3 |
797 int32_t bitMap, // 1=hourset, 2=minuteset, 4=secondset | 914 int32_t bitMap, // 1=hourset, 2=minuteset, 4=secondset |
798 UnicodeString &appendTo, | 915 UnicodeString &appendTo, |
799 UErrorCode &status) const { | 916 UErrorCode &status) const { |
800 if (U_FAILURE(status)) { | 917 if (U_FAILURE(status)) { |
801 return appendTo; | 918 return appendTo; |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 appendRange( | 1030 appendRange( |
914 draft, | 1031 draft, |
915 smallestFieldPosition.getEndIndex(), | 1032 smallestFieldPosition.getEndIndex(), |
916 appendTo); | 1033 appendTo); |
917 } else { | 1034 } else { |
918 appendTo.append(draft); | 1035 appendTo.append(draft); |
919 } | 1036 } |
920 return appendTo; | 1037 return appendTo; |
921 } | 1038 } |
922 | 1039 |
923 const QuantityFormatter *MeasureFormat::getQuantityFormatter( | 1040 const SimplePatternFormatter *MeasureFormat::getFormatterOrNull( |
924 int32_t index, | 1041 const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index) const
{ |
925 int32_t widthIndex, | 1042 width = getRegularWidth(width); |
| 1043 SimplePatternFormatter *const (*unitPatterns)[MeasureFormatCacheData::PATTER
N_COUNT] = |
| 1044 &cache->patterns[unit.getIndex()][0]; |
| 1045 if (unitPatterns[width][index] != NULL) { |
| 1046 return unitPatterns[width][index]; |
| 1047 } |
| 1048 int32_t fallbackWidth = cache->widthFallback[width]; |
| 1049 if (fallbackWidth != UMEASFMT_WIDTH_COUNT && unitPatterns[fallbackWidth][ind
ex] != NULL) { |
| 1050 return unitPatterns[fallbackWidth][index]; |
| 1051 } |
| 1052 return NULL; |
| 1053 } |
| 1054 |
| 1055 const SimplePatternFormatter *MeasureFormat::getFormatter( |
| 1056 const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index, |
| 1057 UErrorCode &errorCode) const { |
| 1058 if (U_FAILURE(errorCode)) { |
| 1059 return NULL; |
| 1060 } |
| 1061 const SimplePatternFormatter *pattern = getFormatterOrNull(unit, width, inde
x); |
| 1062 if (pattern == NULL) { |
| 1063 errorCode = U_MISSING_RESOURCE_ERROR; |
| 1064 } |
| 1065 return pattern; |
| 1066 } |
| 1067 |
| 1068 const SimplePatternFormatter *MeasureFormat::getPluralFormatter( |
| 1069 const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index, |
| 1070 UErrorCode &errorCode) const { |
| 1071 if (U_FAILURE(errorCode)) { |
| 1072 return NULL; |
| 1073 } |
| 1074 if (index != StandardPlural::OTHER) { |
| 1075 const SimplePatternFormatter *pattern = getFormatterOrNull(unit, width,
index); |
| 1076 if (pattern != NULL) { |
| 1077 return pattern; |
| 1078 } |
| 1079 } |
| 1080 return getFormatter(unit, width, StandardPlural::OTHER, errorCode); |
| 1081 } |
| 1082 |
| 1083 const SimplePatternFormatter *MeasureFormat::getPerFormatter( |
| 1084 UMeasureFormatWidth width, |
926 UErrorCode &status) const { | 1085 UErrorCode &status) const { |
927 if (U_FAILURE(status)) { | 1086 if (U_FAILURE(status)) { |
928 return NULL; | 1087 return NULL; |
929 } | 1088 } |
930 const QuantityFormatter *formatters = | 1089 width = getRegularWidth(width); |
931 cache->formatters[index]; | 1090 const SimplePatternFormatter * perFormatters = cache->perFormatters; |
932 if (formatters[widthIndex].isValid()) { | 1091 if (perFormatters[width].getPlaceholderCount() == 2) { |
933 return &formatters[widthIndex]; | 1092 return &perFormatters[width]; |
934 } | 1093 } |
935 if (formatters[UMEASFMT_WIDTH_SHORT].isValid()) { | 1094 int32_t fallbackWidth = cache->widthFallback[width]; |
936 return &formatters[UMEASFMT_WIDTH_SHORT]; | 1095 if (fallbackWidth != UMEASFMT_WIDTH_COUNT && |
| 1096 perFormatters[fallbackWidth].getPlaceholderCount() == 2) { |
| 1097 return &perFormatters[fallbackWidth]; |
937 } | 1098 } |
938 status = U_MISSING_RESOURCE_ERROR; | 1099 status = U_MISSING_RESOURCE_ERROR; |
939 return NULL; | 1100 return NULL; |
940 } | 1101 } |
941 | 1102 |
942 const SimplePatternFormatter *MeasureFormat::getPerUnitFormatter( | |
943 int32_t index, | |
944 int32_t widthIndex) const { | |
945 const SimplePatternFormatter * const * perUnitFormatters = | |
946 cache->getPerUnitFormattersByIndex(index); | |
947 if (perUnitFormatters[widthIndex] != NULL) { | |
948 return perUnitFormatters[widthIndex]; | |
949 } | |
950 if (perUnitFormatters[UMEASFMT_WIDTH_SHORT] != NULL) { | |
951 return perUnitFormatters[UMEASFMT_WIDTH_SHORT]; | |
952 } | |
953 return NULL; | |
954 } | |
955 | |
956 const SimplePatternFormatter *MeasureFormat::getPerFormatter( | |
957 int32_t widthIndex, | |
958 UErrorCode &status) const { | |
959 if (U_FAILURE(status)) { | |
960 return NULL; | |
961 } | |
962 const SimplePatternFormatter * perFormatters = cache->perFormatters; | |
963 | |
964 if (perFormatters[widthIndex].getPlaceholderCount() == 2) { | |
965 return &perFormatters[widthIndex]; | |
966 } | |
967 if (perFormatters[UMEASFMT_WIDTH_SHORT].getPlaceholderCount() == 2) { | |
968 return &perFormatters[UMEASFMT_WIDTH_SHORT]; | |
969 } | |
970 status = U_MISSING_RESOURCE_ERROR; | |
971 return NULL; | |
972 } | |
973 | |
974 static void getPerUnitString( | |
975 const QuantityFormatter &formatter, | |
976 UnicodeString &result) { | |
977 result = formatter.getByVariant("one")->getPatternWithNoPlaceholders(); | |
978 result.trim(); | |
979 } | |
980 | |
981 int32_t MeasureFormat::withPerUnitAndAppend( | 1103 int32_t MeasureFormat::withPerUnitAndAppend( |
982 const UnicodeString &formatted, | 1104 const UnicodeString &formatted, |
983 const MeasureUnit &perUnit, | 1105 const MeasureUnit &perUnit, |
984 UnicodeString &appendTo, | 1106 UnicodeString &appendTo, |
985 UErrorCode &status) const { | 1107 UErrorCode &status) const { |
986 int32_t offset = -1; | 1108 int32_t offset = -1; |
987 if (U_FAILURE(status)) { | 1109 if (U_FAILURE(status)) { |
988 return offset; | 1110 return offset; |
989 } | 1111 } |
990 const SimplePatternFormatter *perUnitFormatter = getPerUnitFormatter( | 1112 const SimplePatternFormatter *perUnitFormatter = |
991 perUnit.getIndex(), widthToIndex(width)); | 1113 getFormatterOrNull(perUnit, width, MeasureFormatCacheData::PER_UNIT_
INDEX); |
992 if (perUnitFormatter != NULL) { | 1114 if (perUnitFormatter != NULL) { |
993 const UnicodeString *params[] = {&formatted}; | 1115 const UnicodeString *params[] = {&formatted}; |
994 perUnitFormatter->formatAndAppend( | 1116 perUnitFormatter->formatAndAppend( |
995 params, | 1117 params, |
996 UPRV_LENGTHOF(params), | 1118 UPRV_LENGTHOF(params), |
997 appendTo, | 1119 appendTo, |
998 &offset, | 1120 &offset, |
999 1, | 1121 1, |
1000 status); | 1122 status); |
1001 return offset; | 1123 return offset; |
1002 } | 1124 } |
1003 const SimplePatternFormatter *perFormatter = getPerFormatter( | 1125 const SimplePatternFormatter *perFormatter = getPerFormatter(width, status); |
1004 widthToIndex(width), status); | 1126 const SimplePatternFormatter *pattern = |
1005 const QuantityFormatter *qf = getQuantityFormatter( | 1127 getPluralFormatter(perUnit, width, StandardPlural::ONE, status); |
1006 perUnit.getIndex(), widthToIndex(width), status); | |
1007 if (U_FAILURE(status)) { | 1128 if (U_FAILURE(status)) { |
1008 return offset; | 1129 return offset; |
1009 } | 1130 } |
1010 UnicodeString perUnitString; | 1131 UnicodeString perUnitString = pattern->getPatternWithNoPlaceholders(); |
1011 getPerUnitString(*qf, perUnitString); | 1132 perUnitString.trim(); |
1012 const UnicodeString *params[] = {&formatted, &perUnitString}; | 1133 const UnicodeString *params[] = {&formatted, &perUnitString}; |
1013 perFormatter->formatAndAppend( | 1134 perFormatter->formatAndAppend( |
1014 params, | 1135 params, |
1015 UPRV_LENGTHOF(params), | 1136 UPRV_LENGTHOF(params), |
1016 appendTo, | 1137 appendTo, |
1017 &offset, | 1138 &offset, |
1018 1, | 1139 1, |
1019 status); | 1140 status); |
1020 return offset; | 1141 return offset; |
1021 } | 1142 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1087 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) { | 1208 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) { |
1088 if (U_FAILURE(ec)) { | 1209 if (U_FAILURE(ec)) { |
1089 return NULL; | 1210 return NULL; |
1090 } | 1211 } |
1091 return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec); | 1212 return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec); |
1092 } | 1213 } |
1093 | 1214 |
1094 U_NAMESPACE_END | 1215 U_NAMESPACE_END |
1095 | 1216 |
1096 #endif /* #if !UCONFIG_NO_FORMATTING */ | 1217 #endif /* #if !UCONFIG_NO_FORMATTING */ |
OLD | NEW |