Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: source/i18n/measfmt.cpp

Issue 1621943002: ICU 56 step 4: Apply post-56 fixes for measure/date format (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/icu.git@56goog
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « source/i18n/i18n.vcxproj.filters ('k') | source/i18n/measunit.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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 */
OLDNEW
« no previous file with comments | « source/i18n/i18n.vcxproj.filters ('k') | source/i18n/measunit.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698