2 **********************************************************************
3 * Copyright (c) 2004-2016, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
7 * Created: April 20, 2004
9 **********************************************************************
11 #include "utypeinfo.h" // for 'typeid' to work
12 #include "unicode/utypes.h"
14 #if !UCONFIG_NO_FORMATTING
16 #include "unicode/measfmt.h"
17 #include "unicode/numfmt.h"
19 #include "unicode/localpointer.h"
21 #include "unicode/simpleformatter.h"
22 #include "quantityformatter.h"
23 #include "unicode/plurrule.h"
24 #include "unicode/decimfmt.h"
26 #include "unicode/ures.h"
31 #include "unicode/listformatter.h"
33 #include "unicode/putil.h"
34 #include "unicode/smpdtfmt.h"
36 #include "unicode/uameasureformat.h"
39 #include "sharednumberformat.h"
40 #include "sharedpluralrules.h"
41 #include "standardplural.h"
42 #include "unifiedcache.h"
44 #define MEAS_UNIT_COUNT 134
45 #define WIDTH_INDEX_COUNT (UMEASFMT_WIDTH_NARROW + 1)
49 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat
)
51 // Used to format durations like 5:47 or 21:35:42.
52 class NumericDateFormatters
: public UMemory
{
55 SimpleDateFormat hourMinute
;
58 SimpleDateFormat minuteSecond
;
60 // formats like H:mm:ss
61 SimpleDateFormat hourMinuteSecond
;
63 // Constructor that takes the actual patterns for hour-minute,
64 // minute-second, and hour-minute-second respectively.
65 NumericDateFormatters(
66 const UnicodeString
&hm
,
67 const UnicodeString
&ms
,
68 const UnicodeString
&hms
,
70 hourMinute(hm
, status
),
71 minuteSecond(ms
, status
),
72 hourMinuteSecond(hms
, status
) {
73 const TimeZone
*gmt
= TimeZone::getGMT();
74 hourMinute
.setTimeZone(*gmt
);
75 minuteSecond
.setTimeZone(*gmt
);
76 hourMinuteSecond
.setTimeZone(*gmt
);
79 NumericDateFormatters(const NumericDateFormatters
&other
);
80 NumericDateFormatters
&operator=(const NumericDateFormatters
&other
);
83 static UMeasureFormatWidth
getRegularWidth(UMeasureFormatWidth width
) {
84 if (width
>= WIDTH_INDEX_COUNT
) {
85 return UMEASFMT_WIDTH_NARROW
;
91 * Instances contain all MeasureFormat specific data for a particular locale.
92 * This data is cached. It is never copied, but is shared via shared pointers.
94 * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of
95 * complete sets of unit & per patterns,
96 * to correspond to the resource data and its aliases.
98 * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
100 class MeasureFormatCacheData
: public SharedObject
{
102 static const int32_t PER_UNIT_INDEX
= StandardPlural::COUNT
;
103 static const int32_t PATTERN_COUNT
= PER_UNIT_INDEX
+ 1;
106 * Redirection data from root-bundle, top-level sideways aliases.
107 * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root
108 * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data
110 UMeasureFormatWidth widthFallback
[WIDTH_INDEX_COUNT
];
111 /** Measure unit -> format width -> array of patterns ("{0} meters") (plurals + PER_UNIT_INDEX) */
112 SimpleFormatter
*patterns
[MEAS_UNIT_COUNT
][WIDTH_INDEX_COUNT
][PATTERN_COUNT
];
113 SimpleFormatter perFormatters
[WIDTH_INDEX_COUNT
];
114 const UChar
* displayNames
[MEAS_UNIT_COUNT
][WIDTH_INDEX_COUNT
]; // Apple-specific for now
116 MeasureFormatCacheData();
117 virtual ~MeasureFormatCacheData();
119 UBool
hasPerFormatter(int32_t width
) const {
120 // TODO: Create a more obvious way to test if the per-formatter has been set?
121 // Use pointers, check for NULL? Or add an isValid() method?
122 return perFormatters
[width
].getArgumentLimit() == 2;
125 void adoptCurrencyFormat(int32_t widthIndex
, NumberFormat
*nfToAdopt
) {
126 delete currencyFormats
[widthIndex
];
127 currencyFormats
[widthIndex
] = nfToAdopt
;
129 const NumberFormat
*getCurrencyFormat(UMeasureFormatWidth width
) const {
130 return currencyFormats
[getRegularWidth(width
)];
132 void adoptIntegerFormat(NumberFormat
*nfToAdopt
) {
133 delete integerFormat
;
134 integerFormat
= nfToAdopt
;
136 const NumberFormat
*getIntegerFormat() const {
137 return integerFormat
;
139 void adoptNumericDateFormatters(NumericDateFormatters
*formattersToAdopt
) {
140 delete numericDateFormatters
;
141 numericDateFormatters
= formattersToAdopt
;
143 const NumericDateFormatters
*getNumericDateFormatters() const {
144 return numericDateFormatters
;
146 void setDisplayName( // Apple=specific
149 const UChar
*namePtr
) {
150 if (widthIndex
< WIDTH_INDEX_COUNT
) {
151 displayNames
[unitIndex
][widthIndex
] = namePtr
;
154 const UChar
* getDisplayName( // Apple=specific
156 int32_t widthIndex
) const {
157 return (widthIndex
< WIDTH_INDEX_COUNT
)? displayNames
[unitIndex
][widthIndex
]: NULL
;
161 NumberFormat
*currencyFormats
[WIDTH_INDEX_COUNT
];
162 NumberFormat
*integerFormat
;
163 NumericDateFormatters
*numericDateFormatters
;
164 MeasureFormatCacheData(const MeasureFormatCacheData
&other
);
165 MeasureFormatCacheData
&operator=(const MeasureFormatCacheData
&other
);
168 MeasureFormatCacheData::MeasureFormatCacheData() {
169 for (int32_t i
= 0; i
< WIDTH_INDEX_COUNT
; ++i
) {
170 widthFallback
[i
] = UMEASFMT_WIDTH_COUNT
;
172 for (int32_t i
= 0; i
< UPRV_LENGTHOF(currencyFormats
); ++i
) {
173 currencyFormats
[i
] = NULL
;
175 uprv_memset(patterns
, 0, sizeof(patterns
));
176 integerFormat
= NULL
;
177 numericDateFormatters
= NULL
;
178 // Apple-specific for now:
179 for (int32_t i
= 0; i
< MEAS_UNIT_COUNT
; ++i
) {
180 for (int32_t j
= 0; j
< WIDTH_INDEX_COUNT
; ++j
) {
181 displayNames
[i
][j
] = NULL
;
186 MeasureFormatCacheData::~MeasureFormatCacheData() {
187 for (int32_t i
= 0; i
< UPRV_LENGTHOF(currencyFormats
); ++i
) {
188 delete currencyFormats
[i
];
190 for (int32_t i
= 0; i
< MEAS_UNIT_COUNT
; ++i
) {
191 for (int32_t j
= 0; j
< WIDTH_INDEX_COUNT
; ++j
) {
192 for (int32_t k
= 0; k
< PATTERN_COUNT
; ++k
) {
193 delete patterns
[i
][j
][k
];
197 delete integerFormat
;
198 delete numericDateFormatters
;
201 static UBool
isCurrency(const MeasureUnit
&unit
) {
202 return (uprv_strcmp(unit
.getType(), "currency") == 0);
205 static UBool
getString(
206 const UResourceBundle
*resource
,
207 UnicodeString
&result
,
208 UErrorCode
&status
) {
210 const UChar
*resStr
= ures_getString(resource
, &len
, &status
);
211 if (U_FAILURE(status
)) {
214 result
.setTo(TRUE
, resStr
, len
);
220 static const UChar g_LOCALE_units
[] = {
221 0x2F, 0x4C, 0x4F, 0x43, 0x41, 0x4C, 0x45, 0x2F,
222 0x75, 0x6E, 0x69, 0x74, 0x73
224 static const UChar gShort
[] = { 0x53, 0x68, 0x6F, 0x72, 0x74 };
225 static const UChar gNarrow
[] = { 0x4E, 0x61, 0x72, 0x72, 0x6F, 0x77 };
228 * Sink for enumerating all of the measurement unit display names.
229 * Contains inner sink classes, each one corresponding to a type of resource table.
230 * The outer sink handles the top-level units, unitsNarrow, and unitsShort tables.
232 * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root):
233 * Only store a value if it is still missing, that is, it has not been overridden.
235 * C++: Each inner sink class has a reference to the main outer sink.
236 * Java: Use non-static inner classes instead.
238 struct UnitDataSink
: public ResourceTableSink
{
240 * Sink for a table of display patterns. For example,
241 * unitsShort/duration/hour contains other{"{0} hrs"}.
243 struct UnitPatternSink
: public ResourceTableSink
{
244 UnitPatternSink(UnitDataSink
&sink
) : outer(sink
) {}
247 void setFormatterIfAbsent(int32_t index
, const ResourceValue
&value
,
248 int32_t minPlaceholders
, UErrorCode
&errorCode
) {
249 SimpleFormatter
**patterns
=
250 &outer
.cacheData
.patterns
[outer
.unitIndex
][outer
.width
][0];
251 if (U_SUCCESS(errorCode
) && patterns
[index
] == NULL
) {
252 patterns
[index
] = new SimpleFormatter(
253 value
.getUnicodeString(errorCode
), minPlaceholders
, 1, errorCode
);
254 if (U_SUCCESS(errorCode
) && patterns
[index
] == NULL
) {
255 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
261 void setDisplayNameIfAbsent(const ResourceValue
&value
, UErrorCode
&errorCode
) {
262 if (U_SUCCESS(errorCode
) && outer
.width
< WIDTH_INDEX_COUNT
) {
263 const UChar
** displayName
= &outer
.cacheData
.displayNames
[outer
.unitIndex
][outer
.width
];
264 if (*displayName
== NULL
&& value
.getType() == URES_STRING
) {
266 *displayName
= value
.getString(nameLen
, errorCode
);
271 virtual void put(const char *key
, const ResourceValue
&value
, UErrorCode
&errorCode
) {
272 if (U_FAILURE(errorCode
)) { return; }
273 if (uprv_strcmp(key
, "dnam") == 0) {
274 // Apple-specific for now, save name data
275 setDisplayNameIfAbsent(value
, errorCode
);
276 } else if (uprv_strcmp(key
, "per") == 0) {
277 // For example, "{0}/h".
278 setFormatterIfAbsent(MeasureFormatCacheData::PER_UNIT_INDEX
, value
, 1, errorCode
);
280 // The key must be one of the plural form strings. For example:
283 setFormatterIfAbsent(StandardPlural::indexFromString(key
, errorCode
), value
, 0,
291 * Sink for a table of per-unit tables. For example,
292 * unitsShort/duration contains tables for duration-unit subtypes day & hour.
294 struct UnitSubtypeSink
: public ResourceTableSink
{
295 UnitSubtypeSink(UnitDataSink
&sink
) : outer(sink
) {}
297 virtual ResourceTableSink
*getOrCreateTableSink(
298 const char *key
, int32_t /* initialSize */, UErrorCode
&errorCode
) {
299 if (U_FAILURE(errorCode
)) { return NULL
; }
300 outer
.unitIndex
= MeasureUnit::internalGetIndexForTypeAndSubtype(outer
.type
, key
);
301 if (outer
.unitIndex
>= 0) {
302 return &outer
.patternSink
;
310 * Sink for compound x-per-y display pattern. For example,
311 * unitsShort/compound/per may be "{0}/{1}".
313 struct UnitCompoundSink
: public ResourceTableSink
{
314 UnitCompoundSink(UnitDataSink
&sink
) : outer(sink
) {}
316 virtual void put(const char *key
, const ResourceValue
&value
, UErrorCode
&errorCode
) {
317 if (U_SUCCESS(errorCode
) && uprv_strcmp(key
, "per") == 0) {
318 outer
.cacheData
.perFormatters
[outer
.width
].
319 applyPatternMinMaxArguments(value
.getUnicodeString(errorCode
), 2, 2, errorCode
);
326 * Sink for a table of unit type tables. For example,
327 * unitsShort contains tables for area & duration.
328 * It also contains a table for the compound/per pattern.
330 struct UnitTypeSink
: public ResourceTableSink
{
331 UnitTypeSink(UnitDataSink
&sink
) : outer(sink
) {}
333 virtual ResourceTableSink
*getOrCreateTableSink(
334 const char *key
, int32_t /* initialSize */, UErrorCode
&errorCode
) {
335 if (U_FAILURE(errorCode
)) { return NULL
; }
336 if (uprv_strcmp(key
, "currency") == 0) {
338 } else if (uprv_strcmp(key
, "compound") == 0) {
339 if (!outer
.cacheData
.hasPerFormatter(outer
.width
)) {
340 return &outer
.compoundSink
;
344 return &outer
.subtypeSink
;
351 UnitDataSink(MeasureFormatCacheData
&outputData
)
352 : patternSink(*this), subtypeSink(*this), compoundSink(*this), typeSink(*this),
353 cacheData(outputData
),
354 width(UMEASFMT_WIDTH_COUNT
), type(NULL
), unitIndex(0) {}
356 virtual void put(const char *key
, const ResourceValue
&value
, UErrorCode
&errorCode
) {
357 // Handle aliases like
358 // units:alias{"/LOCALE/unitsShort"}
359 // which should only occur in the root bundle.
360 if (U_FAILURE(errorCode
) || value
.getType() != URES_ALIAS
) { return; }
361 UMeasureFormatWidth sourceWidth
= widthFromKey(key
);
362 if (sourceWidth
== UMEASFMT_WIDTH_COUNT
) {
363 // Alias from something we don't care about.
366 UMeasureFormatWidth targetWidth
= widthFromAlias(value
, errorCode
);
367 if (targetWidth
== UMEASFMT_WIDTH_COUNT
) {
368 // We do not recognize what to fall back to.
369 errorCode
= U_INVALID_FORMAT_ERROR
;
372 // Check that we do not fall back to another fallback.
373 if (cacheData
.widthFallback
[targetWidth
] != UMEASFMT_WIDTH_COUNT
) {
374 errorCode
= U_INVALID_FORMAT_ERROR
;
377 cacheData
.widthFallback
[sourceWidth
] = targetWidth
;
379 virtual ResourceTableSink
*getOrCreateTableSink(
380 const char *key
, int32_t /* initialSize */, UErrorCode
&errorCode
) {
381 if (U_SUCCESS(errorCode
) && (width
= widthFromKey(key
)) != UMEASFMT_WIDTH_COUNT
) {
387 static UMeasureFormatWidth
widthFromKey(const char *key
) {
388 if (uprv_strncmp(key
, "units", 5) == 0) {
391 return UMEASFMT_WIDTH_WIDE
;
392 } else if (uprv_strcmp(key
, "Short") == 0) {
393 return UMEASFMT_WIDTH_SHORT
;
394 } else if (uprv_strcmp(key
, "Narrow") == 0) {
395 return UMEASFMT_WIDTH_NARROW
;
398 return UMEASFMT_WIDTH_COUNT
;
401 static UMeasureFormatWidth
widthFromAlias(const ResourceValue
&value
, UErrorCode
&errorCode
) {
403 const UChar
*s
= value
.getAliasString(length
, errorCode
);
404 // For example: "/LOCALE/unitsShort"
405 if (U_SUCCESS(errorCode
) && length
>= 13 && u_memcmp(s
, g_LOCALE_units
, 13) == 0) {
409 return UMEASFMT_WIDTH_WIDE
;
410 } else if (u_strCompare(s
, length
, gShort
, 5, FALSE
) == 0) {
411 return UMEASFMT_WIDTH_SHORT
;
412 } else if (u_strCompare(s
, length
, gNarrow
, 6, FALSE
) == 0) {
413 return UMEASFMT_WIDTH_NARROW
;
416 return UMEASFMT_WIDTH_COUNT
;
420 MeasureFormatCacheData
&cacheData
;
422 // Path to current data.
423 UMeasureFormatWidth width
;
428 // Virtual destructors must be defined out of line.
429 UnitDataSink::UnitPatternSink::~UnitPatternSink() {}
430 UnitDataSink::UnitSubtypeSink::~UnitSubtypeSink() {}
431 UnitDataSink::UnitCompoundSink::~UnitCompoundSink() {}
432 UnitDataSink::UnitTypeSink::~UnitTypeSink() {}
433 UnitDataSink::~UnitDataSink() {}
437 static const UAMeasureUnit indexToUAMsasUnit
[] = {
438 // UAMeasureUnit // UAMeasUnit vals # MeasUnit.getIndex()
439 UAMEASUNIT_ACCELERATION_G_FORCE
, // (0 << 8) + 0, # 0
440 UAMEASUNIT_ACCELERATION_METER_PER_SECOND_SQUARED
, // (0 << 8) + 1, # 1
441 UAMEASUNIT_ANGLE_ARC_MINUTE
, // (1 << 8) + 1, # 2
442 UAMEASUNIT_ANGLE_ARC_SECOND
, // (1 << 8) + 2, # 3
443 UAMEASUNIT_ANGLE_DEGREE
, // (1 << 8) + 0, # 4
444 UAMEASUNIT_ANGLE_RADIAN
, // (1 << 8) + 3, # 5
445 UAMEASUNIT_ANGLE_REVOLUTION
, // (1 << 8) + 4, # 6
446 UAMEASUNIT_AREA_ACRE
, // (2 << 8) + 4, # 7
447 UAMEASUNIT_AREA_HECTARE
, // (2 << 8) + 5, # 8
448 UAMEASUNIT_AREA_SQUARE_CENTIMETER
, // (2 << 8) + 6, # 9
449 UAMEASUNIT_AREA_SQUARE_FOOT
, // (2 << 8) + 2, # 10
450 UAMEASUNIT_AREA_SQUARE_INCH
, // (2 << 8) + 7, # 11
451 UAMEASUNIT_AREA_SQUARE_KILOMETER
, // (2 << 8) + 1, # 12
452 UAMEASUNIT_AREA_SQUARE_METER
, // (2 << 8) + 0, # 13
453 UAMEASUNIT_AREA_SQUARE_MILE
, // (2 << 8) + 3, # 14
454 UAMEASUNIT_AREA_SQUARE_YARD
, // (2 << 8) + 8, # 15
455 UAMEASUNIT_CONCENTRATION_KARAT
, // (18 << 8) + 0, # 16
456 UAMEASUNIT_CONCENTRATION_MILLIGRAM_PER_DECILITER
, // (18 << 8) + 1, # 17
457 UAMEASUNIT_CONCENTRATION_MILLIMOLE_PER_LITER
, // (18 << 8) + 2, # 18
458 UAMEASUNIT_CONCENTRATION_PART_PER_MILLION
, // (18 << 8) + 3, # 19
459 UAMEASUNIT_CONSUMPTION_LITER_PER_100_KILOMETERs
, // (13 << 8) + 2, # 20
460 UAMEASUNIT_CONSUMPTION_LITER_PER_KILOMETER
, // (13 << 8) + 0, # 21
461 UAMEASUNIT_CONSUMPTION_MILE_PER_GALLON
, // (13 << 8) + 1, # 22
462 UAMEASUNIT_CONSUMPTION_MILE_PER_GALLON_IMPERIAL
, // (13 << 8) + 3, # 23
463 UAMEASUNIT_DIGITAL_BIT
, // (14 << 8) + 0, # 24
464 UAMEASUNIT_DIGITAL_BYTE
, // (14 << 8) + 1, # 25
465 UAMEASUNIT_DIGITAL_GIGABIT
, // (14 << 8) + 2, # 26
466 UAMEASUNIT_DIGITAL_GIGABYTE
, // (14 << 8) + 3, # 27
467 UAMEASUNIT_DIGITAL_KILOBIT
, // (14 << 8) + 4, # 28
468 UAMEASUNIT_DIGITAL_KILOBYTE
, // (14 << 8) + 5, # 29
469 UAMEASUNIT_DIGITAL_MEGABIT
, // (14 << 8) + 6, # 30
470 UAMEASUNIT_DIGITAL_MEGABYTE
, // (14 << 8) + 7, # 31
471 UAMEASUNIT_DIGITAL_TERABIT
, // (14 << 8) + 8, # 32
472 UAMEASUNIT_DIGITAL_TERABYTE
, // (14 << 8) + 9, # 33
473 UAMEASUNIT_DURATION_CENTURY
, // (4 << 8) + 10, # 34
474 UAMEASUNIT_DURATION_DAY
, // (4 << 8) + 3, # 35
475 UAMEASUNIT_DURATION_HOUR
, // (4 << 8) + 4, # 36
476 UAMEASUNIT_DURATION_MICROSECOND
, // (4 << 8) + 8, # 37
477 UAMEASUNIT_DURATION_MILLISECOND
, // (4 << 8) + 7, # 38
478 UAMEASUNIT_DURATION_MINUTE
, // (4 << 8) + 5, # 39
479 UAMEASUNIT_DURATION_MONTH
, // (4 << 8) + 1, # 40
480 UAMEASUNIT_DURATION_NANOSECOND
, // (4 << 8) + 9, # 41
481 UAMEASUNIT_DURATION_SECOND
, // (4 << 8) + 6, # 42
482 UAMEASUNIT_DURATION_WEEK
, // (4 << 8) + 2, # 43
483 UAMEASUNIT_DURATION_YEAR
, // (4 << 8) + 0, # 44
484 UAMEASUNIT_ELECTRIC_AMPERE
, // (15 << 8) + 0, # 45
485 UAMEASUNIT_ELECTRIC_MILLIAMPERE
, // (15 << 8) + 1, # 46
486 UAMEASUNIT_ELECTRIC_OHM
, // (15 << 8) + 2, # 47
487 UAMEASUNIT_ELECTRIC_VOLT
, // (15 << 8) + 3, # 48
488 UAMEASUNIT_ENERGY_CALORIE
, // (12 << 8) + 0, # 49
489 UAMEASUNIT_ENERGY_FOODCALORIE
, // (12 << 8) + 1, # 50
490 UAMEASUNIT_ENERGY_JOULE
, // (12 << 8) + 2, # 51
491 UAMEASUNIT_ENERGY_KILOCALORIE
, // (12 << 8) + 3, # 52
492 UAMEASUNIT_ENERGY_KILOJOULE
, // (12 << 8) + 4, # 53
493 UAMEASUNIT_ENERGY_KILOWATT_HOUR
, // (12 << 8) + 5, # 54
494 UAMEASUNIT_FREQUENCY_GIGAHERTZ
, // (16 << 8) + 3, # 55
495 UAMEASUNIT_FREQUENCY_HERTZ
, // (16 << 8) + 0, # 56
496 UAMEASUNIT_FREQUENCY_KILOHERTZ
, // (16 << 8) + 1, # 57
497 UAMEASUNIT_FREQUENCY_MEGAHERTZ
, // (16 << 8) + 2, # 58
498 UAMEASUNIT_LENGTH_ASTRONOMICAL_UNIT
, // (5 << 8) + 16, # 59
499 UAMEASUNIT_LENGTH_CENTIMETER
, // (5 << 8) + 1, # 60
500 UAMEASUNIT_LENGTH_DECIMETER
, // (5 << 8) + 10, # 61
501 UAMEASUNIT_LENGTH_FATHOM
, // (5 << 8) + 14, # 62
502 UAMEASUNIT_LENGTH_FOOT
, // (5 << 8) + 5, # 63
503 UAMEASUNIT_LENGTH_FURLONG
, // (5 << 8) + 15, # 64
504 UAMEASUNIT_LENGTH_INCH
, // (5 << 8) + 6, # 65
505 UAMEASUNIT_LENGTH_KILOMETER
, // (5 << 8) + 2, # 66
506 UAMEASUNIT_LENGTH_LIGHT_YEAR
, // (5 << 8) + 9, # 67
507 UAMEASUNIT_LENGTH_METER
, // (5 << 8) + 0, # 68
508 UAMEASUNIT_LENGTH_MICROMETER
, // (5 << 8) + 11, # 69
509 UAMEASUNIT_LENGTH_MILE
, // (5 << 8) + 7, # 70
510 UAMEASUNIT_LENGTH_MILE_SCANDINAVIAN
, // (5 << 8) + 18, # 71
511 UAMEASUNIT_LENGTH_MILLIMETER
, // (5 << 8) + 3, # 72
512 UAMEASUNIT_LENGTH_NANOMETER
, // (5 << 8) + 12, # 73
513 UAMEASUNIT_LENGTH_NAUTICAL_MILE
, // (5 << 8) + 13, # 74
514 UAMEASUNIT_LENGTH_PARSEC
, // (5 << 8) + 17, # 75
515 UAMEASUNIT_LENGTH_PICOMETER
, // (5 << 8) + 4, # 76
516 UAMEASUNIT_LENGTH_YARD
, // (5 << 8) + 8, # 77
517 UAMEASUNIT_LIGHT_LUX
, // (17 << 8) + 0, # 78
518 UAMEASUNIT_MASS_CARAT
, // (6 << 8) + 9, # 79
519 UAMEASUNIT_MASS_GRAM
, // (6 << 8) + 0, # 80
520 UAMEASUNIT_MASS_KILOGRAM
, // (6 << 8) + 1, # 81
521 UAMEASUNIT_MASS_METRIC_TON
, // (6 << 8) + 7, # 82
522 UAMEASUNIT_MASS_MICROGRAM
, // (6 << 8) + 5, # 83
523 UAMEASUNIT_MASS_MILLIGRAM
, // (6 << 8) + 6, # 84
524 UAMEASUNIT_MASS_OUNCE
, // (6 << 8) + 2, # 85
525 UAMEASUNIT_MASS_OUNCE_TROY
, // (6 << 8) + 10, # 86
526 UAMEASUNIT_MASS_POUND
, // (6 << 8) + 3, # 87
527 UAMEASUNIT_MASS_STONE
, // (6 << 8) + 4, # 88
528 UAMEASUNIT_MASS_TON
, // (6 << 8) + 8, # 89
529 UAMEASUNIT_POWER_GIGAWATT
, // (7 << 8) + 5, # 90
530 UAMEASUNIT_POWER_HORSEPOWER
, // (7 << 8) + 2, # 91
531 UAMEASUNIT_POWER_KILOWATT
, // (7 << 8) + 1, # 92
532 UAMEASUNIT_POWER_MEGAWATT
, // (7 << 8) + 4, # 93
533 UAMEASUNIT_POWER_MILLIWATT
, // (7 << 8) + 3, # 94
534 UAMEASUNIT_POWER_WATT
, // (7 << 8) + 0, # 95
535 UAMEASUNIT_PRESSURE_HECTOPASCAL
, // (8 << 8) + 0, # 96
536 UAMEASUNIT_PRESSURE_INCH_HG
, // (8 << 8) + 1, # 97
537 UAMEASUNIT_PRESSURE_MILLIBAR
, // (8 << 8) + 2, # 98
538 UAMEASUNIT_PRESSURE_MILLIMETER_OF_MERCURY
, // (8 << 8) + 3, # 99
539 UAMEASUNIT_PRESSURE_POUND_PER_SQUARE_INCH
, // (8 << 8) + 4, # 100
540 UAMEASUNIT_SPEED_KILOMETER_PER_HOUR
, // (9 << 8) + 1, # 101
541 UAMEASUNIT_SPEED_KNOT
, // (9 << 8) + 3, # 102
542 UAMEASUNIT_SPEED_METER_PER_SECOND
, // (9 << 8) + 0, # 103
543 UAMEASUNIT_SPEED_MILE_PER_HOUR
, // (9 << 8) + 2, # 104
544 UAMEASUNIT_TEMPERATURE_CELSIUS
, // (10 << 8) + 0, # 105
545 UAMEASUNIT_TEMPERATURE_FAHRENHEIT
, // (10 << 8) + 1, # 106
546 UAMEASUNIT_TEMPERATURE_GENERIC
, // (10 << 8) + 3, # 107
547 UAMEASUNIT_TEMPERATURE_KELVIN
, // (10 << 8) + 2, # 108
548 UAMEASUNIT_VOLUME_ACRE_FOOT
, // (11 << 8) + 13, # 109
549 UAMEASUNIT_VOLUME_BUSHEL
, // (11 << 8) + 14, # 110
550 UAMEASUNIT_VOLUME_CENTILITER
, // (11 << 8) + 4, # 111
551 UAMEASUNIT_VOLUME_CUBIC_CENTIMETER
, // (11 << 8) + 8, # 112
552 UAMEASUNIT_VOLUME_CUBIC_FOOT
, // (11 << 8) + 11, # 113
553 UAMEASUNIT_VOLUME_CUBIC_INCH
, // (11 << 8) + 10, # 114
554 UAMEASUNIT_VOLUME_CUBIC_KILOMETER
, // (11 << 8) + 1, # 115
555 UAMEASUNIT_VOLUME_CUBIC_METER
, // (11 << 8) + 9, # 116
556 UAMEASUNIT_VOLUME_CUBIC_MILE
, // (11 << 8) + 2, # 117
557 UAMEASUNIT_VOLUME_CUBIC_YARD
, // (11 << 8) + 12, # 118
558 UAMEASUNIT_VOLUME_CUP
, // (11 << 8) + 18, # 119
559 UAMEASUNIT_VOLUME_CUP_METRIC
, // (11 << 8) + 22, # 120
560 UAMEASUNIT_VOLUME_DECILITER
, // (11 << 8) + 5, # 121
561 UAMEASUNIT_VOLUME_FLUID_OUNCE
, // (11 << 8) + 17, # 122
562 UAMEASUNIT_VOLUME_GALLON
, // (11 << 8) + 21, # 123
563 UAMEASUNIT_VOLUME_GALLON_IMPERIAL
, // (11 << 8) + 24, # 124
564 UAMEASUNIT_VOLUME_HECTOLITER
, // (11 << 8) + 6, # 125
565 UAMEASUNIT_VOLUME_LITER
, // (11 << 8) + 0, # 126
566 UAMEASUNIT_VOLUME_MEGALITER
, // (11 << 8) + 7, # 127
567 UAMEASUNIT_VOLUME_MILLILITER
, // (11 << 8) + 3, # 128
568 UAMEASUNIT_VOLUME_PINT
, // (11 << 8) + 19, # 129
569 UAMEASUNIT_VOLUME_PINT_METRIC
, // (11 << 8) + 23, # 130
570 UAMEASUNIT_VOLUME_QUART
, // (11 << 8) + 20, # 131
571 UAMEASUNIT_VOLUME_TABLESPOON
, // (11 << 8) + 16, # 132
572 UAMEASUNIT_VOLUME_TEASPOON
, // (11 << 8) + 15, # 133
575 static UBool
loadMeasureUnitData(
576 const UResourceBundle
*resource
,
577 MeasureFormatCacheData
&cacheData
,
578 UErrorCode
&status
) {
579 UnitDataSink
sink(cacheData
);
580 ures_getAllTableItemsWithFallback(resource
, "", sink
, status
);
581 // Apple-specific, flesh out display names
582 for (int32_t unitIndex
= 0; unitIndex
< MEAS_UNIT_COUNT
; ++unitIndex
) {
583 if ( cacheData
.getDisplayName(unitIndex
, UMEASFMT_WIDTH_WIDE
) == NULL
) {
584 cacheData
.setDisplayName(unitIndex
, UMEASFMT_WIDTH_WIDE
, cacheData
.getDisplayName(unitIndex
, UMEASFMT_WIDTH_SHORT
));
586 if ( cacheData
.getDisplayName(unitIndex
, UMEASFMT_WIDTH_SHORT
) == NULL
) {
587 cacheData
.setDisplayName(unitIndex
, UMEASFMT_WIDTH_SHORT
, cacheData
.getDisplayName(unitIndex
, UMEASFMT_WIDTH_WIDE
));
589 if ( cacheData
.getDisplayName(unitIndex
, UMEASFMT_WIDTH_NARROW
) == NULL
) {
590 cacheData
.setDisplayName(unitIndex
, UMEASFMT_WIDTH_NARROW
, cacheData
.getDisplayName(unitIndex
, UMEASFMT_WIDTH_SHORT
));
593 return U_SUCCESS(status
);
596 static UnicodeString
loadNumericDateFormatterPattern(
597 const UResourceBundle
*resource
,
599 UErrorCode
&status
) {
600 UnicodeString result
;
601 if (U_FAILURE(status
)) {
605 chs
.append("durationUnits", status
)
606 .append("/", status
).append(pattern
, status
);
607 LocalUResourceBundlePointer
patternBundle(
608 ures_getByKeyWithFallback(
613 if (U_FAILURE(status
)) {
616 getString(patternBundle
.getAlias(), result
, status
);
617 // Replace 'h' with 'H'
618 int32_t len
= result
.length();
619 UChar
*buffer
= result
.getBuffer(len
);
620 for (int32_t i
= 0; i
< len
; ++i
) {
621 if (buffer
[i
] == 0x68) { // 'h'
622 buffer
[i
] = 0x48; // 'H'
625 result
.releaseBuffer(len
);
629 static NumericDateFormatters
*loadNumericDateFormatters(
630 const UResourceBundle
*resource
,
631 UErrorCode
&status
) {
632 if (U_FAILURE(status
)) {
635 NumericDateFormatters
*result
= new NumericDateFormatters(
636 loadNumericDateFormatterPattern(resource
, "hm", status
),
637 loadNumericDateFormatterPattern(resource
, "ms", status
),
638 loadNumericDateFormatterPattern(resource
, "hms", status
),
640 if (U_FAILURE(status
)) {
647 template<> U_I18N_API
648 const MeasureFormatCacheData
*LocaleCacheKey
<MeasureFormatCacheData
>::createObject(
649 const void * /*unused*/, UErrorCode
&status
) const {
650 const char *localeId
= fLoc
.getName();
651 LocalUResourceBundlePointer
unitsBundle(ures_open(U_ICUDATA_UNIT
, localeId
, &status
));
652 static UNumberFormatStyle currencyStyles
[] = {
653 UNUM_CURRENCY_PLURAL
, UNUM_CURRENCY_ISO
, UNUM_CURRENCY
};
654 LocalPointer
<MeasureFormatCacheData
> result(new MeasureFormatCacheData(), status
);
655 if (U_FAILURE(status
)) {
658 if (!loadMeasureUnitData(
659 unitsBundle
.getAlias(),
664 result
->adoptNumericDateFormatters(loadNumericDateFormatters(
665 unitsBundle
.getAlias(), status
));
666 if (U_FAILURE(status
)) {
670 for (int32_t i
= 0; i
< WIDTH_INDEX_COUNT
; ++i
) {
671 result
->adoptCurrencyFormat(i
, NumberFormat::createInstance(
672 localeId
, currencyStyles
[i
], status
));
673 if (U_FAILURE(status
)) {
677 NumberFormat
*inf
= NumberFormat::createInstance(
678 localeId
, UNUM_DECIMAL
, status
);
679 if (U_FAILURE(status
)) {
682 inf
->setMaximumFractionDigits(0);
683 DecimalFormat
*decfmt
= dynamic_cast<DecimalFormat
*>(inf
);
684 if (decfmt
!= NULL
) {
685 decfmt
->setRoundingMode(DecimalFormat::kRoundDown
);
687 result
->adoptIntegerFormat(inf
);
689 return result
.orphan();
692 static UBool
isTimeUnit(const MeasureUnit
&mu
, const char *tu
) {
693 return uprv_strcmp(mu
.getType(), "duration") == 0 &&
694 uprv_strcmp(mu
.getSubtype(), tu
) == 0;
697 // Converts a composite measure into hours-minutes-seconds and stores at hms
698 // array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
699 // units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
700 // contains hours-minutes, this function would return 3.
702 // If measures cannot be converted into hours, minutes, seconds or if amounts
703 // are negative, or if hours, minutes, seconds are out of order, returns 0.
704 static int32_t toHMS(
705 const Measure
*measures
,
706 int32_t measureCount
,
708 UErrorCode
&status
) {
709 if (U_FAILURE(status
)) {
713 if (U_FAILURE(status
)) {
716 // We use copy constructor to ensure that both sides of equality operator
717 // are instances of MeasureUnit base class and not a subclass. Otherwise,
718 // operator== will immediately return false.
719 for (int32_t i
= 0; i
< measureCount
; ++i
) {
720 if (isTimeUnit(measures
[i
].getUnit(), "hour")) {
721 // hour must come first
725 hms
[0] = measures
[i
].getNumber();
726 if (hms
[0].getDouble() < 0.0) {
730 } else if (isTimeUnit(measures
[i
].getUnit(), "minute")) {
731 // minute must come after hour
735 hms
[1] = measures
[i
].getNumber();
736 if (hms
[1].getDouble() < 0.0) {
740 } else if (isTimeUnit(measures
[i
].getUnit(), "second")) {
741 // second must come after hour and minute
745 hms
[2] = measures
[i
].getNumber();
746 if (hms
[2].getDouble() < 0.0) {
758 MeasureFormat::MeasureFormat(
759 const Locale
&locale
, UMeasureFormatWidth w
, UErrorCode
&status
)
763 width((w
==UMEASFMT_WIDTH_SHORTER
)? UMEASFMT_WIDTH_SHORT
: w
),
764 stripPatternSpaces(w
==UMEASFMT_WIDTH_SHORTER
),
766 listFormatterStd(NULL
) {
767 initMeasureFormat(locale
, (w
==UMEASFMT_WIDTH_SHORTER
)? UMEASFMT_WIDTH_SHORT
: w
, NULL
, status
);
770 MeasureFormat::MeasureFormat(
771 const Locale
&locale
,
772 UMeasureFormatWidth w
,
773 NumberFormat
*nfToAdopt
,
778 width((w
==UMEASFMT_WIDTH_SHORTER
)? UMEASFMT_WIDTH_SHORT
: w
),
779 stripPatternSpaces(w
==UMEASFMT_WIDTH_SHORTER
),
781 listFormatterStd(NULL
) {
782 initMeasureFormat(locale
, (w
==UMEASFMT_WIDTH_SHORTER
)? UMEASFMT_WIDTH_SHORT
: w
, nfToAdopt
, status
);
785 MeasureFormat::MeasureFormat(const MeasureFormat
&other
) :
788 numberFormat(other
.numberFormat
),
789 pluralRules(other
.pluralRules
),
791 stripPatternSpaces(other
.stripPatternSpaces
),
793 listFormatterStd(NULL
) {
795 numberFormat
->addRef();
796 pluralRules
->addRef();
797 if (other
.listFormatter
!= NULL
) {
798 listFormatter
= new ListFormatter(*other
.listFormatter
);
800 if (other
.listFormatterStd
!= NULL
) {
801 listFormatterStd
= new ListFormatter(*other
.listFormatterStd
);
805 MeasureFormat
&MeasureFormat::operator=(const MeasureFormat
&other
) {
806 if (this == &other
) {
809 Format::operator=(other
);
810 SharedObject::copyPtr(other
.cache
, cache
);
811 SharedObject::copyPtr(other
.numberFormat
, numberFormat
);
812 SharedObject::copyPtr(other
.pluralRules
, pluralRules
);
814 stripPatternSpaces
= other
.stripPatternSpaces
;
815 delete listFormatter
;
816 if (other
.listFormatter
!= NULL
) {
817 listFormatter
= new ListFormatter(*other
.listFormatter
);
819 listFormatter
= NULL
;
821 delete listFormatterStd
;
822 if (other
.listFormatterStd
!= NULL
) {
823 listFormatterStd
= new ListFormatter(*other
.listFormatterStd
);
825 listFormatterStd
= NULL
;
830 MeasureFormat::MeasureFormat() :
834 width(UMEASFMT_WIDTH_SHORT
),
835 stripPatternSpaces(FALSE
),
837 listFormatterStd(NULL
) {
840 MeasureFormat::~MeasureFormat() {
844 if (numberFormat
!= NULL
) {
845 numberFormat
->removeRef();
847 if (pluralRules
!= NULL
) {
848 pluralRules
->removeRef();
850 delete listFormatter
;
851 delete listFormatterStd
;
854 UBool
MeasureFormat::operator==(const Format
&other
) const {
855 if (this == &other
) { // Same object, equal
858 if (!Format::operator==(other
)) {
861 const MeasureFormat
&rhs
= static_cast<const MeasureFormat
&>(other
);
863 // Note: Since the ListFormatter depends only on Locale and width, we
864 // don't have to check it here.
866 // differing widths aren't equivalent
867 if (width
!= rhs
.width
|| stripPatternSpaces
!= rhs
.stripPatternSpaces
) {
870 // Width the same check locales.
871 // We don't need to check locales if both objects have same cache.
872 if (cache
!= rhs
.cache
) {
873 UErrorCode status
= U_ZERO_ERROR
;
874 const char *localeId
= getLocaleID(status
);
875 const char *rhsLocaleId
= rhs
.getLocaleID(status
);
876 if (U_FAILURE(status
)) {
877 // On failure, assume not equal
880 if (uprv_strcmp(localeId
, rhsLocaleId
) != 0) {
884 // Locales same, check NumberFormat if shared data differs.
886 numberFormat
== rhs
.numberFormat
||
887 **numberFormat
== **rhs
.numberFormat
);
890 Format
*MeasureFormat::clone() const {
891 return new MeasureFormat(*this);
894 UnicodeString
&MeasureFormat::format(
895 const Formattable
&obj
,
896 UnicodeString
&appendTo
,
898 UErrorCode
&status
) const {
899 if (U_FAILURE(status
)) return appendTo
;
900 if (obj
.getType() == Formattable::kObject
) {
901 const UObject
* formatObj
= obj
.getObject();
902 const Measure
* amount
= dynamic_cast<const Measure
*>(formatObj
);
903 if (amount
!= NULL
) {
904 return formatMeasure(
905 *amount
, **numberFormat
, appendTo
, pos
, status
);
908 status
= U_ILLEGAL_ARGUMENT_ERROR
;
912 void MeasureFormat::parseObject(
913 const UnicodeString
& /*source*/,
914 Formattable
& /*result*/,
915 ParsePosition
& /*pos*/) const {
919 UnicodeString
&MeasureFormat::formatMeasurePerUnit(
920 const Measure
&measure
,
921 const MeasureUnit
&perUnit
,
922 UnicodeString
&appendTo
,
924 UErrorCode
&status
) const {
925 if (U_FAILURE(status
)) {
928 MeasureUnit
*resolvedUnit
=
929 MeasureUnit::resolveUnitPerUnit(measure
.getUnit(), perUnit
);
930 if (resolvedUnit
!= NULL
) {
931 Measure
newMeasure(measure
.getNumber(), resolvedUnit
, status
);
932 return formatMeasure(
933 newMeasure
, **numberFormat
, appendTo
, pos
, status
);
935 FieldPosition
fpos(pos
.getField());
936 UnicodeString result
;
937 int32_t offset
= withPerUnitAndAppend(
939 measure
, **numberFormat
, result
, fpos
, status
),
943 if (U_FAILURE(status
)) {
946 if (fpos
.getBeginIndex() != 0 || fpos
.getEndIndex() != 0) {
947 pos
.setBeginIndex(fpos
.getBeginIndex() + offset
);
948 pos
.setEndIndex(fpos
.getEndIndex() + offset
);
953 UnicodeString
&MeasureFormat::formatMeasures(
954 const Measure
*measures
,
955 int32_t measureCount
,
956 UnicodeString
&appendTo
,
958 UErrorCode
&status
) const {
959 if (U_FAILURE(status
)) {
962 if (measureCount
== 0) {
965 if (measureCount
== 1) {
966 return formatMeasure(measures
[0], **numberFormat
, appendTo
, pos
, status
);
968 if (width
== UMEASFMT_WIDTH_NUMERIC
) {
970 int32_t bitMap
= toHMS(measures
, measureCount
, hms
, status
);
972 FieldPositionIteratorHandler
handler(NULL
, status
);
973 return formatNumeric(hms
, bitMap
, appendTo
, handler
, status
);
976 if (pos
.getField() != FieldPosition::DONT_CARE
) {
977 return formatMeasuresSlowTrack(
978 measures
, measureCount
, appendTo
, pos
, status
);
980 UnicodeString
*results
= new UnicodeString
[measureCount
];
981 if (results
== NULL
) {
982 status
= U_MEMORY_ALLOCATION_ERROR
;
985 for (int32_t i
= 0; i
< measureCount
; ++i
) {
986 const NumberFormat
*nf
= cache
->getIntegerFormat();
987 if (i
== measureCount
- 1) {
988 nf
= numberFormat
->get();
997 listFormatter
->format(results
, measureCount
, appendTo
, status
);
1002 // Apple-specific version for now;
1003 // uses FieldPositionIterator* instead of FieldPosition&
1004 UnicodeString
&MeasureFormat::formatMeasures(
1005 const Measure
*measures
,
1006 int32_t measureCount
,
1007 UnicodeString
&appendTo
,
1008 FieldPositionIterator
* posIter
,
1009 UErrorCode
&status
) const {
1010 if (U_FAILURE(status
)) {
1013 FieldPositionIteratorHandler
handler(posIter
, status
);
1014 if (measureCount
== 0) {
1017 if (measureCount
== 1) {
1018 int32_t start
= appendTo
.length();
1019 int32_t field
= indexToUAMsasUnit
[measures
[0].getUnit().getIndex()];
1020 FieldPosition
pos(UAMEASFMT_NUMERIC_FIELD_FLAG
); // special field value to request range of entire numeric part
1021 formatMeasure(measures
[0], **numberFormat
, appendTo
, pos
, status
);
1022 handler
.addAttribute(field
, start
, appendTo
.length());
1023 handler
.addAttribute(field
| UAMEASFMT_NUMERIC_FIELD_FLAG
, pos
.getBeginIndex(), pos
.getEndIndex());
1026 if (width
== UMEASFMT_WIDTH_NUMERIC
) {
1028 int32_t bitMap
= toHMS(measures
, measureCount
, hms
, status
);
1030 return formatNumeric(hms
, bitMap
, appendTo
, handler
, status
);
1033 UnicodeString
*results
= new UnicodeString
[measureCount
];
1034 if (results
== NULL
) {
1035 status
= U_MEMORY_ALLOCATION_ERROR
;
1038 FieldPosition
*numPositions
= new FieldPosition
[measureCount
];
1039 if (results
== NULL
) {
1041 status
= U_MEMORY_ALLOCATION_ERROR
;
1045 for (int32_t i
= 0; i
< measureCount
; ++i
) {
1046 const NumberFormat
*nf
= cache
->getIntegerFormat();
1047 if (i
== measureCount
- 1) {
1048 nf
= numberFormat
->get();
1050 numPositions
[i
].setField(UAMEASFMT_NUMERIC_FIELD_FLAG
);
1058 listFormatter
->format(results
, measureCount
, appendTo
, status
);
1059 for (int32_t i
= 0; i
< measureCount
; ++i
) {
1060 int32_t begin
= appendTo
.indexOf(results
[i
]);
1062 int32_t field
= indexToUAMsasUnit
[measures
[i
].getUnit().getIndex()];
1063 handler
.addAttribute(field
, begin
, begin
+ results
[i
].length());
1064 int32_t numPosBegin
= numPositions
[i
].getBeginIndex();
1065 int32_t numPosEnd
= numPositions
[i
].getEndIndex();
1066 if (numPosBegin
>= 0 && numPosEnd
> numPosBegin
) {
1067 handler
.addAttribute(field
| UAMEASFMT_NUMERIC_FIELD_FLAG
, begin
+ numPosBegin
, begin
+ numPosEnd
);
1072 delete [] numPositions
;
1077 void MeasureFormat::initMeasureFormat(
1078 const Locale
&locale
,
1079 UMeasureFormatWidth w
,
1080 NumberFormat
*nfToAdopt
,
1081 UErrorCode
&status
) {
1082 static const char *listStyles
[] = {"unit", "unit-short", "unit-narrow"};
1083 LocalPointer
<NumberFormat
> nf(nfToAdopt
);
1084 if (U_FAILURE(status
)) {
1087 const char *name
= locale
.getName();
1088 setLocaleIDs(name
, name
);
1090 UnifiedCache::getByLocale(locale
, cache
, status
);
1091 if (U_FAILURE(status
)) {
1095 const SharedPluralRules
*pr
= PluralRules::createSharedInstance(
1096 locale
, UPLURAL_TYPE_CARDINAL
, status
);
1097 if (U_FAILURE(status
)) {
1100 SharedObject::copyPtr(pr
, pluralRules
);
1103 const SharedNumberFormat
*shared
= NumberFormat::createSharedInstance(
1104 locale
, UNUM_DECIMAL
, status
);
1105 if (U_FAILURE(status
)) {
1108 SharedObject::copyPtr(shared
, numberFormat
);
1109 shared
->removeRef();
1111 adoptNumberFormat(nf
.orphan(), status
);
1112 if (U_FAILURE(status
)) {
1117 if (stripPatternSpaces
) {
1118 w
= UMEASFMT_WIDTH_NARROW
;
1120 delete listFormatter
;
1121 listFormatter
= ListFormatter::createInstance(
1123 listStyles
[getRegularWidth(w
)],
1125 delete listFormatterStd
;
1126 listFormatterStd
= ListFormatter::createInstance(
1132 void MeasureFormat::adoptNumberFormat(
1133 NumberFormat
*nfToAdopt
, UErrorCode
&status
) {
1134 LocalPointer
<NumberFormat
> nf(nfToAdopt
);
1135 if (U_FAILURE(status
)) {
1138 SharedNumberFormat
*shared
= new SharedNumberFormat(nf
.getAlias());
1139 if (shared
== NULL
) {
1140 status
= U_MEMORY_ALLOCATION_ERROR
;
1144 SharedObject::copyPtr(shared
, numberFormat
);
1147 UBool
MeasureFormat::setMeasureFormatLocale(const Locale
&locale
, UErrorCode
&status
) {
1148 if (U_FAILURE(status
) || locale
== getLocale(status
)) {
1151 initMeasureFormat(locale
, width
, NULL
, status
);
1152 return U_SUCCESS(status
);
1155 // Apple-specific for now
1156 UMeasureFormatWidth
MeasureFormat::getWidth() const {
1160 const NumberFormat
&MeasureFormat::getNumberFormat() const {
1161 return **numberFormat
;
1164 const PluralRules
&MeasureFormat::getPluralRules() const {
1165 return **pluralRules
;
1168 Locale
MeasureFormat::getLocale(UErrorCode
&status
) const {
1169 return Format::getLocale(ULOC_VALID_LOCALE
, status
);
1172 const char *MeasureFormat::getLocaleID(UErrorCode
&status
) const {
1173 return Format::getLocaleID(ULOC_VALID_LOCALE
, status
);
1177 UnicodeString
&MeasureFormat::getUnitName(
1178 const MeasureUnit
* unit
,
1179 UnicodeString
&result
) const {
1180 const UChar
* unitName
= cache
->getDisplayName( unit
->getIndex(), getRegularWidth(width
) );
1181 if (unitName
!= NULL
) {
1182 int32_t unitNameLen
= u_strlen(unitName
);
1183 if (unitNameLen
<= 64) {
1184 result
.setTo(unitName
, unitNameLen
);
1188 result
.setToBogus();
1193 UnicodeString
&MeasureFormat::getMultipleUnitNames(
1194 const MeasureUnit
** units
,
1196 UAMeasureNameListStyle listStyle
,
1197 UnicodeString
&result
) const {
1198 if (unitCount
== 0) {
1199 return result
.remove();
1201 if (unitCount
== 1) {
1202 return getUnitName(units
[0], result
);
1204 UnicodeString
*results
= new UnicodeString
[unitCount
];
1205 if (results
!= NULL
) {
1206 for (int32_t i
= 0; i
< unitCount
; ++i
) {
1207 getUnitName(units
[i
], results
[i
]);
1209 UErrorCode status
= U_ZERO_ERROR
;
1210 if (listStyle
== UAMEASNAME_LIST_STANDARD
) {
1211 listFormatterStd
->format(results
, unitCount
, result
, status
);
1213 listFormatter
->format(results
, unitCount
, result
, status
);
1216 if (U_SUCCESS(status
)) {
1220 result
.setToBogus();
1224 UnicodeString
&MeasureFormat::formatMeasure(
1225 const Measure
&measure
,
1226 const NumberFormat
&nf
,
1227 UnicodeString
&appendTo
,
1229 UErrorCode
&status
) const {
1230 if (U_FAILURE(status
)) {
1233 const Formattable
& amtNumber
= measure
.getNumber();
1234 const MeasureUnit
& amtUnit
= measure
.getUnit();
1235 if (isCurrency(amtUnit
)) {
1237 u_charsToUChars(amtUnit
.getSubtype(), isoCode
, 4);
1238 return cache
->getCurrencyFormat(width
)->format(
1239 new CurrencyAmount(amtNumber
, isoCode
, status
),
1244 UnicodeString formattedNumber
;
1245 UBool posForFullNumericPart
= (pos
.getField() == UAMEASFMT_NUMERIC_FIELD_FLAG
);
1246 if (posForFullNumericPart
) {
1247 pos
.setField(FieldPosition::DONT_CARE
);
1249 StandardPlural::Form pluralForm
= QuantityFormatter::selectPlural(
1250 amtNumber
, nf
, **pluralRules
, formattedNumber
, pos
, status
);
1251 if (posForFullNumericPart
) {
1252 pos
.setField(UAMEASFMT_NUMERIC_FIELD_FLAG
);
1253 pos
.setBeginIndex(0);
1254 pos
.setEndIndex(formattedNumber
.length());
1256 const SimpleFormatter
*formatter
= getPluralFormatter(amtUnit
, width
, pluralForm
, status
);
1257 int32_t cur
= appendTo
.length();
1258 QuantityFormatter::format(*formatter
, formattedNumber
, appendTo
, pos
, status
);
1259 if (stripPatternSpaces
) {
1260 const SimpleFormatter
*narrowFormatter
= getPluralFormatter(amtUnit
, UMEASFMT_WIDTH_NARROW
, pluralForm
, status
);
1261 if (U_SUCCESS(status
)) {
1262 // Get the narrow pattern with all {n} set to empty string.
1263 // If there are spaces in that, then do not continue to strip spaces
1264 // (i.e. even in the narrowest form this locale keeps spaces).
1265 UnicodeString narrowPatternNoArgs
= narrowFormatter
->getTextWithNoArguments();
1266 if (narrowPatternNoArgs
.indexOf((UChar
)0x0020) == -1 && narrowPatternNoArgs
.indexOf((UChar
)0x00A0) == -1) {
1267 int32_t end
= appendTo
.length();
1268 for (; cur
< end
; cur
++) {
1269 if (appendTo
.charAt(cur
) == 0x0020) {
1270 appendTo
.remove(cur
, 1);
1271 if (pos
.getBeginIndex() > cur
) {
1272 pos
.setBeginIndex(pos
.getBeginIndex() - 1);
1273 pos
.setEndIndex(pos
.getEndIndex() - 1);
1283 // Formats hours-minutes-seconds as 5:37:23 or similar.
1284 UnicodeString
&MeasureFormat::formatNumeric(
1285 const Formattable
*hms
, // always length 3
1286 int32_t bitMap
, // 1=hourset, 2=minuteset, 4=secondset
1287 UnicodeString
&appendTo
,
1288 FieldPositionHandler
& handler
,
1289 UErrorCode
&status
) const {
1290 if (U_FAILURE(status
)) {
1294 (UDate
) (((uprv_trunc(hms
[0].getDouble(status
)) * 60.0
1295 + uprv_trunc(hms
[1].getDouble(status
))) * 60.0
1296 + uprv_trunc(hms
[2].getDouble(status
))) * 1000.0);
1300 return formatNumeric(
1302 cache
->getNumericDateFormatters()->hourMinuteSecond
,
1310 return formatNumeric(
1312 cache
->getNumericDateFormatters()->minuteSecond
,
1320 return formatNumeric(
1322 cache
->getNumericDateFormatters()->hourMinute
,
1330 status
= U_INTERNAL_PROGRAM_ERROR
;
1337 static void appendRange(
1338 const UnicodeString
&src
,
1341 UnicodeString
&dest
) {
1342 dest
.append(src
, start
, end
- start
);
1345 static void appendRange(
1346 const UnicodeString
&src
,
1348 UnicodeString
&dest
) {
1349 dest
.append(src
, end
, src
.length() - end
);
1352 // Formats time like 5:37:23
1353 UnicodeString
&MeasureFormat::formatNumeric(
1354 UDate date
, // Time since epoch 1:30:00 would be 5400000
1355 const DateFormat
&dateFmt
, // h:mm, m:ss, or h:mm:ss
1356 UDateFormatField smallestField
, // seconds in 5:37:23.5
1357 const Formattable
&smallestAmount
, // 23.5 for 5:37:23.5
1358 UnicodeString
&appendTo
,
1359 FieldPositionHandler
& handler
,
1360 UErrorCode
&status
) const {
1361 if (U_FAILURE(status
)) {
1364 // Format the smallest amount with this object's NumberFormat
1365 UnicodeString smallestAmountFormatted
;
1367 // We keep track of the integer part of smallest amount so that
1368 // we can replace it later so that we get '0:00:09.3' instead of
1370 FieldPosition
intFieldPosition(UNUM_INTEGER_FIELD
);
1371 (*numberFormat
)->format(
1372 smallestAmount
, smallestAmountFormatted
, intFieldPosition
, status
);
1374 intFieldPosition
.getBeginIndex() == 0 &&
1375 intFieldPosition
.getEndIndex() == 0) {
1376 status
= U_INTERNAL_PROGRAM_ERROR
;
1380 // Format time. draft becomes something like '5:30:45'
1381 FieldPositionIterator posIter
;
1382 UnicodeString draft
;
1383 dateFmt
.format(date
, draft
, &posIter
, status
);
1385 int32_t start
= appendTo
.length();
1386 FieldPosition
smallestFieldPosition(smallestField
);
1388 int32_t measField
= -1;
1389 while (posIter
.next(fp
)) {
1390 int32_t dateField
= fp
.getField();
1391 switch (dateField
) {
1392 case UDAT_HOUR_OF_DAY1_FIELD
:
1393 case UDAT_HOUR_OF_DAY0_FIELD
:
1394 case UDAT_HOUR1_FIELD
:
1395 case UDAT_HOUR0_FIELD
:
1396 measField
= UAMEASUNIT_DURATION_HOUR
; break;
1397 case UDAT_MINUTE_FIELD
:
1398 measField
= UAMEASUNIT_DURATION_MINUTE
; break;
1399 case UDAT_SECOND_FIELD
:
1400 measField
= UAMEASUNIT_DURATION_SECOND
; break;
1402 measField
= -1; break;
1404 if (dateField
!= smallestField
) {
1405 if (measField
>= 0) {
1406 handler
.addAttribute(measField
, start
+ fp
.getBeginIndex(), start
+ fp
.getEndIndex());
1407 handler
.addAttribute(measField
| UAMEASFMT_NUMERIC_FIELD_FLAG
, start
+ fp
.getBeginIndex(), start
+ fp
.getEndIndex());
1410 smallestFieldPosition
.setBeginIndex(fp
.getBeginIndex());
1411 smallestFieldPosition
.setEndIndex(fp
.getEndIndex());
1416 // If we find field for smallest amount replace it with the formatted
1417 // smallest amount from above taking care to replace the integer part
1418 // with what is in original time. For example, If smallest amount
1419 // is 9.35s and the formatted time is 0:00:09 then 9.35 becomes 09.35
1420 // and replacing yields 0:00:09.35
1421 if (smallestFieldPosition
.getBeginIndex() != 0 ||
1422 smallestFieldPosition
.getEndIndex() != 0) {
1423 appendRange(draft
, 0, smallestFieldPosition
.getBeginIndex(), appendTo
);
1425 smallestAmountFormatted
,
1427 intFieldPosition
.getBeginIndex(),
1431 smallestFieldPosition
.getBeginIndex(),
1432 smallestFieldPosition
.getEndIndex(),
1435 smallestAmountFormatted
,
1436 intFieldPosition
.getEndIndex(),
1440 smallestFieldPosition
.getEndIndex(),
1442 handler
.addAttribute(measField
, start
+ smallestFieldPosition
.getBeginIndex(), appendTo
.length());
1443 handler
.addAttribute(measField
| UAMEASFMT_NUMERIC_FIELD_FLAG
, start
+ smallestFieldPosition
.getBeginIndex(), appendTo
.length());
1445 appendTo
.append(draft
);
1450 const SimpleFormatter
*MeasureFormat::getFormatterOrNull(
1451 const MeasureUnit
&unit
, UMeasureFormatWidth width
, int32_t index
) const {
1452 width
= getRegularWidth(width
);
1453 SimpleFormatter
*const (*unitPatterns
)[MeasureFormatCacheData::PATTERN_COUNT
] =
1454 &cache
->patterns
[unit
.getIndex()][0];
1455 if (unitPatterns
[width
][index
] != NULL
) {
1456 return unitPatterns
[width
][index
];
1458 int32_t fallbackWidth
= cache
->widthFallback
[width
];
1459 if (fallbackWidth
!= UMEASFMT_WIDTH_COUNT
&& unitPatterns
[fallbackWidth
][index
] != NULL
) {
1460 return unitPatterns
[fallbackWidth
][index
];
1465 const SimpleFormatter
*MeasureFormat::getFormatter(
1466 const MeasureUnit
&unit
, UMeasureFormatWidth width
, int32_t index
,
1467 UErrorCode
&errorCode
) const {
1468 if (U_FAILURE(errorCode
)) {
1471 const SimpleFormatter
*pattern
= getFormatterOrNull(unit
, width
, index
);
1472 if (pattern
== NULL
) {
1473 errorCode
= U_MISSING_RESOURCE_ERROR
;
1478 const SimpleFormatter
*MeasureFormat::getPluralFormatter(
1479 const MeasureUnit
&unit
, UMeasureFormatWidth width
, int32_t index
,
1480 UErrorCode
&errorCode
) const {
1481 if (U_FAILURE(errorCode
)) {
1484 if (index
!= StandardPlural::OTHER
) {
1485 const SimpleFormatter
*pattern
= getFormatterOrNull(unit
, width
, index
);
1486 if (pattern
!= NULL
) {
1490 return getFormatter(unit
, width
, StandardPlural::OTHER
, errorCode
);
1493 const SimpleFormatter
*MeasureFormat::getPerFormatter(
1494 UMeasureFormatWidth width
,
1495 UErrorCode
&status
) const {
1496 if (U_FAILURE(status
)) {
1499 width
= getRegularWidth(width
);
1500 const SimpleFormatter
* perFormatters
= cache
->perFormatters
;
1501 if (perFormatters
[width
].getArgumentLimit() == 2) {
1502 return &perFormatters
[width
];
1504 int32_t fallbackWidth
= cache
->widthFallback
[width
];
1505 if (fallbackWidth
!= UMEASFMT_WIDTH_COUNT
&&
1506 perFormatters
[fallbackWidth
].getArgumentLimit() == 2) {
1507 return &perFormatters
[fallbackWidth
];
1509 status
= U_MISSING_RESOURCE_ERROR
;
1513 int32_t MeasureFormat::withPerUnitAndAppend(
1514 const UnicodeString
&formatted
,
1515 const MeasureUnit
&perUnit
,
1516 UnicodeString
&appendTo
,
1517 UErrorCode
&status
) const {
1518 int32_t offset
= -1;
1519 if (U_FAILURE(status
)) {
1522 const SimpleFormatter
*perUnitFormatter
=
1523 getFormatterOrNull(perUnit
, width
, MeasureFormatCacheData::PER_UNIT_INDEX
);
1524 if (perUnitFormatter
!= NULL
) {
1525 const UnicodeString
*params
[] = {&formatted
};
1526 perUnitFormatter
->formatAndAppend(
1528 UPRV_LENGTHOF(params
),
1535 const SimpleFormatter
*perFormatter
= getPerFormatter(width
, status
);
1536 const SimpleFormatter
*pattern
=
1537 getPluralFormatter(perUnit
, width
, StandardPlural::ONE
, status
);
1538 if (U_FAILURE(status
)) {
1541 UnicodeString perUnitString
= pattern
->getTextWithNoArguments();
1542 perUnitString
.trim();
1543 const UnicodeString
*params
[] = {&formatted
, &perUnitString
};
1544 perFormatter
->formatAndAppend(
1546 UPRV_LENGTHOF(params
),
1554 UnicodeString
&MeasureFormat::formatMeasuresSlowTrack(
1555 const Measure
*measures
,
1556 int32_t measureCount
,
1557 UnicodeString
& appendTo
,
1559 UErrorCode
& status
) const {
1560 if (U_FAILURE(status
)) {
1563 FieldPosition
dontCare(FieldPosition::DONT_CARE
);
1564 FieldPosition
fpos(pos
.getField());
1565 UnicodeString
*results
= new UnicodeString
[measureCount
];
1566 int32_t fieldPositionFoundIndex
= -1;
1567 for (int32_t i
= 0; i
< measureCount
; ++i
) {
1568 const NumberFormat
*nf
= cache
->getIntegerFormat();
1569 if (i
== measureCount
- 1) {
1570 nf
= numberFormat
->get();
1572 if (fieldPositionFoundIndex
== -1) {
1573 formatMeasure(measures
[i
], *nf
, results
[i
], fpos
, status
);
1574 if (U_FAILURE(status
)) {
1578 if (fpos
.getBeginIndex() != 0 || fpos
.getEndIndex() != 0) {
1579 fieldPositionFoundIndex
= i
;
1582 formatMeasure(measures
[i
], *nf
, results
[i
], dontCare
, status
);
1586 listFormatter
->format(
1590 fieldPositionFoundIndex
,
1593 if (U_FAILURE(status
)) {
1598 pos
.setBeginIndex(fpos
.getBeginIndex() + offset
);
1599 pos
.setEndIndex(fpos
.getEndIndex() + offset
);
1605 MeasureFormat
* U_EXPORT2
MeasureFormat::createCurrencyFormat(const Locale
& locale
,
1607 CurrencyFormat
* fmt
= NULL
;
1608 if (U_SUCCESS(ec
)) {
1609 fmt
= new CurrencyFormat(locale
, ec
);
1610 if (U_FAILURE(ec
)) {
1618 MeasureFormat
* U_EXPORT2
MeasureFormat::createCurrencyFormat(UErrorCode
& ec
) {
1619 if (U_FAILURE(ec
)) {
1622 return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec
);
1627 #endif /* #if !UCONFIG_NO_FORMATTING */