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

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

Issue 845603002: Update ICU to 54.1 step 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/icu.git@master
Patch Set: remove unusued directories Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « source/i18n/locdspnm.cpp ('k') | source/i18n/measunit.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 ********************************************************************** 2 **********************************************************************
3 * Copyright (c) 2004-2011, International Business Machines 3 * Copyright (c) 2004-2014, International Business Machines
4 * Corporation and others. All Rights Reserved. 4 * Corporation and others. All Rights Reserved.
5 ********************************************************************** 5 **********************************************************************
6 * Author: Alan Liu 6 * Author: Alan Liu
7 * Created: April 20, 2004 7 * Created: April 20, 2004
8 * Since: ICU 3.0 8 * Since: ICU 3.0
9 ********************************************************************** 9 **********************************************************************
10 */ 10 */
11 #include "utypeinfo.h" // for 'typeid' to work
11 #include "unicode/utypes.h" 12 #include "unicode/utypes.h"
12 13
13 #if !UCONFIG_NO_FORMATTING 14 #if !UCONFIG_NO_FORMATTING
14 15
15 #include "unicode/measfmt.h" 16 #include "unicode/measfmt.h"
17 #include "unicode/numfmt.h"
16 #include "currfmt.h" 18 #include "currfmt.h"
19 #include "unicode/localpointer.h"
20 #include "simplepatternformatter.h"
21 #include "quantityformatter.h"
22 #include "unicode/plurrule.h"
23 #include "unicode/decimfmt.h"
24 #include "uresimp.h"
25 #include "unicode/ures.h"
26 #include "ureslocs.h"
27 #include "cstring.h"
28 #include "mutex.h"
29 #include "ucln_in.h"
30 #include "unicode/listformatter.h"
31 #include "charstr.h"
32 #include "unicode/putil.h"
33 #include "unicode/smpdtfmt.h"
34 #include "uassert.h"
35
36 #include "sharednumberformat.h"
37 #include "sharedpluralrules.h"
38 #include "unifiedcache.h"
39
40 #define MEAS_UNIT_COUNT 121
41 #define WIDTH_INDEX_COUNT (UMEASFMT_WIDTH_NARROW + 1)
17 42
18 U_NAMESPACE_BEGIN 43 U_NAMESPACE_BEGIN
19 44
20 MeasureFormat::MeasureFormat() {} 45 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
21 46
22 MeasureFormat::~MeasureFormat() {} 47 // Used to format durations like 5:47 or 21:35:42.
48 class NumericDateFormatters : public UMemory {
49 public:
50 // Formats like H:mm
51 SimpleDateFormat hourMinute;
52
53 // formats like M:ss
54 SimpleDateFormat minuteSecond;
55
56 // formats like H:mm:ss
57 SimpleDateFormat hourMinuteSecond;
58
59 // Constructor that takes the actual patterns for hour-minute,
60 // minute-second, and hour-minute-second respectively.
61 NumericDateFormatters(
62 const UnicodeString &hm,
63 const UnicodeString &ms,
64 const UnicodeString &hms,
65 UErrorCode &status) :
66 hourMinute(hm, status),
67 minuteSecond(ms, status),
68 hourMinuteSecond(hms, status) {
69 const TimeZone *gmt = TimeZone::getGMT();
70 hourMinute.setTimeZone(*gmt);
71 minuteSecond.setTimeZone(*gmt);
72 hourMinuteSecond.setTimeZone(*gmt);
73 }
74 private:
75 NumericDateFormatters(const NumericDateFormatters &other);
76 NumericDateFormatters &operator=(const NumericDateFormatters &other);
77 };
78
79 // Instances contain all MeasureFormat specific data for a particular locale.
80 // This data is cached. It is never copied, but is shared via shared pointers.
81 class MeasureFormatCacheData : public SharedObject {
82 public:
83 QuantityFormatter formatters[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT];
84 SimplePatternFormatter perFormatters[WIDTH_INDEX_COUNT];
85
86 MeasureFormatCacheData();
87 void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) {
88 delete currencyFormats[widthIndex];
89 currencyFormats[widthIndex] = nfToAdopt;
90 }
91 const NumberFormat *getCurrencyFormat(int32_t widthIndex) const {
92 return currencyFormats[widthIndex];
93 }
94 void adoptIntegerFormat(NumberFormat *nfToAdopt) {
95 delete integerFormat;
96 integerFormat = nfToAdopt;
97 }
98 const NumberFormat *getIntegerFormat() const {
99 return integerFormat;
100 }
101 void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) {
102 delete numericDateFormatters;
103 numericDateFormatters = formattersToAdopt;
104 }
105 const NumericDateFormatters *getNumericDateFormatters() const {
106 return numericDateFormatters;
107 }
108 void adoptPerUnitFormatter(
109 int32_t index,
110 int32_t widthIndex,
111 SimplePatternFormatter *formatterToAdopt) {
112 delete perUnitFormatters[index][widthIndex];
113 perUnitFormatters[index][widthIndex] = formatterToAdopt;
114 }
115 const SimplePatternFormatter * const * getPerUnitFormattersByIndex(
116 int32_t index) const {
117 return perUnitFormatters[index];
118 }
119 virtual ~MeasureFormatCacheData();
120 private:
121 NumberFormat *currencyFormats[WIDTH_INDEX_COUNT];
122 NumberFormat *integerFormat;
123 NumericDateFormatters *numericDateFormatters;
124 SimplePatternFormatter *perUnitFormatters[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT ];
125 MeasureFormatCacheData(const MeasureFormatCacheData &other);
126 MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
127 };
128
129 MeasureFormatCacheData::MeasureFormatCacheData() {
130 for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
131 currencyFormats[i] = NULL;
132 }
133 for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) {
134 for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) {
135 perUnitFormatters[i][j] = NULL;
136 }
137 }
138 integerFormat = NULL;
139 numericDateFormatters = NULL;
140 }
141
142 MeasureFormatCacheData::~MeasureFormatCacheData() {
143 for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
144 delete currencyFormats[i];
145 }
146 for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) {
147 for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) {
148 delete perUnitFormatters[i][j];
149 }
150 }
151 delete integerFormat;
152 delete numericDateFormatters;
153 }
154
155 static int32_t widthToIndex(UMeasureFormatWidth width) {
156 if (width >= WIDTH_INDEX_COUNT) {
157 return WIDTH_INDEX_COUNT - 1;
158 }
159 return width;
160 }
161
162 static UBool isCurrency(const MeasureUnit &unit) {
163 return (uprv_strcmp(unit.getType(), "currency") == 0);
164 }
165
166 static UBool getString(
167 const UResourceBundle *resource,
168 UnicodeString &result,
169 UErrorCode &status) {
170 int32_t len = 0;
171 const UChar *resStr = ures_getString(resource, &len, &status);
172 if (U_FAILURE(status)) {
173 return FALSE;
174 }
175 result.setTo(TRUE, resStr, len);
176 return TRUE;
177 }
178
179
180 static UBool loadMeasureUnitData(
181 const UResourceBundle *resource,
182 MeasureFormatCacheData &cacheData,
183 UErrorCode &status) {
184 if (U_FAILURE(status)) {
185 return FALSE;
186 }
187 static const char *widthPath[] = {"units", "unitsShort", "unitsNarrow"};
188 MeasureUnit *units = NULL;
189 int32_t unitCount = MeasureUnit::getAvailable(units, 0, status);
190 while (status == U_BUFFER_OVERFLOW_ERROR) {
191 status = U_ZERO_ERROR;
192 delete [] units;
193 units = new MeasureUnit[unitCount];
194 if (units == NULL) {
195 status = U_MEMORY_ALLOCATION_ERROR;
196 return FALSE;
197 }
198 unitCount = MeasureUnit::getAvailable(units, unitCount, status);
199 }
200 for (int32_t currentWidth = 0; currentWidth < WIDTH_INDEX_COUNT; ++currentWi dth) {
201 // Be sure status is clear since next resource bundle lookup may fail.
202 if (U_FAILURE(status)) {
203 delete [] units;
204 return FALSE;
205 }
206 LocalUResourceBundlePointer widthBundle(
207 ures_getByKeyWithFallback(
208 resource, widthPath[currentWidth], NULL, &status));
209 // We may not have data for all widths in all locales.
210 if (status == U_MISSING_RESOURCE_ERROR) {
211 status = U_ZERO_ERROR;
212 continue;
213 }
214 {
215 // compound per
216 LocalUResourceBundlePointer compoundPerBundle(
217 ures_getByKeyWithFallback(
218 widthBundle.getAlias(),
219 "compound/per",
220 NULL,
221 &status));
222 if (U_FAILURE(status)) {
223 status = U_ZERO_ERROR;
224 } else {
225 UnicodeString perPattern;
226 getString(compoundPerBundle.getAlias(), perPattern, status);
227 cacheData.perFormatters[currentWidth].compile(perPattern, status );
228 }
229 }
230 for (int32_t currentUnit = 0; currentUnit < unitCount; ++currentUnit) {
231 // Be sure status is clear next lookup may fail.
232 if (U_FAILURE(status)) {
233 delete [] units;
234 return FALSE;
235 }
236 if (isCurrency(units[currentUnit])) {
237 continue;
238 }
239 CharString pathBuffer;
240 pathBuffer.append(units[currentUnit].getType(), status)
241 .append("/", status)
242 .append(units[currentUnit].getSubtype(), status);
243 LocalUResourceBundlePointer unitBundle(
244 ures_getByKeyWithFallback(
245 widthBundle.getAlias(),
246 pathBuffer.data(),
247 NULL,
248 &status));
249 // We may not have data for all units in all widths
250 if (status == U_MISSING_RESOURCE_ERROR) {
251 status = U_ZERO_ERROR;
252 continue;
253 }
254 // We must have the unit bundle to proceed
255 if (U_FAILURE(status)) {
256 delete [] units;
257 return FALSE;
258 }
259 int32_t size = ures_getSize(unitBundle.getAlias());
260 for (int32_t plIndex = 0; plIndex < size; ++plIndex) {
261 LocalUResourceBundlePointer pluralBundle(
262 ures_getByIndex(
263 unitBundle.getAlias(), plIndex, NULL, &status));
264 if (U_FAILURE(status)) {
265 delete [] units;
266 return FALSE;
267 }
268 const char * resKey = ures_getKey(pluralBundle.getAlias());
269 if (uprv_strcmp(resKey, "dnam") == 0) {
270 continue; // skip display name & per pattern (new in CLDR 26 / ICU 54) for now, not part of plurals
271 }
272 if (uprv_strcmp(resKey, "per") == 0) {
273 UnicodeString perPattern;
274 getString(pluralBundle.getAlias(), perPattern, status);
275 cacheData.adoptPerUnitFormatter(
276 units[currentUnit].getIndex(),
277 currentWidth,
278 new SimplePatternFormatter(perPattern));
279 continue;
280 }
281 UnicodeString rawPattern;
282 getString(pluralBundle.getAlias(), rawPattern, status);
283 cacheData.formatters[units[currentUnit].getIndex()][currentWidth ].add(
284 resKey,
285 rawPattern,
286 status);
287 }
288 }
289 }
290 delete [] units;
291 return U_SUCCESS(status);
292 }
293
294 static UnicodeString loadNumericDateFormatterPattern(
295 const UResourceBundle *resource,
296 const char *pattern,
297 UErrorCode &status) {
298 UnicodeString result;
299 if (U_FAILURE(status)) {
300 return result;
301 }
302 CharString chs;
303 chs.append("durationUnits", status)
304 .append("/", status).append(pattern, status);
305 LocalUResourceBundlePointer patternBundle(
306 ures_getByKeyWithFallback(
307 resource,
308 chs.data(),
309 NULL,
310 &status));
311 if (U_FAILURE(status)) {
312 return result;
313 }
314 getString(patternBundle.getAlias(), result, status);
315 // Replace 'h' with 'H'
316 int32_t len = result.length();
317 UChar *buffer = result.getBuffer(len);
318 for (int32_t i = 0; i < len; ++i) {
319 if (buffer[i] == 0x68) { // 'h'
320 buffer[i] = 0x48; // 'H'
321 }
322 }
323 result.releaseBuffer(len);
324 return result;
325 }
326
327 static NumericDateFormatters *loadNumericDateFormatters(
328 const UResourceBundle *resource,
329 UErrorCode &status) {
330 if (U_FAILURE(status)) {
331 return NULL;
332 }
333 NumericDateFormatters *result = new NumericDateFormatters(
334 loadNumericDateFormatterPattern(resource, "hm", status),
335 loadNumericDateFormatterPattern(resource, "ms", status),
336 loadNumericDateFormatterPattern(resource, "hms", status),
337 status);
338 if (U_FAILURE(status)) {
339 delete result;
340 return NULL;
341 }
342 return result;
343 }
344
345 template<> U_I18N_API
346 const MeasureFormatCacheData *LocaleCacheKey<MeasureFormatCacheData>::createObje ct(
347 const void * /*unused*/, UErrorCode &status) const {
348 const char *localeId = fLoc.getName();
349 LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status));
350 LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, localeId, &status));
351 static UNumberFormatStyle currencyStyles[] = {
352 UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY};
353 if (U_FAILURE(status)) {
354 return NULL;
355 }
356 LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData());
357 if (result.isNull()) {
358 status = U_MEMORY_ALLOCATION_ERROR;
359 return NULL;
360 }
361 if (!loadMeasureUnitData(
362 unitsBundle.getAlias(),
363 *result,
364 status)) {
365 return NULL;
366 }
367 result->adoptNumericDateFormatters(loadNumericDateFormatters(
368 topLevel.getAlias(), status));
369 if (U_FAILURE(status)) {
370 return NULL;
371 }
372
373 for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
374 result->adoptCurrencyFormat(i, NumberFormat::createInstance(
375 localeId, currencyStyles[i], status));
376 if (U_FAILURE(status)) {
377 return NULL;
378 }
379 }
380 NumberFormat *inf = NumberFormat::createInstance(
381 localeId, UNUM_DECIMAL, status);
382 if (U_FAILURE(status)) {
383 return NULL;
384 }
385 inf->setMaximumFractionDigits(0);
386 DecimalFormat *decfmt = dynamic_cast<DecimalFormat *>(inf);
387 if (decfmt != NULL) {
388 decfmt->setRoundingMode(DecimalFormat::kRoundDown);
389 }
390 result->adoptIntegerFormat(inf);
391 result->addRef();
392 return result.orphan();
393 }
394
395 static UBool isTimeUnit(const MeasureUnit &mu, const char *tu) {
396 return uprv_strcmp(mu.getType(), "duration") == 0 &&
397 uprv_strcmp(mu.getSubtype(), tu) == 0;
398 }
399
400 // Converts a composite measure into hours-minutes-seconds and stores at hms
401 // array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
402 // units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
403 // contains hours-minutes, this function would return 3.
404 //
405 // If measures cannot be converted into hours, minutes, seconds or if amounts
406 // are negative, or if hours, minutes, seconds are out of order, returns 0.
407 static int32_t toHMS(
408 const Measure *measures,
409 int32_t measureCount,
410 Formattable *hms,
411 UErrorCode &status) {
412 if (U_FAILURE(status)) {
413 return 0;
414 }
415 int32_t result = 0;
416 if (U_FAILURE(status)) {
417 return 0;
418 }
419 // We use copy constructor to ensure that both sides of equality operator
420 // are instances of MeasureUnit base class and not a subclass. Otherwise,
421 // operator== will immediately return false.
422 for (int32_t i = 0; i < measureCount; ++i) {
423 if (isTimeUnit(measures[i].getUnit(), "hour")) {
424 // hour must come first
425 if (result >= 1) {
426 return 0;
427 }
428 hms[0] = measures[i].getNumber();
429 if (hms[0].getDouble() < 0.0) {
430 return 0;
431 }
432 result |= 1;
433 } else if (isTimeUnit(measures[i].getUnit(), "minute")) {
434 // minute must come after hour
435 if (result >= 2) {
436 return 0;
437 }
438 hms[1] = measures[i].getNumber();
439 if (hms[1].getDouble() < 0.0) {
440 return 0;
441 }
442 result |= 2;
443 } else if (isTimeUnit(measures[i].getUnit(), "second")) {
444 // second must come after hour and minute
445 if (result >= 4) {
446 return 0;
447 }
448 hms[2] = measures[i].getNumber();
449 if (hms[2].getDouble() < 0.0) {
450 return 0;
451 }
452 result |= 4;
453 } else {
454 return 0;
455 }
456 }
457 return result;
458 }
459
460
461 MeasureFormat::MeasureFormat(
462 const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
463 : cache(NULL),
464 numberFormat(NULL),
465 pluralRules(NULL),
466 width(w),
467 listFormatter(NULL) {
468 initMeasureFormat(locale, w, NULL, status);
469 }
470
471 MeasureFormat::MeasureFormat(
472 const Locale &locale,
473 UMeasureFormatWidth w,
474 NumberFormat *nfToAdopt,
475 UErrorCode &status)
476 : cache(NULL),
477 numberFormat(NULL),
478 pluralRules(NULL),
479 width(w),
480 listFormatter(NULL) {
481 initMeasureFormat(locale, w, nfToAdopt, status);
482 }
483
484 MeasureFormat::MeasureFormat(const MeasureFormat &other) :
485 Format(other),
486 cache(other.cache),
487 numberFormat(other.numberFormat),
488 pluralRules(other.pluralRules),
489 width(other.width),
490 listFormatter(NULL) {
491 cache->addRef();
492 numberFormat->addRef();
493 pluralRules->addRef();
494 listFormatter = new ListFormatter(*other.listFormatter);
495 }
496
497 MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
498 if (this == &other) {
499 return *this;
500 }
501 Format::operator=(other);
502 SharedObject::copyPtr(other.cache, cache);
503 SharedObject::copyPtr(other.numberFormat, numberFormat);
504 SharedObject::copyPtr(other.pluralRules, pluralRules);
505 width = other.width;
506 delete listFormatter;
507 listFormatter = new ListFormatter(*other.listFormatter);
508 return *this;
509 }
510
511 MeasureFormat::MeasureFormat() :
512 cache(NULL),
513 numberFormat(NULL),
514 pluralRules(NULL),
515 width(UMEASFMT_WIDTH_WIDE),
516 listFormatter(NULL) {
517 }
518
519 MeasureFormat::~MeasureFormat() {
520 if (cache != NULL) {
521 cache->removeRef();
522 }
523 if (numberFormat != NULL) {
524 numberFormat->removeRef();
525 }
526 if (pluralRules != NULL) {
527 pluralRules->removeRef();
528 }
529 delete listFormatter;
530 }
531
532 UBool MeasureFormat::operator==(const Format &other) const {
533 if (this == &other) { // Same object, equal
534 return TRUE;
535 }
536 if (!Format::operator==(other)) {
537 return FALSE;
538 }
539 const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other);
540
541 // Note: Since the ListFormatter depends only on Locale and width, we
542 // don't have to check it here.
543
544 // differing widths aren't equivalent
545 if (width != rhs.width) {
546 return FALSE;
547 }
548 // Width the same check locales.
549 // We don't need to check locales if both objects have same cache.
550 if (cache != rhs.cache) {
551 UErrorCode status = U_ZERO_ERROR;
552 const char *localeId = getLocaleID(status);
553 const char *rhsLocaleId = rhs.getLocaleID(status);
554 if (U_FAILURE(status)) {
555 // On failure, assume not equal
556 return FALSE;
557 }
558 if (uprv_strcmp(localeId, rhsLocaleId) != 0) {
559 return FALSE;
560 }
561 }
562 // Locales same, check NumberFormat if shared data differs.
563 return (
564 numberFormat == rhs.numberFormat ||
565 **numberFormat == **rhs.numberFormat);
566 }
567
568 Format *MeasureFormat::clone() const {
569 return new MeasureFormat(*this);
570 }
571
572 UnicodeString &MeasureFormat::format(
573 const Formattable &obj,
574 UnicodeString &appendTo,
575 FieldPosition &pos,
576 UErrorCode &status) const {
577 if (U_FAILURE(status)) return appendTo;
578 if (obj.getType() == Formattable::kObject) {
579 const UObject* formatObj = obj.getObject();
580 const Measure* amount = dynamic_cast<const Measure*>(formatObj);
581 if (amount != NULL) {
582 return formatMeasure(
583 *amount, **numberFormat, appendTo, pos, status);
584 }
585 }
586 status = U_ILLEGAL_ARGUMENT_ERROR;
587 return appendTo;
588 }
589
590 void MeasureFormat::parseObject(
591 const UnicodeString & /*source*/,
592 Formattable & /*result*/,
593 ParsePosition& /*pos*/) const {
594 return;
595 }
596
597 UnicodeString &MeasureFormat::formatMeasuresPer(
598 const Measure *measures,
599 int32_t measureCount,
600 const MeasureUnit &perUnit,
601 UnicodeString &appendTo,
602 FieldPosition &pos,
603 UErrorCode &status) const {
604 FieldPosition fpos(pos.getField());
605 UnicodeString measuresString;
606 int32_t offset = withPerUnit(
607 formatMeasures(
608 measures, measureCount, measuresString, fpos, status),
609 perUnit,
610 appendTo,
611 status);
612 if (U_FAILURE(status)) {
613 return appendTo;
614 }
615 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
616 pos.setBeginIndex(fpos.getBeginIndex() + offset);
617 pos.setEndIndex(fpos.getEndIndex() + offset);
618 }
619 return appendTo;
620 }
621
622 UnicodeString &MeasureFormat::formatMeasures(
623 const Measure *measures,
624 int32_t measureCount,
625 UnicodeString &appendTo,
626 FieldPosition &pos,
627 UErrorCode &status) const {
628 if (U_FAILURE(status)) {
629 return appendTo;
630 }
631 if (measureCount == 0) {
632 return appendTo;
633 }
634 if (measureCount == 1) {
635 return formatMeasure(measures[0], **numberFormat, appendTo, pos, status) ;
636 }
637 if (width == UMEASFMT_WIDTH_NUMERIC) {
638 Formattable hms[3];
639 int32_t bitMap = toHMS(measures, measureCount, hms, status);
640 if (bitMap > 0) {
641 return formatNumeric(hms, bitMap, appendTo, status);
642 }
643 }
644 if (pos.getField() != FieldPosition::DONT_CARE) {
645 return formatMeasuresSlowTrack(
646 measures, measureCount, appendTo, pos, status);
647 }
648 UnicodeString *results = new UnicodeString[measureCount];
649 if (results == NULL) {
650 status = U_MEMORY_ALLOCATION_ERROR;
651 return appendTo;
652 }
653 for (int32_t i = 0; i < measureCount; ++i) {
654 const NumberFormat *nf = cache->getIntegerFormat();
655 if (i == measureCount - 1) {
656 nf = numberFormat->get();
657 }
658 formatMeasure(
659 measures[i],
660 *nf,
661 results[i],
662 pos,
663 status);
664 }
665 listFormatter->format(results, measureCount, appendTo, status);
666 delete [] results;
667 return appendTo;
668 }
669
670 void MeasureFormat::initMeasureFormat(
671 const Locale &locale,
672 UMeasureFormatWidth w,
673 NumberFormat *nfToAdopt,
674 UErrorCode &status) {
675 static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
676 LocalPointer<NumberFormat> nf(nfToAdopt);
677 if (U_FAILURE(status)) {
678 return;
679 }
680 const char *name = locale.getName();
681 setLocaleIDs(name, name);
682
683 UnifiedCache::getByLocale(locale, cache, status);
684 if (U_FAILURE(status)) {
685 return;
686 }
687
688 const SharedPluralRules *pr = PluralRules::createSharedInstance(
689 locale, UPLURAL_TYPE_CARDINAL, status);
690 if (U_FAILURE(status)) {
691 return;
692 }
693 SharedObject::copyPtr(pr, pluralRules);
694 pr->removeRef();
695 if (nf.isNull()) {
696 const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
697 locale, UNUM_DECIMAL, status);
698 if (U_FAILURE(status)) {
699 return;
700 }
701 SharedObject::copyPtr(shared, numberFormat);
702 shared->removeRef();
703 } else {
704 adoptNumberFormat(nf.orphan(), status);
705 if (U_FAILURE(status)) {
706 return;
707 }
708 }
709 width = w;
710 delete listFormatter;
711 listFormatter = ListFormatter::createInstance(
712 locale,
713 listStyles[widthToIndex(width)],
714 status);
715 }
716
717 void MeasureFormat::adoptNumberFormat(
718 NumberFormat *nfToAdopt, UErrorCode &status) {
719 LocalPointer<NumberFormat> nf(nfToAdopt);
720 if (U_FAILURE(status)) {
721 return;
722 }
723 SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
724 if (shared == NULL) {
725 status = U_MEMORY_ALLOCATION_ERROR;
726 return;
727 }
728 nf.orphan();
729 SharedObject::copyPtr(shared, numberFormat);
730 }
731
732 UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &st atus) {
733 if (U_FAILURE(status) || locale == getLocale(status)) {
734 return FALSE;
735 }
736 initMeasureFormat(locale, width, NULL, status);
737 return U_SUCCESS(status);
738 }
739
740 const NumberFormat &MeasureFormat::getNumberFormat() const {
741 return **numberFormat;
742 }
743
744 const PluralRules &MeasureFormat::getPluralRules() const {
745 return **pluralRules;
746 }
747
748 Locale MeasureFormat::getLocale(UErrorCode &status) const {
749 return Format::getLocale(ULOC_VALID_LOCALE, status);
750 }
751
752 const char *MeasureFormat::getLocaleID(UErrorCode &status) const {
753 return Format::getLocaleID(ULOC_VALID_LOCALE, status);
754 }
755
756 UnicodeString &MeasureFormat::formatMeasure(
757 const Measure &measure,
758 const NumberFormat &nf,
759 UnicodeString &appendTo,
760 FieldPosition &pos,
761 UErrorCode &status) const {
762 if (U_FAILURE(status)) {
763 return appendTo;
764 }
765 const Formattable& amtNumber = measure.getNumber();
766 const MeasureUnit& amtUnit = measure.getUnit();
767 if (isCurrency(amtUnit)) {
768 UChar isoCode[4];
769 u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
770 return cache->getCurrencyFormat(widthToIndex(width))->format(
771 new CurrencyAmount(amtNumber, isoCode, status),
772 appendTo,
773 pos,
774 status);
775 }
776 const QuantityFormatter *quantityFormatter = getQuantityFormatter(
777 amtUnit.getIndex(), widthToIndex(width), status);
778 if (U_FAILURE(status)) {
779 return appendTo;
780 }
781 return quantityFormatter->format(
782 amtNumber,
783 nf,
784 **pluralRules,
785 appendTo,
786 pos,
787 status);
788 }
789
790 // Formats hours-minutes-seconds as 5:37:23 or similar.
791 UnicodeString &MeasureFormat::formatNumeric(
792 const Formattable *hms, // always length 3
793 int32_t bitMap, // 1=hourset, 2=minuteset, 4=secondset
794 UnicodeString &appendTo,
795 UErrorCode &status) const {
796 if (U_FAILURE(status)) {
797 return appendTo;
798 }
799 UDate millis =
800 (UDate) (((uprv_trunc(hms[0].getDouble(status)) * 60.0
801 + uprv_trunc(hms[1].getDouble(status))) * 60.0
802 + uprv_trunc(hms[2].getDouble(status))) * 1000.0);
803 switch (bitMap) {
804 case 5: // hs
805 case 7: // hms
806 return formatNumeric(
807 millis,
808 cache->getNumericDateFormatters()->hourMinuteSecond,
809 UDAT_SECOND_FIELD,
810 hms[2],
811 appendTo,
812 status);
813 break;
814 case 6: // ms
815 return formatNumeric(
816 millis,
817 cache->getNumericDateFormatters()->minuteSecond,
818 UDAT_SECOND_FIELD,
819 hms[2],
820 appendTo,
821 status);
822 break;
823 case 3: // hm
824 return formatNumeric(
825 millis,
826 cache->getNumericDateFormatters()->hourMinute,
827 UDAT_MINUTE_FIELD,
828 hms[1],
829 appendTo,
830 status);
831 break;
832 default:
833 status = U_INTERNAL_PROGRAM_ERROR;
834 return appendTo;
835 break;
836 }
837 return appendTo;
838 }
839
840 static void appendRange(
841 const UnicodeString &src,
842 int32_t start,
843 int32_t end,
844 UnicodeString &dest) {
845 dest.append(src, start, end - start);
846 }
847
848 static void appendRange(
849 const UnicodeString &src,
850 int32_t end,
851 UnicodeString &dest) {
852 dest.append(src, end, src.length() - end);
853 }
854
855 // Formats time like 5:37:23
856 UnicodeString &MeasureFormat::formatNumeric(
857 UDate date, // Time since epoch 1:30:00 would be 5400000
858 const DateFormat &dateFmt, // h:mm, m:ss, or h:mm:ss
859 UDateFormatField smallestField, // seconds in 5:37:23.5
860 const Formattable &smallestAmount, // 23.5 for 5:37:23.5
861 UnicodeString &appendTo,
862 UErrorCode &status) const {
863 if (U_FAILURE(status)) {
864 return appendTo;
865 }
866 // Format the smallest amount with this object's NumberFormat
867 UnicodeString smallestAmountFormatted;
868
869 // We keep track of the integer part of smallest amount so that
870 // we can replace it later so that we get '0:00:09.3' instead of
871 // '0:00:9.3'
872 FieldPosition intFieldPosition(UNUM_INTEGER_FIELD);
873 (*numberFormat)->format(
874 smallestAmount, smallestAmountFormatted, intFieldPosition, status);
875 if (
876 intFieldPosition.getBeginIndex() == 0 &&
877 intFieldPosition.getEndIndex() == 0) {
878 status = U_INTERNAL_PROGRAM_ERROR;
879 return appendTo;
880 }
881
882 // Format time. draft becomes something like '5:30:45'
883 FieldPosition smallestFieldPosition(smallestField);
884 UnicodeString draft;
885 dateFmt.format(date, draft, smallestFieldPosition, status);
886
887 // If we find field for smallest amount replace it with the formatted
888 // smallest amount from above taking care to replace the integer part
889 // with what is in original time. For example, If smallest amount
890 // is 9.35s and the formatted time is 0:00:09 then 9.35 becomes 09.35
891 // and replacing yields 0:00:09.35
892 if (smallestFieldPosition.getBeginIndex() != 0 ||
893 smallestFieldPosition.getEndIndex() != 0) {
894 appendRange(draft, 0, smallestFieldPosition.getBeginIndex(), appendTo);
895 appendRange(
896 smallestAmountFormatted,
897 0,
898 intFieldPosition.getBeginIndex(),
899 appendTo);
900 appendRange(
901 draft,
902 smallestFieldPosition.getBeginIndex(),
903 smallestFieldPosition.getEndIndex(),
904 appendTo);
905 appendRange(
906 smallestAmountFormatted,
907 intFieldPosition.getEndIndex(),
908 appendTo);
909 appendRange(
910 draft,
911 smallestFieldPosition.getEndIndex(),
912 appendTo);
913 } else {
914 appendTo.append(draft);
915 }
916 return appendTo;
917 }
918
919 const QuantityFormatter *MeasureFormat::getQuantityFormatter(
920 int32_t index,
921 int32_t widthIndex,
922 UErrorCode &status) const {
923 if (U_FAILURE(status)) {
924 return NULL;
925 }
926 const QuantityFormatter *formatters =
927 cache->formatters[index];
928 if (formatters[widthIndex].isValid()) {
929 return &formatters[widthIndex];
930 }
931 if (formatters[UMEASFMT_WIDTH_SHORT].isValid()) {
932 return &formatters[UMEASFMT_WIDTH_SHORT];
933 }
934 if (formatters[UMEASFMT_WIDTH_WIDE].isValid()) {
935 return &formatters[UMEASFMT_WIDTH_WIDE];
936 }
937 status = U_MISSING_RESOURCE_ERROR;
938 return NULL;
939 }
940
941 const SimplePatternFormatter *MeasureFormat::getPerUnitFormatter(
942 int32_t index,
943 int32_t widthIndex) const {
944 const SimplePatternFormatter * const * perUnitFormatters =
945 cache->getPerUnitFormattersByIndex(index);
946 if (perUnitFormatters[widthIndex] != NULL) {
947 return perUnitFormatters[widthIndex];
948 }
949 if (perUnitFormatters[UMEASFMT_WIDTH_SHORT] != NULL) {
950 return perUnitFormatters[UMEASFMT_WIDTH_SHORT];
951 }
952 if (perUnitFormatters[UMEASFMT_WIDTH_WIDE] != NULL) {
953 return perUnitFormatters[UMEASFMT_WIDTH_WIDE];
954 }
955 return NULL;
956 }
957
958 const SimplePatternFormatter *MeasureFormat::getPerFormatter(
959 int32_t widthIndex,
960 UErrorCode &status) const {
961 if (U_FAILURE(status)) {
962 return NULL;
963 }
964 const SimplePatternFormatter * perFormatters = cache->perFormatters;
965
966 if (perFormatters[widthIndex].getPlaceholderCount() == 2) {
967 return &perFormatters[widthIndex];
968 }
969 if (perFormatters[UMEASFMT_WIDTH_SHORT].getPlaceholderCount() == 2) {
970 return &perFormatters[UMEASFMT_WIDTH_SHORT];
971 }
972 if (perFormatters[UMEASFMT_WIDTH_WIDE].getPlaceholderCount() == 2) {
973 return &perFormatters[UMEASFMT_WIDTH_WIDE];
974 }
975 status = U_MISSING_RESOURCE_ERROR;
976 return NULL;
977 }
978
979 static void getPerUnitString(
980 const QuantityFormatter &formatter,
981 UnicodeString &result) {
982 result = formatter.getByVariant("one")->getPatternWithNoPlaceholders();
983 result.trim();
984 }
985
986 int32_t MeasureFormat::withPerUnit(
987 const UnicodeString &formatted,
988 const MeasureUnit &perUnit,
989 UnicodeString &appendTo,
990 UErrorCode &status) const {
991 int32_t offset = -1;
992 if (U_FAILURE(status)) {
993 return offset;
994 }
995 const SimplePatternFormatter *perUnitFormatter = getPerUnitFormatter(
996 perUnit.getIndex(), widthToIndex(width));
997 if (perUnitFormatter != NULL) {
998 const UnicodeString *params[] = {&formatted};
999 perUnitFormatter->format(
1000 params,
1001 UPRV_LENGTHOF(params),
1002 appendTo,
1003 &offset,
1004 1,
1005 status);
1006 return offset;
1007 }
1008 const SimplePatternFormatter *perFormatter = getPerFormatter(
1009 widthToIndex(width), status);
1010 const QuantityFormatter *qf = getQuantityFormatter(
1011 perUnit.getIndex(), widthToIndex(width), status);
1012 if (U_FAILURE(status)) {
1013 return offset;
1014 }
1015 UnicodeString perUnitString;
1016 getPerUnitString(*qf, perUnitString);
1017 const UnicodeString *params[] = {&formatted, &perUnitString};
1018 perFormatter->format(
1019 params,
1020 UPRV_LENGTHOF(params),
1021 appendTo,
1022 &offset,
1023 1,
1024 status);
1025 return offset;
1026 }
1027
1028 UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
1029 const Measure *measures,
1030 int32_t measureCount,
1031 UnicodeString& appendTo,
1032 FieldPosition& pos,
1033 UErrorCode& status) const {
1034 if (U_FAILURE(status)) {
1035 return appendTo;
1036 }
1037 FieldPosition dontCare(FieldPosition::DONT_CARE);
1038 FieldPosition fpos(pos.getField());
1039 UnicodeString *results = new UnicodeString[measureCount];
1040 int32_t fieldPositionFoundIndex = -1;
1041 for (int32_t i = 0; i < measureCount; ++i) {
1042 const NumberFormat *nf = cache->getIntegerFormat();
1043 if (i == measureCount - 1) {
1044 nf = numberFormat->get();
1045 }
1046 if (fieldPositionFoundIndex == -1) {
1047 formatMeasure(measures[i], *nf, results[i], fpos, status);
1048 if (U_FAILURE(status)) {
1049 delete [] results;
1050 return appendTo;
1051 }
1052 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
1053 fieldPositionFoundIndex = i;
1054 }
1055 } else {
1056 formatMeasure(measures[i], *nf, results[i], dontCare, status);
1057 }
1058 }
1059 int32_t offset;
1060 listFormatter->format(
1061 results,
1062 measureCount,
1063 appendTo,
1064 fieldPositionFoundIndex,
1065 offset,
1066 status);
1067 if (U_FAILURE(status)) {
1068 delete [] results;
1069 return appendTo;
1070 }
1071 if (offset != -1) {
1072 pos.setBeginIndex(fpos.getBeginIndex() + offset);
1073 pos.setEndIndex(fpos.getEndIndex() + offset);
1074 }
1075 delete [] results;
1076 return appendTo;
1077 }
23 1078
24 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& local e, 1079 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& local e,
25 UErrorCode& ec) { 1080 UErrorCode& ec) {
26 CurrencyFormat* fmt = NULL; 1081 CurrencyFormat* fmt = NULL;
27 if (U_SUCCESS(ec)) { 1082 if (U_SUCCESS(ec)) {
28 fmt = new CurrencyFormat(locale, ec); 1083 fmt = new CurrencyFormat(locale, ec);
29 if (U_FAILURE(ec)) { 1084 if (U_FAILURE(ec)) {
30 delete fmt; 1085 delete fmt;
31 fmt = NULL; 1086 fmt = NULL;
32 } 1087 }
33 } 1088 }
34 return fmt; 1089 return fmt;
35 } 1090 }
36 1091
37 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) { 1092 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
38 if (U_FAILURE(ec)) { 1093 if (U_FAILURE(ec)) {
39 return NULL; 1094 return NULL;
40 } 1095 }
41 return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec); 1096 return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
42 } 1097 }
43 1098
44 U_NAMESPACE_END 1099 U_NAMESPACE_END
45 1100
46 #endif /* #if !UCONFIG_NO_FORMATTING */ 1101 #endif /* #if !UCONFIG_NO_FORMATTING */
OLDNEW
« no previous file with comments | « source/i18n/locdspnm.cpp ('k') | source/i18n/measunit.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698