]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/measfmt.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / i18n / measfmt.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
374ca955
A
3/*
4**********************************************************************
2ca993e8 5* Copyright (c) 2004-2016, International Business Machines
374ca955
A
6* Corporation and others. All Rights Reserved.
7**********************************************************************
8* Author: Alan Liu
9* Created: April 20, 2004
10* Since: ICU 3.0
11**********************************************************************
12*/
57a6839d 13#include "utypeinfo.h" // for 'typeid' to work
374ca955
A
14#include "unicode/utypes.h"
15
16#if !UCONFIG_NO_FORMATTING
17
18#include "unicode/measfmt.h"
57a6839d 19#include "unicode/numfmt.h"
374ca955 20#include "currfmt.h"
57a6839d 21#include "unicode/localpointer.h"
2ca993e8
A
22#include "resource.h"
23#include "unicode/simpleformatter.h"
57a6839d
A
24#include "quantityformatter.h"
25#include "unicode/plurrule.h"
26#include "unicode/decimfmt.h"
57a6839d
A
27#include "uresimp.h"
28#include "unicode/ures.h"
f3c0d7a5 29#include "unicode/ustring.h"
b331163b 30#include "ureslocs.h"
57a6839d
A
31#include "cstring.h"
32#include "mutex.h"
33#include "ucln_in.h"
34#include "unicode/listformatter.h"
35#include "charstr.h"
36#include "unicode/putil.h"
37#include "unicode/smpdtfmt.h"
b331163b 38#include "uassert.h"
3d1f044b
A
39#include "unicode/numberformatter.h"
40#include "number_longnames.h"
41// Apple-specific
2ca993e8
A
42#include "unicode/uameasureformat.h"
43#include "fphdlimp.h"
57a6839d
A
44
45#include "sharednumberformat.h"
46#include "sharedpluralrules.h"
2ca993e8 47#include "standardplural.h"
b331163b 48#include "unifiedcache.h"
57a6839d 49
57a6839d 50
374ca955
A
51U_NAMESPACE_BEGIN
52
0f5d89e8
A
53static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
54
57a6839d
A
55UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
56
57// Used to format durations like 5:47 or 21:35:42.
58class NumericDateFormatters : public UMemory {
59public:
60 // Formats like H:mm
340931cb 61 UnicodeString hourMinute;
57a6839d
A
62
63 // formats like M:ss
340931cb 64 UnicodeString minuteSecond;
57a6839d
A
65
66 // formats like H:mm:ss
340931cb 67 UnicodeString hourMinuteSecond;
57a6839d
A
68
69 // Constructor that takes the actual patterns for hour-minute,
70 // minute-second, and hour-minute-second respectively.
71 NumericDateFormatters(
72 const UnicodeString &hm,
73 const UnicodeString &ms,
340931cb
A
74 const UnicodeString &hms) :
75 hourMinute(hm),
76 minuteSecond(ms),
77 hourMinuteSecond(hms) {
57a6839d
A
78 }
79private:
80 NumericDateFormatters(const NumericDateFormatters &other);
81 NumericDateFormatters &operator=(const NumericDateFormatters &other);
82};
83
2ca993e8
A
84static UMeasureFormatWidth getRegularWidth(UMeasureFormatWidth width) {
85 if (width >= WIDTH_INDEX_COUNT) {
86 return UMEASFMT_WIDTH_NARROW;
87 }
88 return width;
89}
90
3d1f044b
A
91static UNumberUnitWidth getUnitWidth(UMeasureFormatWidth width) {
92 switch (width) {
93 case UMEASFMT_WIDTH_WIDE:
94 return UNUM_UNIT_WIDTH_FULL_NAME;
95 case UMEASFMT_WIDTH_NARROW:
96 case UMEASFMT_WIDTH_NUMERIC:
97 return UNUM_UNIT_WIDTH_NARROW;
98 case UMEASFMT_WIDTH_SHORT:
99 default:
100 return UNUM_UNIT_WIDTH_SHORT;
101 }
102}
103
2ca993e8
A
104/**
105 * Instances contain all MeasureFormat specific data for a particular locale.
106 * This data is cached. It is never copied, but is shared via shared pointers.
107 *
108 * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of
109 * complete sets of unit & per patterns,
110 * to correspond to the resource data and its aliases.
111 *
112 * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
113 */
57a6839d
A
114class MeasureFormatCacheData : public SharedObject {
115public:
2ca993e8
A
116
117 /**
118 * Redirection data from root-bundle, top-level sideways aliases.
119 * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root
120 * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data
121 */
122 UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT];
b331163b 123
57a6839d 124 MeasureFormatCacheData();
2ca993e8
A
125 virtual ~MeasureFormatCacheData();
126
57a6839d
A
127 void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) {
128 delete currencyFormats[widthIndex];
129 currencyFormats[widthIndex] = nfToAdopt;
130 }
2ca993e8
A
131 const NumberFormat *getCurrencyFormat(UMeasureFormatWidth width) const {
132 return currencyFormats[getRegularWidth(width)];
57a6839d
A
133 }
134 void adoptIntegerFormat(NumberFormat *nfToAdopt) {
135 delete integerFormat;
136 integerFormat = nfToAdopt;
137 }
138 const NumberFormat *getIntegerFormat() const {
139 return integerFormat;
140 }
141 void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) {
142 delete numericDateFormatters;
143 numericDateFormatters = formattersToAdopt;
144 }
145 const NumericDateFormatters *getNumericDateFormatters() const {
146 return numericDateFormatters;
147 }
2ca993e8 148
57a6839d 149private:
0f5d89e8
A
150 NumberFormat* currencyFormats[WIDTH_INDEX_COUNT];
151 NumberFormat* integerFormat;
152 NumericDateFormatters* numericDateFormatters;
153
57a6839d
A
154 MeasureFormatCacheData(const MeasureFormatCacheData &other);
155 MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
156};
157
0f5d89e8
A
158MeasureFormatCacheData::MeasureFormatCacheData()
159 : integerFormat(nullptr), numericDateFormatters(nullptr) {
2ca993e8
A
160 for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
161 widthFallback[i] = UMEASFMT_WIDTH_COUNT;
162 }
0f5d89e8 163 memset(currencyFormats, 0, sizeof(currencyFormats));
57a6839d
A
164}
165
166MeasureFormatCacheData::~MeasureFormatCacheData() {
b331163b 167 for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
57a6839d
A
168 delete currencyFormats[i];
169 }
f3c0d7a5 170 // Note: the contents of 'dnams' are pointers into the resource bundle
57a6839d
A
171 delete integerFormat;
172 delete numericDateFormatters;
173}
174
57a6839d
A
175static UBool isCurrency(const MeasureUnit &unit) {
176 return (uprv_strcmp(unit.getType(), "currency") == 0);
177}
178
179static UBool getString(
180 const UResourceBundle *resource,
181 UnicodeString &result,
182 UErrorCode &status) {
183 int32_t len = 0;
184 const UChar *resStr = ures_getString(resource, &len, &status);
185 if (U_FAILURE(status)) {
186 return FALSE;
187 }
188 result.setTo(TRUE, resStr, len);
189 return TRUE;
190}
191
2ca993e8 192static const UAMeasureUnit indexToUAMsasUnit[] = {
3d1f044b
A
193 // UAMeasureUnit // UAMeasUnit vals # MeasUnit.getIndex()
194 // # --- acceleration (0)
195 UAMEASUNIT_ACCELERATION_G_FORCE, // (0 << 8) + 0, # 0 g-force
196 UAMEASUNIT_ACCELERATION_METER_PER_SECOND_SQUARED, // (0 << 8) + 1, # 1 meter-per-second-squared
197 // # --- angle (2)
198 UAMEASUNIT_ANGLE_ARC_MINUTE, // (1 << 8) + 1, # 2 arc-minute
199 UAMEASUNIT_ANGLE_ARC_SECOND, // (1 << 8) + 2, # 3 arc-second
200 UAMEASUNIT_ANGLE_DEGREE, // (1 << 8) + 0, # 4 degree
201 UAMEASUNIT_ANGLE_RADIAN, // (1 << 8) + 3, # 5 radian
202 UAMEASUNIT_ANGLE_REVOLUTION, // (1 << 8) + 4, # 6 revolution
203 // # --- area (7)
204 UAMEASUNIT_AREA_ACRE, // (2 << 8) + 4, # 7 acre
205 UAMEASUNIT_AREA_DUNAM, // (2 << 8) + 9, # 8 dunam
206 UAMEASUNIT_AREA_HECTARE, // (2 << 8) + 5, # 9 hectare
207 UAMEASUNIT_AREA_SQUARE_CENTIMETER, // (2 << 8) + 6, # 10 square-centimeter
208 UAMEASUNIT_AREA_SQUARE_FOOT, // (2 << 8) + 2, # 11 square-foot
209 UAMEASUNIT_AREA_SQUARE_INCH, // (2 << 8) + 7, # 12 square-inch
210 UAMEASUNIT_AREA_SQUARE_KILOMETER, // (2 << 8) + 1, # 13 square-kilometer
211 UAMEASUNIT_AREA_SQUARE_METER, // (2 << 8) + 0, # 14 square-meter
212 UAMEASUNIT_AREA_SQUARE_MILE, // (2 << 8) + 3, # 15 square-mile
213 UAMEASUNIT_AREA_SQUARE_YARD, // (2 << 8) + 8, # 16 square-yard
214 // # --- concentr (17)
215 UAMEASUNIT_CONCENTRATION_KARAT, // (18 << 8) + 0, # 17 karat
216 UAMEASUNIT_CONCENTRATION_MILLIGRAM_PER_DECILITER, // (18 << 8) + 1, # 18 milligram-per-deciliter
217 UAMEASUNIT_CONCENTRATION_MILLIMOLE_PER_LITER, // (18 << 8) + 2, # 19 millimole-per-liter
218 UAMEASUNIT_CONCENTRATION_MOLE, // (18 << 8) + 7, # 20 mole
219 UAMEASUNIT_CONCENTRATION_PART_PER_MILLION, // (18 << 8) + 3, # 21 part-per-million
220 UAMEASUNIT_CONCENTRATION_PERCENT, // (18 << 8) + 4, # 22 percent
221 UAMEASUNIT_CONCENTRATION_PERMILLE, // (18 << 8) + 5, # 23 permille
222 UAMEASUNIT_CONCENTRATION_PERMYRIAD, // (18 << 8) + 6, # 24 permyriad
223 // # --- consumption (25)
224 UAMEASUNIT_CONSUMPTION_LITER_PER_100_KILOMETERs, // (13 << 8) + 2, # 25 liter-per-100kilometers
225 UAMEASUNIT_CONSUMPTION_LITER_PER_KILOMETER, // (13 << 8) + 0, # 26 liter-per-kilometer
226 UAMEASUNIT_CONSUMPTION_MILE_PER_GALLON, // (13 << 8) + 1, # 27 mile-per-gallon
227 UAMEASUNIT_CONSUMPTION_MILE_PER_GALLON_IMPERIAL, // (13 << 8) + 3, # 28 mile-per-gallon-imperial
228 // # --- currency (29)
229 // # --- digital (29)
230 UAMEASUNIT_DIGITAL_BIT, // (14 << 8) + 0, # 29 bit
231 UAMEASUNIT_DIGITAL_BYTE, // (14 << 8) + 1, # 30 byte
232 UAMEASUNIT_DIGITAL_GIGABIT, // (14 << 8) + 2, # 31 gigabit
233 UAMEASUNIT_DIGITAL_GIGABYTE, // (14 << 8) + 3, # 32 gigabyte
234 UAMEASUNIT_DIGITAL_KILOBIT, // (14 << 8) + 4, # 33 kilobit
235 UAMEASUNIT_DIGITAL_KILOBYTE, // (14 << 8) + 5, # 34 kilobyte
236 UAMEASUNIT_DIGITAL_MEGABIT, // (14 << 8) + 6, # 35 megabit
237 UAMEASUNIT_DIGITAL_MEGABYTE, // (14 << 8) + 7, # 36 megabyte
238 UAMEASUNIT_DIGITAL_PETABYTE, // (14 << 8) + 10, # 37 petabyte
239 UAMEASUNIT_DIGITAL_TERABIT, // (14 << 8) + 8, # 38 terabit
240 UAMEASUNIT_DIGITAL_TERABYTE, // (14 << 8) + 9, # 39 terabyte
241 // # --- duration (40)
242 UAMEASUNIT_DURATION_CENTURY, // (4 << 8) + 10, # 40 century
243 UAMEASUNIT_DURATION_DAY, // (4 << 8) + 3, # 41 day
244 UAMEASUNIT_DURATION_DAY_PERSON, // (4 << 8) + 14, # 42 day-person
340931cb
A
245 UAMEASUNIT_DURATION_DECADE, // (4 << 8) + 15, # 43 decade
246 UAMEASUNIT_DURATION_HOUR, // (4 << 8) + 4, # 44 hour
247 UAMEASUNIT_DURATION_MICROSECOND, // (4 << 8) + 8, # 45 microsecond
248 UAMEASUNIT_DURATION_MILLISECOND, // (4 << 8) + 7, # 46 millisecond
249 UAMEASUNIT_DURATION_MINUTE, // (4 << 8) + 5, # 47 minute
250 UAMEASUNIT_DURATION_MONTH, // (4 << 8) + 1, # 48 month
251 UAMEASUNIT_DURATION_MONTH_PERSON, // (4 << 8) + 12, # 49 month-person
252 UAMEASUNIT_DURATION_NANOSECOND, // (4 << 8) + 9, # 50 nanosecond
253 UAMEASUNIT_DURATION_SECOND, // (4 << 8) + 6, # 51 second
254 UAMEASUNIT_DURATION_WEEK, // (4 << 8) + 2, # 52 week
255 UAMEASUNIT_DURATION_WEEK_PERSON, // (4 << 8) + 13, # 53 week-person
256 UAMEASUNIT_DURATION_YEAR, // (4 << 8) + 0, # 54 year
257 UAMEASUNIT_DURATION_YEAR_PERSON, // (4 << 8) + 11, # 55 year-person
258 // # --- electric (56)
259 UAMEASUNIT_ELECTRIC_AMPERE, // (15 << 8) + 0, # 56 ampere
260 UAMEASUNIT_ELECTRIC_MILLIAMPERE, // (15 << 8) + 1, # 57 milliampere
261 UAMEASUNIT_ELECTRIC_OHM, // (15 << 8) + 2, # 58 ohm
262 UAMEASUNIT_ELECTRIC_VOLT, // (15 << 8) + 3, # 59 volt
263 // # --- energy (60)
264 UAMEASUNIT_ENERGY_BRITISH_THERMAL_UNIT, // (12 << 8) + 7, # 60 british-thermal-unit
265 UAMEASUNIT_ENERGY_CALORIE, // (12 << 8) + 0, # 61 calorie
266 UAMEASUNIT_ENERGY_ELECTRONVOLT, // (12 << 8) + 6, # 62 electronvolt
267 UAMEASUNIT_ENERGY_FOODCALORIE, // (12 << 8) + 1, # 63 foodcalorie
268 UAMEASUNIT_ENERGY_JOULE, // (12 << 8) + 2, # 64 joule
269 UAMEASUNIT_ENERGY_KILOCALORIE, // (12 << 8) + 3, # 65 kilocalorie
270 UAMEASUNIT_ENERGY_KILOJOULE, // (12 << 8) + 4, # 66 kilojoule
271 UAMEASUNIT_ENERGY_KILOWATT_HOUR, // (12 << 8) + 5, # 67 kilowatt-hour
272 UAMEASUNIT_ENERGY_THERM_US, // (12 << 8) + 8, # 68 therm-us
273 // # --- force (69)
274 UAMEASUNIT_FORCE_NEWTON, // (19 << 8) + 0, # 69 newton
275 UAMEASUNIT_FORCE_POUND_FORCE, // (19 << 8) + 1, # 70 pound-force
276 // # --- frequency (71)
277 UAMEASUNIT_FREQUENCY_GIGAHERTZ, // (16 << 8) + 3, # 71 gigahertz
278 UAMEASUNIT_FREQUENCY_HERTZ, // (16 << 8) + 0, # 72 hertz
279 UAMEASUNIT_FREQUENCY_KILOHERTZ, // (16 << 8) + 1, # 73 kilohertz
280 UAMEASUNIT_FREQUENCY_MEGAHERTZ, // (16 << 8) + 2, # 74 megahertz
281 // # --- graphics (75)
282 UAMEASUNIT_GRAPHICS_DOT_PER_CENTIMETER, // (21 << 8) + 5, # 75 dot-per-centimeter
283 UAMEASUNIT_GRAPHICS_DOT_PER_INCH, // (21 << 8) + 6, # 76 dot-per-inch
284 UAMEASUNIT_GRAPHICS_EM, // (21 << 8) + 0, # 77 em
285 UAMEASUNIT_GRAPHICS_MEGAPIXEL, // (21 << 8) + 2, # 78 megapixel
286 UAMEASUNIT_GRAPHICS_PIXEL, // (21 << 8) + 1, # 79 pixel
287 UAMEASUNIT_GRAPHICS_PIXEL_PER_CENTIMETER, // (21 << 8) + 3, # 80 pixel-per-centimeter
288 UAMEASUNIT_GRAPHICS_PIXEL_PER_INCH, // (21 << 8) + 4, # 81 pixel-per-inch
289 // # --- length (82)
290 UAMEASUNIT_LENGTH_ASTRONOMICAL_UNIT, // (5 << 8) + 16, # 82 astronomical-unit
291 UAMEASUNIT_LENGTH_CENTIMETER, // (5 << 8) + 1, # 83 centimeter
292 UAMEASUNIT_LENGTH_DECIMETER, // (5 << 8) + 10, # 84 decimeter
293 UAMEASUNIT_LENGTH_FATHOM, // (5 << 8) + 14, # 85 fathom
294 UAMEASUNIT_LENGTH_FOOT, // (5 << 8) + 5, # 86 foot
295 UAMEASUNIT_LENGTH_FURLONG, // (5 << 8) + 15, # 87 furlong
296 UAMEASUNIT_LENGTH_INCH, // (5 << 8) + 6, # 88 inch
297 UAMEASUNIT_LENGTH_KILOMETER, // (5 << 8) + 2, # 89 kilometer
298 UAMEASUNIT_LENGTH_LIGHT_YEAR, // (5 << 8) + 9, # 90 light-year
299 UAMEASUNIT_LENGTH_METER, // (5 << 8) + 0, # 91 meter
300 UAMEASUNIT_LENGTH_MICROMETER, // (5 << 8) + 11, # 92 micrometer
301 UAMEASUNIT_LENGTH_MILE, // (5 << 8) + 7, # 93 mile
302 UAMEASUNIT_LENGTH_MILE_SCANDINAVIAN, // (5 << 8) + 18, # 94 mile-scandinavian
303 UAMEASUNIT_LENGTH_MILLIMETER, // (5 << 8) + 3, # 95 millimeter
304 UAMEASUNIT_LENGTH_NANOMETER, // (5 << 8) + 12, # 96 nanometer
305 UAMEASUNIT_LENGTH_NAUTICAL_MILE, // (5 << 8) + 13, # 97 nautical-mile
306 UAMEASUNIT_LENGTH_PARSEC, // (5 << 8) + 17, # 98 parsec
307 UAMEASUNIT_LENGTH_PICOMETER, // (5 << 8) + 4, # 99 picometer
308 UAMEASUNIT_LENGTH_POINT, // (5 << 8) + 19, # 100 point
309 UAMEASUNIT_LENGTH_SOLAR_RADIUS, // (5 << 8) + 20, # 101 solar-radius
310 UAMEASUNIT_LENGTH_YARD, // (5 << 8) + 8, # 102 yard
311 // # --- light (103)
312 UAMEASUNIT_LIGHT_LUX, // (17 << 8) + 0, # 103 lux
313 UAMEASUNIT_LIGHT_SOLAR_LUMINOSITY, // (17 << 8) + 1, # 104 solar-luminosity
314 // # --- mass (105)
315 UAMEASUNIT_MASS_CARAT, // (6 << 8) + 9, # 105 carat
316 UAMEASUNIT_MASS_DALTON, // (6 << 8) + 11, # 106 dalton
317 UAMEASUNIT_MASS_EARTH_MASS, // (6 << 8) + 12, # 107 earth-mass
318 UAMEASUNIT_MASS_GRAM, // (6 << 8) + 0, # 108 gram
319 UAMEASUNIT_MASS_KILOGRAM, // (6 << 8) + 1, # 109 kilogram
320 UAMEASUNIT_MASS_METRIC_TON, // (6 << 8) + 7, # 110 metric-ton
321 UAMEASUNIT_MASS_MICROGRAM, // (6 << 8) + 5, # 111 microgram
322 UAMEASUNIT_MASS_MILLIGRAM, // (6 << 8) + 6, # 112 milligram
323 UAMEASUNIT_MASS_OUNCE, // (6 << 8) + 2, # 113 ounce
324 UAMEASUNIT_MASS_OUNCE_TROY, // (6 << 8) + 10, # 114 ounce-troy
325 UAMEASUNIT_MASS_POUND, // (6 << 8) + 3, # 115 pound
326 UAMEASUNIT_MASS_SOLAR_MASS, // (6 << 8) + 13, # 116 solar-mass
327 UAMEASUNIT_MASS_STONE, // (6 << 8) + 4, # 117 stone
328 UAMEASUNIT_MASS_TON, // (6 << 8) + 8, # 118 ton
329 // # --- none (119)
330 UAMEASUNIT_CONCENTRATION_PERCENT, // BOGUS # 119 base
331 UAMEASUNIT_CONCENTRATION_PERCENT, // BOGUS # 120 percent
332 UAMEASUNIT_CONCENTRATION_PERMILLE, // BOGUS # 121 permille
333 // # --- power (122)
334 UAMEASUNIT_POWER_GIGAWATT, // (7 << 8) + 5, # 122 gigawatt
335 UAMEASUNIT_POWER_HORSEPOWER, // (7 << 8) + 2, # 123 horsepower
336 UAMEASUNIT_POWER_KILOWATT, // (7 << 8) + 1, # 124 kilowatt
337 UAMEASUNIT_POWER_MEGAWATT, // (7 << 8) + 4, # 125 megawatt
338 UAMEASUNIT_POWER_MILLIWATT, // (7 << 8) + 3, # 126 milliwatt
339 UAMEASUNIT_POWER_WATT, // (7 << 8) + 0, # 127 watt
340 // # --- pressure (128)
341 UAMEASUNIT_PRESSURE_ATMOSPHERE, // (8 << 8) + 5, # 128 atmosphere
342 UAMEASUNIT_PRESSURE_BAR, // (8 << 8) + 9, # 129 bar
343 UAMEASUNIT_PRESSURE_HECTOPASCAL, // (8 << 8) + 0, # 130 hectopascal
344 UAMEASUNIT_PRESSURE_INCH_HG, // (8 << 8) + 1, # 131 inch-hg
345 UAMEASUNIT_PRESSURE_KILOPASCAL, // (8 << 8) + 6, # 132 kilopascal
346 UAMEASUNIT_PRESSURE_MEGAPASCAL, // (8 << 8) + 7, # 133 megapascal
347 UAMEASUNIT_PRESSURE_MILLIBAR, // (8 << 8) + 2, # 134 millibar
348 UAMEASUNIT_PRESSURE_MILLIMETER_OF_MERCURY, // (8 << 8) + 3, # 135 millimeter-of-mercury
349 UAMEASUNIT_PRESSURE_PASCAL, // (8 << 8) + 8, # 136 pascal
350 UAMEASUNIT_PRESSURE_POUND_PER_SQUARE_INCH, // (8 << 8) + 4, # 137 pound-per-square-inch
351 // # --- speed (138)
352 UAMEASUNIT_SPEED_KILOMETER_PER_HOUR, // (9 << 8) + 1, # 138 kilometer-per-hour
353 UAMEASUNIT_SPEED_KNOT, // (9 << 8) + 3, # 139 knot
354 UAMEASUNIT_SPEED_METER_PER_SECOND, // (9 << 8) + 0, # 140 meter-per-second
355 UAMEASUNIT_SPEED_MILE_PER_HOUR, // (9 << 8) + 2, # 141 mile-per-hour
356 // # --- temperature (142)
357 UAMEASUNIT_TEMPERATURE_CELSIUS, // (10 << 8) + 0, # 142 celsius
358 UAMEASUNIT_TEMPERATURE_FAHRENHEIT, // (10 << 8) + 1, # 143 fahrenheit
359 UAMEASUNIT_TEMPERATURE_GENERIC, // (10 << 8) + 3, # 144 generic
360 UAMEASUNIT_TEMPERATURE_KELVIN, // (10 << 8) + 2, # 145 kelvin
361 // # --- torque (146)
362 UAMEASUNIT_TORQUE_NEWTON_METER, // (20 << 8) + 0, # 146 newton-meter
363 UAMEASUNIT_TORQUE_POUND_FOOT, // (20 << 8) + 1, # 147 pound-foot
364 // # --- volume (148)
365 UAMEASUNIT_VOLUME_ACRE_FOOT, // (11 << 8) + 13, # 148 acre-foot
366 UAMEASUNIT_VOLUME_BARREL, // (11 << 8) + 26, # 149 barrel
367 UAMEASUNIT_VOLUME_BUSHEL, // (11 << 8) + 14, # 150 bushel
368 UAMEASUNIT_VOLUME_CENTILITER, // (11 << 8) + 4, # 151 centiliter
369 UAMEASUNIT_VOLUME_CUBIC_CENTIMETER, // (11 << 8) + 8, # 152 cubic-centimeter
370 UAMEASUNIT_VOLUME_CUBIC_FOOT, // (11 << 8) + 11, # 153 cubic-foot
371 UAMEASUNIT_VOLUME_CUBIC_INCH, // (11 << 8) + 10, # 154 cubic-inch
372 UAMEASUNIT_VOLUME_CUBIC_KILOMETER, // (11 << 8) + 1, # 155 cubic-kilometer
373 UAMEASUNIT_VOLUME_CUBIC_METER, // (11 << 8) + 9, # 156 cubic-meter
374 UAMEASUNIT_VOLUME_CUBIC_MILE, // (11 << 8) + 2, # 157 cubic-mile
375 UAMEASUNIT_VOLUME_CUBIC_YARD, // (11 << 8) + 12, # 158 cubic-yard
376 UAMEASUNIT_VOLUME_CUP, // (11 << 8) + 18, # 159 cup
377 UAMEASUNIT_VOLUME_CUP_METRIC, // (11 << 8) + 22, # 160 cup-metric
378 UAMEASUNIT_VOLUME_DECILITER, // (11 << 8) + 5, # 161 deciliter
379 UAMEASUNIT_VOLUME_FLUID_OUNCE, // (11 << 8) + 17, # 162 fluid-ounce
380 UAMEASUNIT_VOLUME_FLUID_OUNCE_IMPERIAL, // (11 << 8) + 25, # 163 fluid-ounce-imperial
381 UAMEASUNIT_VOLUME_GALLON, // (11 << 8) + 21, # 164 gallon
382 UAMEASUNIT_VOLUME_GALLON_IMPERIAL, // (11 << 8) + 24, # 165 gallon-imperial
383 UAMEASUNIT_VOLUME_HECTOLITER, // (11 << 8) + 6, # 166 hectoliter
384 UAMEASUNIT_VOLUME_LITER, // (11 << 8) + 0, # 167 liter
385 UAMEASUNIT_VOLUME_MEGALITER, // (11 << 8) + 7, # 168 megaliter
386 UAMEASUNIT_VOLUME_MILLILITER, // (11 << 8) + 3, # 169 milliliter
387 UAMEASUNIT_VOLUME_PINT, // (11 << 8) + 19, # 170 pint
388 UAMEASUNIT_VOLUME_PINT_METRIC, // (11 << 8) + 23, # 171 pint-metric
389 UAMEASUNIT_VOLUME_QUART, // (11 << 8) + 20, # 172 quart
390 UAMEASUNIT_VOLUME_TABLESPOON, // (11 << 8) + 16, # 173 tablespoon
391 UAMEASUNIT_VOLUME_TEASPOON, // (11 << 8) + 15, # 174 teaspoon
2ca993e8
A
392};
393
57a6839d
A
394static UnicodeString loadNumericDateFormatterPattern(
395 const UResourceBundle *resource,
396 const char *pattern,
397 UErrorCode &status) {
398 UnicodeString result;
399 if (U_FAILURE(status)) {
400 return result;
401 }
402 CharString chs;
403 chs.append("durationUnits", status)
404 .append("/", status).append(pattern, status);
405 LocalUResourceBundlePointer patternBundle(
406 ures_getByKeyWithFallback(
407 resource,
408 chs.data(),
409 NULL,
410 &status));
411 if (U_FAILURE(status)) {
412 return result;
413 }
414 getString(patternBundle.getAlias(), result, status);
415 // Replace 'h' with 'H'
416 int32_t len = result.length();
417 UChar *buffer = result.getBuffer(len);
418 for (int32_t i = 0; i < len; ++i) {
419 if (buffer[i] == 0x68) { // 'h'
420 buffer[i] = 0x48; // 'H'
421 }
422 }
423 result.releaseBuffer(len);
424 return result;
425}
374ca955 426
57a6839d
A
427static NumericDateFormatters *loadNumericDateFormatters(
428 const UResourceBundle *resource,
429 UErrorCode &status) {
430 if (U_FAILURE(status)) {
431 return NULL;
432 }
433 NumericDateFormatters *result = new NumericDateFormatters(
434 loadNumericDateFormatterPattern(resource, "hm", status),
435 loadNumericDateFormatterPattern(resource, "ms", status),
340931cb 436 loadNumericDateFormatterPattern(resource, "hms", status));
57a6839d
A
437 if (U_FAILURE(status)) {
438 delete result;
439 return NULL;
440 }
441 return result;
442}
443
b331163b
A
444template<> U_I18N_API
445const MeasureFormatCacheData *LocaleCacheKey<MeasureFormatCacheData>::createObject(
446 const void * /*unused*/, UErrorCode &status) const {
447 const char *localeId = fLoc.getName();
448 LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, localeId, &status));
57a6839d
A
449 static UNumberFormatStyle currencyStyles[] = {
450 UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY};
b331163b 451 LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData(), status);
57a6839d
A
452 if (U_FAILURE(status)) {
453 return NULL;
454 }
57a6839d 455 result->adoptNumericDateFormatters(loadNumericDateFormatters(
b331163b 456 unitsBundle.getAlias(), status));
57a6839d
A
457 if (U_FAILURE(status)) {
458 return NULL;
459 }
460
461 for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
f3c0d7a5
A
462 // NumberFormat::createInstance can erase warning codes from status, so pass it
463 // a separate status instance
464 UErrorCode localStatus = U_ZERO_ERROR;
57a6839d 465 result->adoptCurrencyFormat(i, NumberFormat::createInstance(
f3c0d7a5
A
466 localeId, currencyStyles[i], localStatus));
467 if (localStatus != U_ZERO_ERROR) {
468 status = localStatus;
469 }
57a6839d
A
470 if (U_FAILURE(status)) {
471 return NULL;
472 }
473 }
474 NumberFormat *inf = NumberFormat::createInstance(
475 localeId, UNUM_DECIMAL, status);
476 if (U_FAILURE(status)) {
477 return NULL;
478 }
479 inf->setMaximumFractionDigits(0);
480 DecimalFormat *decfmt = dynamic_cast<DecimalFormat *>(inf);
481 if (decfmt != NULL) {
482 decfmt->setRoundingMode(DecimalFormat::kRoundDown);
483 }
484 result->adoptIntegerFormat(inf);
b331163b 485 result->addRef();
57a6839d
A
486 return result.orphan();
487}
488
57a6839d
A
489static UBool isTimeUnit(const MeasureUnit &mu, const char *tu) {
490 return uprv_strcmp(mu.getType(), "duration") == 0 &&
491 uprv_strcmp(mu.getSubtype(), tu) == 0;
492}
493
494// Converts a composite measure into hours-minutes-seconds and stores at hms
495// array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
496// units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
497// contains hours-minutes, this function would return 3.
498//
499// If measures cannot be converted into hours, minutes, seconds or if amounts
500// are negative, or if hours, minutes, seconds are out of order, returns 0.
501static int32_t toHMS(
502 const Measure *measures,
503 int32_t measureCount,
504 Formattable *hms,
505 UErrorCode &status) {
506 if (U_FAILURE(status)) {
507 return 0;
508 }
509 int32_t result = 0;
510 if (U_FAILURE(status)) {
511 return 0;
512 }
513 // We use copy constructor to ensure that both sides of equality operator
514 // are instances of MeasureUnit base class and not a subclass. Otherwise,
515 // operator== will immediately return false.
516 for (int32_t i = 0; i < measureCount; ++i) {
517 if (isTimeUnit(measures[i].getUnit(), "hour")) {
518 // hour must come first
519 if (result >= 1) {
520 return 0;
521 }
522 hms[0] = measures[i].getNumber();
523 if (hms[0].getDouble() < 0.0) {
524 return 0;
525 }
526 result |= 1;
527 } else if (isTimeUnit(measures[i].getUnit(), "minute")) {
528 // minute must come after hour
529 if (result >= 2) {
530 return 0;
531 }
532 hms[1] = measures[i].getNumber();
533 if (hms[1].getDouble() < 0.0) {
534 return 0;
535 }
536 result |= 2;
537 } else if (isTimeUnit(measures[i].getUnit(), "second")) {
538 // second must come after hour and minute
539 if (result >= 4) {
540 return 0;
541 }
542 hms[2] = measures[i].getNumber();
543 if (hms[2].getDouble() < 0.0) {
544 return 0;
545 }
546 result |= 4;
547 } else {
548 return 0;
549 }
550 }
551 return result;
552}
553
554
555MeasureFormat::MeasureFormat(
556 const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
557 : cache(NULL),
558 numberFormat(NULL),
559 pluralRules(NULL),
3d1f044b 560 fWidth((w==UMEASFMT_WIDTH_SHORTER)? UMEASFMT_WIDTH_SHORT: w),
2ca993e8
A
561 stripPatternSpaces(w==UMEASFMT_WIDTH_SHORTER),
562 listFormatter(NULL),
563 listFormatterStd(NULL) {
564 initMeasureFormat(locale, (w==UMEASFMT_WIDTH_SHORTER)? UMEASFMT_WIDTH_SHORT: w, NULL, status);
57a6839d
A
565}
566
567MeasureFormat::MeasureFormat(
568 const Locale &locale,
569 UMeasureFormatWidth w,
570 NumberFormat *nfToAdopt,
f3c0d7a5 571 UErrorCode &status)
57a6839d
A
572 : cache(NULL),
573 numberFormat(NULL),
574 pluralRules(NULL),
3d1f044b 575 fWidth((w==UMEASFMT_WIDTH_SHORTER)? UMEASFMT_WIDTH_SHORT: w),
2ca993e8
A
576 stripPatternSpaces(w==UMEASFMT_WIDTH_SHORTER),
577 listFormatter(NULL),
578 listFormatterStd(NULL) {
579 initMeasureFormat(locale, (w==UMEASFMT_WIDTH_SHORTER)? UMEASFMT_WIDTH_SHORT: w, nfToAdopt, status);
57a6839d
A
580}
581
582MeasureFormat::MeasureFormat(const MeasureFormat &other) :
583 Format(other),
584 cache(other.cache),
585 numberFormat(other.numberFormat),
586 pluralRules(other.pluralRules),
3d1f044b 587 fWidth(other.fWidth),
2ca993e8
A
588 stripPatternSpaces(other.stripPatternSpaces),
589 listFormatter(NULL),
590 listFormatterStd(NULL) {
57a6839d
A
591 cache->addRef();
592 numberFormat->addRef();
593 pluralRules->addRef();
2ca993e8
A
594 if (other.listFormatter != NULL) {
595 listFormatter = new ListFormatter(*other.listFormatter);
596 }
597 if (other.listFormatterStd != NULL) {
598 listFormatterStd = new ListFormatter(*other.listFormatterStd);
599 }
57a6839d
A
600}
601
602MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
603 if (this == &other) {
604 return *this;
605 }
606 Format::operator=(other);
607 SharedObject::copyPtr(other.cache, cache);
608 SharedObject::copyPtr(other.numberFormat, numberFormat);
609 SharedObject::copyPtr(other.pluralRules, pluralRules);
3d1f044b 610 fWidth = other.fWidth;
2ca993e8 611 stripPatternSpaces = other.stripPatternSpaces;
57a6839d 612 delete listFormatter;
2ca993e8
A
613 if (other.listFormatter != NULL) {
614 listFormatter = new ListFormatter(*other.listFormatter);
615 } else {
616 listFormatter = NULL;
617 }
618 delete listFormatterStd;
619 if (other.listFormatterStd != NULL) {
620 listFormatterStd = new ListFormatter(*other.listFormatterStd);
621 } else {
622 listFormatterStd = NULL;
623 }
57a6839d
A
624 return *this;
625}
626
627MeasureFormat::MeasureFormat() :
628 cache(NULL),
629 numberFormat(NULL),
630 pluralRules(NULL),
3d1f044b 631 fWidth(UMEASFMT_WIDTH_SHORT),
2ca993e8
A
632 stripPatternSpaces(FALSE),
633 listFormatter(NULL),
634 listFormatterStd(NULL) {
57a6839d
A
635}
636
637MeasureFormat::~MeasureFormat() {
638 if (cache != NULL) {
639 cache->removeRef();
640 }
641 if (numberFormat != NULL) {
642 numberFormat->removeRef();
643 }
644 if (pluralRules != NULL) {
645 pluralRules->removeRef();
646 }
647 delete listFormatter;
2ca993e8 648 delete listFormatterStd;
57a6839d
A
649}
650
651UBool MeasureFormat::operator==(const Format &other) const {
652 if (this == &other) { // Same object, equal
653 return TRUE;
654 }
655 if (!Format::operator==(other)) {
656 return FALSE;
657 }
658 const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other);
659
660 // Note: Since the ListFormatter depends only on Locale and width, we
661 // don't have to check it here.
662
663 // differing widths aren't equivalent
3d1f044b 664 if (fWidth != rhs.fWidth || stripPatternSpaces != rhs.stripPatternSpaces) {
57a6839d
A
665 return FALSE;
666 }
667 // Width the same check locales.
668 // We don't need to check locales if both objects have same cache.
669 if (cache != rhs.cache) {
670 UErrorCode status = U_ZERO_ERROR;
671 const char *localeId = getLocaleID(status);
672 const char *rhsLocaleId = rhs.getLocaleID(status);
673 if (U_FAILURE(status)) {
674 // On failure, assume not equal
675 return FALSE;
676 }
677 if (uprv_strcmp(localeId, rhsLocaleId) != 0) {
678 return FALSE;
679 }
680 }
681 // Locales same, check NumberFormat if shared data differs.
682 return (
683 numberFormat == rhs.numberFormat ||
684 **numberFormat == **rhs.numberFormat);
685}
686
340931cb 687MeasureFormat *MeasureFormat::clone() const {
57a6839d
A
688 return new MeasureFormat(*this);
689}
690
691UnicodeString &MeasureFormat::format(
692 const Formattable &obj,
693 UnicodeString &appendTo,
694 FieldPosition &pos,
695 UErrorCode &status) const {
696 if (U_FAILURE(status)) return appendTo;
697 if (obj.getType() == Formattable::kObject) {
698 const UObject* formatObj = obj.getObject();
699 const Measure* amount = dynamic_cast<const Measure*>(formatObj);
700 if (amount != NULL) {
701 return formatMeasure(
702 *amount, **numberFormat, appendTo, pos, status);
703 }
704 }
705 status = U_ILLEGAL_ARGUMENT_ERROR;
706 return appendTo;
707}
708
709void MeasureFormat::parseObject(
710 const UnicodeString & /*source*/,
711 Formattable & /*result*/,
712 ParsePosition& /*pos*/) const {
713 return;
714}
715
b331163b
A
716UnicodeString &MeasureFormat::formatMeasurePerUnit(
717 const Measure &measure,
718 const MeasureUnit &perUnit,
719 UnicodeString &appendTo,
720 FieldPosition &pos,
721 UErrorCode &status) const {
722 if (U_FAILURE(status)) {
723 return appendTo;
724 }
3d1f044b
A
725 auto* df = dynamic_cast<const DecimalFormat*>(&getNumberFormatInternal());
726 if (df == nullptr) {
727 // Don't know how to handle other types of NumberFormat
728 status = U_UNSUPPORTED_ERROR;
b331163b
A
729 return appendTo;
730 }
3d1f044b
A
731 number::FormattedNumber result;
732 if (auto* lnf = df->toNumberFormatter(status)) {
733 result = lnf->unit(measure.getUnit())
734 .perUnit(perUnit)
735 .unitWidth(getUnitWidth(fWidth))
736 .formatDouble(measure.getNumber().getDouble(status), status);
b331163b 737 }
3d1f044b
A
738 DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
739 appendTo.append(result.toTempString(status));
b331163b
A
740 return appendTo;
741}
742
57a6839d
A
743UnicodeString &MeasureFormat::formatMeasures(
744 const Measure *measures,
745 int32_t measureCount,
746 UnicodeString &appendTo,
747 FieldPosition &pos,
748 UErrorCode &status) const {
749 if (U_FAILURE(status)) {
750 return appendTo;
751 }
752 if (measureCount == 0) {
753 return appendTo;
754 }
755 if (measureCount == 1) {
756 return formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
757 }
3d1f044b 758 if (fWidth == UMEASFMT_WIDTH_NUMERIC) {
57a6839d
A
759 Formattable hms[3];
760 int32_t bitMap = toHMS(measures, measureCount, hms, status);
761 if (bitMap > 0) {
340931cb 762 return formatNumeric(hms, bitMap, appendTo, status);
57a6839d
A
763 }
764 }
765 if (pos.getField() != FieldPosition::DONT_CARE) {
766 return formatMeasuresSlowTrack(
767 measures, measureCount, appendTo, pos, status);
768 }
769 UnicodeString *results = new UnicodeString[measureCount];
770 if (results == NULL) {
771 status = U_MEMORY_ALLOCATION_ERROR;
772 return appendTo;
773 }
774 for (int32_t i = 0; i < measureCount; ++i) {
775 const NumberFormat *nf = cache->getIntegerFormat();
776 if (i == measureCount - 1) {
777 nf = numberFormat->get();
778 }
779 formatMeasure(
780 measures[i],
781 *nf,
782 results[i],
783 pos,
784 status);
785 }
786 listFormatter->format(results, measureCount, appendTo, status);
2ca993e8
A
787 delete [] results;
788 return appendTo;
789}
790
791// Apple-specific version for now;
792// uses FieldPositionIterator* instead of FieldPosition&
793UnicodeString &MeasureFormat::formatMeasures(
794 const Measure *measures,
795 int32_t measureCount,
796 UnicodeString &appendTo,
797 FieldPositionIterator* posIter,
798 UErrorCode &status) const {
799 if (U_FAILURE(status)) {
800 return appendTo;
801 }
802 FieldPositionIteratorHandler handler(posIter, status);
803 if (measureCount == 0) {
804 return appendTo;
805 }
806 if (measureCount == 1) {
807 int32_t start = appendTo.length();
808 int32_t field = indexToUAMsasUnit[measures[0].getUnit().getIndex()];
809 FieldPosition pos(UAMEASFMT_NUMERIC_FIELD_FLAG); // special field value to request range of entire numeric part
810 formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
811 handler.addAttribute(field, start, appendTo.length());
812 handler.addAttribute(field | UAMEASFMT_NUMERIC_FIELD_FLAG, pos.getBeginIndex(), pos.getEndIndex());
813 return appendTo;
814 }
3d1f044b 815 if (fWidth == UMEASFMT_WIDTH_NUMERIC) {
2ca993e8
A
816 Formattable hms[3];
817 int32_t bitMap = toHMS(measures, measureCount, hms, status);
818 if (bitMap > 0) {
340931cb 819 return formatNumeric(hms, bitMap, appendTo, status);
2ca993e8
A
820 }
821 }
822 UnicodeString *results = new UnicodeString[measureCount];
823 if (results == NULL) {
824 status = U_MEMORY_ALLOCATION_ERROR;
825 return appendTo;
826 }
827 FieldPosition *numPositions = new FieldPosition[measureCount];
828 if (results == NULL) {
829 delete [] results;
830 status = U_MEMORY_ALLOCATION_ERROR;
831 return appendTo;
832 }
833
834 for (int32_t i = 0; i < measureCount; ++i) {
835 const NumberFormat *nf = cache->getIntegerFormat();
836 if (i == measureCount - 1) {
837 nf = numberFormat->get();
838 }
839 numPositions[i].setField(UAMEASFMT_NUMERIC_FIELD_FLAG);
840 formatMeasure(
841 measures[i],
842 *nf,
843 results[i],
844 numPositions[i],
845 status);
846 }
847 listFormatter->format(results, measureCount, appendTo, status);
848 for (int32_t i = 0; i < measureCount; ++i) {
849 int32_t begin = appendTo.indexOf(results[i]);
850 if (begin >= 0) {
851 int32_t field = indexToUAMsasUnit[measures[i].getUnit().getIndex()];
852 handler.addAttribute(field, begin, begin + results[i].length());
853 int32_t numPosBegin = numPositions[i].getBeginIndex();
854 int32_t numPosEnd = numPositions[i].getEndIndex();
855 if (numPosBegin >= 0 && numPosEnd > numPosBegin) {
856 handler.addAttribute(field | UAMEASFMT_NUMERIC_FIELD_FLAG, begin + numPosBegin, begin + numPosEnd);
857 }
858 }
859 }
860 delete [] results;
861 delete [] numPositions;
57a6839d
A
862 return appendTo;
863}
864
3d1f044b
A
865UnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& status) const {
866 return number::impl::LongNameHandler::getUnitDisplayName(
867 getLocale(status),
868 unit,
869 getUnitWidth(fWidth),
870 status);
f3c0d7a5
A
871}
872
57a6839d
A
873void MeasureFormat::initMeasureFormat(
874 const Locale &locale,
875 UMeasureFormatWidth w,
876 NumberFormat *nfToAdopt,
877 UErrorCode &status) {
878 static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
879 LocalPointer<NumberFormat> nf(nfToAdopt);
880 if (U_FAILURE(status)) {
881 return;
882 }
883 const char *name = locale.getName();
884 setLocaleIDs(name, name);
885
b331163b
A
886 UnifiedCache::getByLocale(locale, cache, status);
887 if (U_FAILURE(status)) {
57a6839d
A
888 return;
889 }
890
b331163b
A
891 const SharedPluralRules *pr = PluralRules::createSharedInstance(
892 locale, UPLURAL_TYPE_CARDINAL, status);
57a6839d
A
893 if (U_FAILURE(status)) {
894 return;
895 }
b331163b
A
896 SharedObject::copyPtr(pr, pluralRules);
897 pr->removeRef();
57a6839d 898 if (nf.isNull()) {
3d1f044b 899 // TODO: Clean this up
b331163b
A
900 const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
901 locale, UNUM_DECIMAL, status);
57a6839d
A
902 if (U_FAILURE(status)) {
903 return;
904 }
b331163b
A
905 SharedObject::copyPtr(shared, numberFormat);
906 shared->removeRef();
57a6839d
A
907 } else {
908 adoptNumberFormat(nf.orphan(), status);
909 if (U_FAILURE(status)) {
910 return;
911 }
912 }
3d1f044b 913 fWidth = w;
2ca993e8
A
914 if (stripPatternSpaces) {
915 w = UMEASFMT_WIDTH_NARROW;
916 }
57a6839d
A
917 delete listFormatter;
918 listFormatter = ListFormatter::createInstance(
919 locale,
2ca993e8
A
920 listStyles[getRegularWidth(w)],
921 status);
922 delete listFormatterStd;
923 listFormatterStd = ListFormatter::createInstance(
924 locale,
925 "standard",
57a6839d
A
926 status);
927}
928
929void MeasureFormat::adoptNumberFormat(
930 NumberFormat *nfToAdopt, UErrorCode &status) {
931 LocalPointer<NumberFormat> nf(nfToAdopt);
932 if (U_FAILURE(status)) {
933 return;
934 }
935 SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
936 if (shared == NULL) {
937 status = U_MEMORY_ALLOCATION_ERROR;
938 return;
939 }
940 nf.orphan();
941 SharedObject::copyPtr(shared, numberFormat);
942}
943
944UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) {
945 if (U_FAILURE(status) || locale == getLocale(status)) {
946 return FALSE;
947 }
3d1f044b 948 initMeasureFormat(locale, fWidth, NULL, status);
57a6839d 949 return U_SUCCESS(status);
f3c0d7a5 950}
57a6839d 951
b331163b
A
952// Apple-specific for now
953UMeasureFormatWidth MeasureFormat::getWidth() const {
3d1f044b 954 return fWidth;
b331163b
A
955}
956
3d1f044b 957const NumberFormat &MeasureFormat::getNumberFormatInternal() const {
57a6839d
A
958 return **numberFormat;
959}
960
3d1f044b
A
961const NumberFormat &MeasureFormat::getCurrencyFormatInternal() const {
962 return *cache->getCurrencyFormat(UMEASFMT_WIDTH_NARROW);
963}
964
57a6839d
A
965const PluralRules &MeasureFormat::getPluralRules() const {
966 return **pluralRules;
967}
968
969Locale MeasureFormat::getLocale(UErrorCode &status) const {
970 return Format::getLocale(ULOC_VALID_LOCALE, status);
971}
972
973const char *MeasureFormat::getLocaleID(UErrorCode &status) const {
974 return Format::getLocaleID(ULOC_VALID_LOCALE, status);
975}
976
2ca993e8 977// Apple=specific
f3c0d7a5
A
978// now just re-implement using standard getUnitDisplayName
979// so we no longer use cache->getDisplayName
2ca993e8
A
980UnicodeString &MeasureFormat::getUnitName(
981 const MeasureUnit* unit,
982 UnicodeString &result ) const {
f3c0d7a5
A
983 UErrorCode status = U_ZERO_ERROR;
984 result = getUnitDisplayName(*unit, status); // does not use or set status
2ca993e8
A
985 return result;
986}
987
988// Apple=specific
989UnicodeString &MeasureFormat::getMultipleUnitNames(
990 const MeasureUnit** units,
991 int32_t unitCount,
992 UAMeasureNameListStyle listStyle,
993 UnicodeString &result ) const {
994 if (unitCount == 0) {
995 return result.remove();
996 }
997 if (unitCount == 1) {
998 return getUnitName(units[0], result);
999 }
1000 UnicodeString *results = new UnicodeString[unitCount];
1001 if (results != NULL) {
1002 for (int32_t i = 0; i < unitCount; ++i) {
1003 getUnitName(units[i], results[i]);
1004 }
1005 UErrorCode status = U_ZERO_ERROR;
1006 if (listStyle == UAMEASNAME_LIST_STANDARD) {
1007 listFormatterStd->format(results, unitCount, result, status);
1008 } else {
1009 listFormatter->format(results, unitCount, result, status);
1010 }
1011 delete [] results;
1012 if (U_SUCCESS(status)) {
1013 return result;
1014 }
1015 }
1016 result.setToBogus();
1017 return result;
1018}
1019
57a6839d
A
1020UnicodeString &MeasureFormat::formatMeasure(
1021 const Measure &measure,
1022 const NumberFormat &nf,
1023 UnicodeString &appendTo,
1024 FieldPosition &pos,
1025 UErrorCode &status) const {
1026 if (U_FAILURE(status)) {
1027 return appendTo;
1028 }
1029 const Formattable& amtNumber = measure.getNumber();
1030 const MeasureUnit& amtUnit = measure.getUnit();
1031 if (isCurrency(amtUnit)) {
1032 UChar isoCode[4];
1033 u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
3d1f044b 1034 return cache->getCurrencyFormat(fWidth)->format(
57a6839d
A
1035 new CurrencyAmount(amtNumber, isoCode, status),
1036 appendTo,
1037 pos,
1038 status);
1039 }
3d1f044b 1040 int32_t cur = appendTo.length();
2ca993e8
A
1041 UBool posForFullNumericPart = (pos.getField() == UAMEASFMT_NUMERIC_FIELD_FLAG);
1042 if (posForFullNumericPart) {
1043 pos.setField(FieldPosition::DONT_CARE);
1044 }
3d1f044b
A
1045
1046 auto* df = dynamic_cast<const DecimalFormat*>(&nf);
1047 if (df == nullptr) {
340931cb
A
1048 // Handle other types of NumberFormat using the ICU 63 code, modified to
1049 // get the unitPattern from LongNameHandler and handle fallback to OTHER.
3d1f044b
A
1050 UnicodeString formattedNumber;
1051 StandardPlural::Form pluralForm = QuantityFormatter::selectPlural(
1052 amtNumber, nf, **pluralRules, formattedNumber, pos, status);
1053 if (posForFullNumericPart) {
1054 pos.setField(UAMEASFMT_NUMERIC_FIELD_FLAG);
1055 pos.setBeginIndex(0);
1056 pos.setEndIndex(formattedNumber.length());
1057 }
1058 UnicodeString pattern = number::impl::LongNameHandler::getUnitPattern(getLocale(status),
1059 amtUnit, getUnitWidth(fWidth), pluralForm, status);
340931cb 1060 // The above handles fallback from other widths to short, and from other plural forms to OTHER
3d1f044b
A
1061 if (U_FAILURE(status)) {
1062 return appendTo;
1063 }
1064 SimpleFormatter formatter(pattern, 0, 1, status);
1065 QuantityFormatter::format(formatter, formattedNumber, appendTo, pos, status);
1066 } else {
1067 // This is the current code
1068 number::FormattedNumber result;
1069 if (auto* lnf = df->toNumberFormatter(status)) {
1070 result = lnf->unit(amtUnit)
1071 .unitWidth(getUnitWidth(fWidth))
1072 .formatDouble(amtNumber.getDouble(status), status);
1073 }
1074 DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
1075 if (posForFullNumericPart) {
1076 pos.setField(UNUM_INTEGER_FIELD);
1077 DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
1078 int32_t intBegin = pos.getBeginIndex();
1079 int32_t intEnd = pos.getEndIndex();
1080 pos.setField(UNUM_FRACTION_FIELD);
1081 DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
1082 int32_t fracBegin = pos.getBeginIndex();
1083 int32_t fracEnd = pos.getEndIndex();
1084 if (intBegin >= 0 && intEnd > intBegin) {
1085 // we have an integer part
1086 pos.setBeginIndex(intBegin);
1087 if (fracBegin >= intEnd && fracEnd > fracBegin) {
1088 // we have a fraction part, include it too
1089 pos.setEndIndex(fracEnd);
1090 } else {
1091 pos.setEndIndex(intEnd);
1092 }
1093 } else if (fracBegin >= 0 && fracEnd > fracBegin) {
1094 // only a fract part, use it
1095 pos.setBeginIndex(fracBegin);
1096 pos.setEndIndex(fracEnd);
1097 } else {
1098 // no numeric part
1099 pos.setBeginIndex(0);
1100 pos.setEndIndex(0);
1101 }
1102 pos.setField(UAMEASFMT_NUMERIC_FIELD_FLAG);
1103 }
1104 appendTo.append(result.toTempString(status));
2ca993e8 1105 }
3d1f044b 1106
2ca993e8 1107 if (stripPatternSpaces) {
3d1f044b
A
1108 // Get the narrow pattern for OTHER.
1109 // If there are spaces in that, then do not continue to strip spaces
1110 // (i.e. even in the narrowest form this locale keeps spaces).
1111 UnicodeString narrowPattern = number::impl::LongNameHandler::getUnitPattern(getLocale(status),
1112 amtUnit, UNUM_UNIT_WIDTH_NARROW, StandardPlural::Form::OTHER, status);
2ca993e8 1113 if (U_SUCCESS(status)) {
3d1f044b 1114 if (narrowPattern.indexOf((UChar)0x0020) == -1 && narrowPattern.indexOf((UChar)0x00A0) == -1) {
2ca993e8
A
1115 int32_t end = appendTo.length();
1116 for (; cur < end; cur++) {
1117 if (appendTo.charAt(cur) == 0x0020) {
1118 appendTo.remove(cur, 1);
1119 if (pos.getBeginIndex() > cur) {
1120 pos.setBeginIndex(pos.getBeginIndex() - 1);
1121 pos.setEndIndex(pos.getEndIndex() - 1);
1122 }
1123 }
1124 }
1125 }
1126 }
57a6839d 1127 }
2ca993e8 1128 return appendTo;
57a6839d
A
1129}
1130
340931cb
A
1131
1132// Formats numeric time duration as 5:00:47 or 3:54.
57a6839d
A
1133UnicodeString &MeasureFormat::formatNumeric(
1134 const Formattable *hms, // always length 3
340931cb 1135 int32_t bitMap, // 1=hour set, 2=minute set, 4=second set
57a6839d
A
1136 UnicodeString &appendTo,
1137 UErrorCode &status) const {
1138 if (U_FAILURE(status)) {
1139 return appendTo;
1140 }
340931cb
A
1141
1142 UnicodeString pattern;
1143
1144 double hours = hms[0].getDouble(status);
1145 double minutes = hms[1].getDouble(status);
1146 double seconds = hms[2].getDouble(status);
1147 if (U_FAILURE(status)) {
57a6839d 1148 return appendTo;
57a6839d 1149 }
57a6839d 1150
340931cb
A
1151 // All possible combinations: "h", "m", "s", "hm", "hs", "ms", "hms"
1152 if (bitMap == 5 || bitMap == 7) { // "hms" & "hs" (we add minutes if "hs")
1153 pattern = cache->getNumericDateFormatters()->hourMinuteSecond;
1154 hours = uprv_trunc(hours);
1155 minutes = uprv_trunc(minutes);
1156 } else if (bitMap == 3) { // "hm"
1157 pattern = cache->getNumericDateFormatters()->hourMinute;
1158 hours = uprv_trunc(hours);
1159 } else if (bitMap == 6) { // "ms"
1160 pattern = cache->getNumericDateFormatters()->minuteSecond;
1161 minutes = uprv_trunc(minutes);
1162 } else { // h m s, handled outside formatNumeric. No value is also an error.
1163 status = U_INTERNAL_PROGRAM_ERROR;
1164 return appendTo;
1165 }
57a6839d 1166
340931cb
A
1167 const DecimalFormat *numberFormatter = dynamic_cast<const DecimalFormat*>(numberFormat->get());
1168 if (!numberFormatter) {
1169 status = U_INTERNAL_PROGRAM_ERROR;
1170 return appendTo;
1171 }
1172 number::LocalizedNumberFormatter numberFormatter2;
1173 if (auto* lnf = numberFormatter->toNumberFormatter(status)) {
1174 numberFormatter2 = lnf->integerWidth(number::IntegerWidth::zeroFillTo(2));
1175 } else {
57a6839d
A
1176 return appendTo;
1177 }
340931cb
A
1178 LocalPointer<DecimalFormat> intFmtClone;
1179 const DecimalFormat *intFmt = dynamic_cast<const DecimalFormat*>(cache->getIntegerFormat());
1180 if (intFmt) {
1181 intFmtClone.adoptInstead((DecimalFormat *)intFmt->clone());
1182 }
1183 if (intFmtClone.isNull()) {
57a6839d
A
1184 status = U_INTERNAL_PROGRAM_ERROR;
1185 return appendTo;
1186 }
1187
340931cb
A
1188 FormattedStringBuilder fsb;
1189
1190 UBool protect = FALSE;
1191 const int32_t patternLength = pattern.length();
1192 for (int32_t i = 0; i < patternLength; i++) {
1193 char16_t c = pattern[i];
1194
1195 // Also set the proper field in this switch
1196 // We don't use DateFormat.Field because this is not a date / time, is a duration.
1197 double value = 0;
1198 switch (c) {
1199 case u'H': value = hours; break;
1200 case u'm': value = minutes; break;
1201 case u's': value = seconds; break;
2ca993e8 1202 }
340931cb
A
1203
1204 // For undefined field we use UNUM_FIELD_COUNT, for historical reasons.
1205 // See cleanup bug: https://unicode-org.atlassian.net/browse/ICU-20665
1206 // But we give it a clear name, to keep "the ugly part" in one place.
1207 constexpr UNumberFormatFields undefinedField = UNUM_FIELD_COUNT;
1208
1209 // There is not enough info to add Field(s) for the unit because all we have are plain
1210 // text patterns. For example in "21:51" there is no text for something like "hour",
1211 // while in something like "21h51" there is ("h"). But we can't really tell...
1212 switch (c) {
1213 case u'H':
1214 case u'm':
1215 case u's':
1216 if (protect) {
1217 fsb.appendChar16(c, undefinedField, status);
1218 } else {
1219 UnicodeString tmp;
1220 UBool lastNumField = ((c == u's') || (c == u'm' && bitMap == 3));
1221 if ((i + 1 < patternLength) && pattern[i + 1] == c) { // doubled
1222 if (!lastNumField) {
1223 intFmtClone->setMinimumIntegerDigits(2);
1224 intFmtClone->format(value, tmp, status);
1225 } else {
1226 tmp = numberFormatter2.formatDouble(value, status).toString(status);
1227 }
1228 i++;
1229 } else {
1230 if (!lastNumField) {
1231 intFmtClone->setMinimumIntegerDigits(1);
1232 intFmtClone->format(value, tmp, status);
1233 } else {
1234 numberFormatter->format(value, tmp, status);
1235 }
1236 }
1237 // TODO: Use proper Field
1238 fsb.append(tmp, undefinedField, status);
1239 }
1240 break;
1241 case u'\'':
1242 // '' is escaped apostrophe
1243 if ((i + 1 < patternLength) && pattern[i + 1] == c) {
1244 fsb.appendChar16(c, undefinedField, status);
1245 i++;
1246 } else {
1247 protect = !protect;
1248 }
1249 break;
1250 default:
1251 fsb.appendChar16(c, undefinedField, status);
2ca993e8
A
1252 }
1253 }
57a6839d 1254
340931cb
A
1255 appendTo.append(fsb.toTempUnicodeString());
1256
57a6839d
A
1257 return appendTo;
1258}
1259
57a6839d
A
1260UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
1261 const Measure *measures,
1262 int32_t measureCount,
1263 UnicodeString& appendTo,
1264 FieldPosition& pos,
1265 UErrorCode& status) const {
1266 if (U_FAILURE(status)) {
1267 return appendTo;
1268 }
1269 FieldPosition dontCare(FieldPosition::DONT_CARE);
1270 FieldPosition fpos(pos.getField());
3d1f044b 1271 LocalArray<UnicodeString> results(new UnicodeString[measureCount], status);
57a6839d
A
1272 int32_t fieldPositionFoundIndex = -1;
1273 for (int32_t i = 0; i < measureCount; ++i) {
1274 const NumberFormat *nf = cache->getIntegerFormat();
1275 if (i == measureCount - 1) {
1276 nf = numberFormat->get();
1277 }
1278 if (fieldPositionFoundIndex == -1) {
1279 formatMeasure(measures[i], *nf, results[i], fpos, status);
1280 if (U_FAILURE(status)) {
57a6839d
A
1281 return appendTo;
1282 }
1283 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
1284 fieldPositionFoundIndex = i;
1285 }
1286 } else {
1287 formatMeasure(measures[i], *nf, results[i], dontCare, status);
1288 }
1289 }
1290 int32_t offset;
1291 listFormatter->format(
3d1f044b 1292 results.getAlias(),
57a6839d
A
1293 measureCount,
1294 appendTo,
1295 fieldPositionFoundIndex,
1296 offset,
1297 status);
1298 if (U_FAILURE(status)) {
57a6839d
A
1299 return appendTo;
1300 }
3d1f044b 1301 // Fix up FieldPosition indexes if our field is found.
57a6839d
A
1302 if (offset != -1) {
1303 pos.setBeginIndex(fpos.getBeginIndex() + offset);
1304 pos.setEndIndex(fpos.getEndIndex() + offset);
1305 }
57a6839d
A
1306 return appendTo;
1307}
4388f060 1308
374ca955
A
1309MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
1310 UErrorCode& ec) {
3d1f044b
A
1311 if (U_FAILURE(ec)) {
1312 return nullptr;
374ca955 1313 }
3d1f044b
A
1314 LocalPointer<CurrencyFormat> fmt(new CurrencyFormat(locale, ec), ec);
1315 return fmt.orphan();
374ca955
A
1316}
1317
1318MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
1319 if (U_FAILURE(ec)) {
3d1f044b 1320 return nullptr;
374ca955
A
1321 }
1322 return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
1323}
1324
1325U_NAMESPACE_END
1326
1327#endif /* #if !UCONFIG_NO_FORMATTING */