Home | History | Annotate | Download | only in i18n
      1 /*
      2 **********************************************************************
      3 * Copyright (c) 2004-2016, International Business Machines
      4 * Corporation and others.  All Rights Reserved.
      5 **********************************************************************
      6 * Author: Alan Liu
      7 * Created: April 20, 2004
      8 * Since: ICU 3.0
      9 **********************************************************************
     10 */
     11 #include "utypeinfo.h"  // for 'typeid' to work
     12 #include "unicode/utypes.h"
     13 
     14 #if !UCONFIG_NO_FORMATTING
     15 
     16 #include "unicode/measfmt.h"
     17 #include "unicode/numfmt.h"
     18 #include "currfmt.h"
     19 #include "unicode/localpointer.h"
     20 #include "resource.h"
     21 #include "simplepatternformatter.h"
     22 #include "quantityformatter.h"
     23 #include "unicode/plurrule.h"
     24 #include "unicode/decimfmt.h"
     25 #include "uresimp.h"
     26 #include "unicode/ures.h"
     27 #include "ureslocs.h"
     28 #include "cstring.h"
     29 #include "mutex.h"
     30 #include "ucln_in.h"
     31 #include "unicode/listformatter.h"
     32 #include "charstr.h"
     33 #include "unicode/putil.h"
     34 #include "unicode/smpdtfmt.h"
     35 #include "uassert.h"
     36 
     37 #include "sharednumberformat.h"
     38 #include "sharedpluralrules.h"
     39 #include "standardplural.h"
     40 #include "unifiedcache.h"
     41 
     42 #define MEAS_UNIT_COUNT 129
     43 #define WIDTH_INDEX_COUNT (UMEASFMT_WIDTH_NARROW + 1)
     44 
     45 U_NAMESPACE_BEGIN
     46 
     47 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
     48 
     49 // Used to format durations like 5:47 or 21:35:42.
     50 class NumericDateFormatters : public UMemory {
     51 public:
     52     // Formats like H:mm
     53     SimpleDateFormat hourMinute;
     54 
     55     // formats like M:ss
     56     SimpleDateFormat minuteSecond;
     57 
     58     // formats like H:mm:ss
     59     SimpleDateFormat hourMinuteSecond;
     60 
     61     // Constructor that takes the actual patterns for hour-minute,
     62     // minute-second, and hour-minute-second respectively.
     63     NumericDateFormatters(
     64             const UnicodeString &hm,
     65             const UnicodeString &ms,
     66             const UnicodeString &hms,
     67             UErrorCode &status) :
     68             hourMinute(hm, status),
     69             minuteSecond(ms, status),
     70             hourMinuteSecond(hms, status) {
     71         const TimeZone *gmt = TimeZone::getGMT();
     72         hourMinute.setTimeZone(*gmt);
     73         minuteSecond.setTimeZone(*gmt);
     74         hourMinuteSecond.setTimeZone(*gmt);
     75     }
     76 private:
     77     NumericDateFormatters(const NumericDateFormatters &other);
     78     NumericDateFormatters &operator=(const NumericDateFormatters &other);
     79 };
     80 
     81 static UMeasureFormatWidth getRegularWidth(UMeasureFormatWidth width) {
     82     if (width >= WIDTH_INDEX_COUNT) {
     83         return UMEASFMT_WIDTH_NARROW;
     84     }
     85     return width;
     86 }
     87 
     88 /**
     89  * Instances contain all MeasureFormat specific data for a particular locale.
     90  * This data is cached. It is never copied, but is shared via shared pointers.
     91  *
     92  * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of
     93  * complete sets of unit & per patterns,
     94  * to correspond to the resource data and its aliases.
     95  *
     96  * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
     97  */
     98 class MeasureFormatCacheData : public SharedObject {
     99 public:
    100     static const int32_t PER_UNIT_INDEX = StandardPlural::COUNT;
    101     static const int32_t PATTERN_COUNT = PER_UNIT_INDEX + 1;
    102 
    103     /**
    104      * Redirection data from root-bundle, top-level sideways aliases.
    105      * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root
    106      * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data
    107      */
    108     UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT];
    109     /** Measure unit -> format width -> array of patterns ("{0} meters") (plurals + PER_UNIT_INDEX) */
    110     SimplePatternFormatter *patterns[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT][PATTERN_COUNT];
    111     SimplePatternFormatter perFormatters[WIDTH_INDEX_COUNT];
    112 
    113     MeasureFormatCacheData();
    114     virtual ~MeasureFormatCacheData();
    115 
    116     UBool hasPerFormatter(int32_t width) const {
    117         // TODO: Create a more obvious way to test if the per-formatter has been set?
    118         // Use pointers, check for NULL? Or add an isValid() method?
    119         return perFormatters[width].getPlaceholderCount() == 2;
    120     }
    121 
    122     void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) {
    123         delete currencyFormats[widthIndex];
    124         currencyFormats[widthIndex] = nfToAdopt;
    125     }
    126     const NumberFormat *getCurrencyFormat(UMeasureFormatWidth width) const {
    127         return currencyFormats[getRegularWidth(width)];
    128     }
    129     void adoptIntegerFormat(NumberFormat *nfToAdopt) {
    130         delete integerFormat;
    131         integerFormat = nfToAdopt;
    132     }
    133     const NumberFormat *getIntegerFormat() const {
    134         return integerFormat;
    135     }
    136     void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) {
    137         delete numericDateFormatters;
    138         numericDateFormatters = formattersToAdopt;
    139     }
    140     const NumericDateFormatters *getNumericDateFormatters() const {
    141         return numericDateFormatters;
    142     }
    143 
    144 private:
    145     NumberFormat *currencyFormats[WIDTH_INDEX_COUNT];
    146     NumberFormat *integerFormat;
    147     NumericDateFormatters *numericDateFormatters;
    148     MeasureFormatCacheData(const MeasureFormatCacheData &other);
    149     MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
    150 };
    151 
    152 MeasureFormatCacheData::MeasureFormatCacheData() {
    153     for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
    154         widthFallback[i] = UMEASFMT_WIDTH_COUNT;
    155     }
    156     for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
    157         currencyFormats[i] = NULL;
    158     }
    159     uprv_memset(patterns, 0, sizeof(patterns));
    160     integerFormat = NULL;
    161     numericDateFormatters = NULL;
    162 }
    163 
    164 MeasureFormatCacheData::~MeasureFormatCacheData() {
    165     for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
    166         delete currencyFormats[i];
    167     }
    168     for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) {
    169         for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) {
    170             for (int32_t k = 0; k < PATTERN_COUNT; ++k) {
    171                 delete patterns[i][j][k];
    172             }
    173         }
    174     }
    175     delete integerFormat;
    176     delete numericDateFormatters;
    177 }
    178 
    179 static UBool isCurrency(const MeasureUnit &unit) {
    180     return (uprv_strcmp(unit.getType(), "currency") == 0);
    181 }
    182 
    183 static UBool getString(
    184         const UResourceBundle *resource,
    185         UnicodeString &result,
    186         UErrorCode &status) {
    187     int32_t len = 0;
    188     const UChar *resStr = ures_getString(resource, &len, &status);
    189     if (U_FAILURE(status)) {
    190         return FALSE;
    191     }
    192     result.setTo(TRUE, resStr, len);
    193     return TRUE;
    194 }
    195 
    196 namespace {
    197 
    198 static const UChar g_LOCALE_units[] = {
    199     0x2F, 0x4C, 0x4F, 0x43, 0x41, 0x4C, 0x45, 0x2F,
    200     0x75, 0x6E, 0x69, 0x74, 0x73
    201 };
    202 static const UChar gShort[] = { 0x53, 0x68, 0x6F, 0x72, 0x74 };
    203 static const UChar gNarrow[] = { 0x4E, 0x61, 0x72, 0x72, 0x6F, 0x77 };
    204 
    205 /**
    206  * Sink for enumerating all of the measurement unit display names.
    207  * Contains inner sink classes, each one corresponding to a type of resource table.
    208  * The outer sink handles the top-level units, unitsNarrow, and unitsShort tables.
    209  *
    210  * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root):
    211  * Only store a value if it is still missing, that is, it has not been overridden.
    212  *
    213  * C++: Each inner sink class has a reference to the main outer sink.
    214  * Java: Use non-static inner classes instead.
    215  */
    216 struct UnitDataSink : public ResourceTableSink {
    217     /**
    218      * Sink for a table of display patterns. For example,
    219      * unitsShort/duration/hour contains other{"{0} hrs"}.
    220      */
    221     struct UnitPatternSink : public ResourceTableSink {
    222         UnitPatternSink(UnitDataSink &sink) : outer(sink) {}
    223         ~UnitPatternSink();
    224 
    225         void setFormatterIfAbsent(int32_t index, const ResourceValue &value,
    226                                   int32_t minPlaceholders, UErrorCode &errorCode) {
    227             SimplePatternFormatter **patterns =
    228                 &outer.cacheData.patterns[outer.unitIndex][outer.width][0];
    229             if (U_SUCCESS(errorCode) && patterns[index] == NULL) {
    230                 patterns[index] = new SimplePatternFormatter(
    231                        value.getUnicodeString(errorCode), minPlaceholders, 1, errorCode);
    232                 if (U_SUCCESS(errorCode) && patterns[index] == NULL) {
    233                     errorCode = U_MEMORY_ALLOCATION_ERROR;
    234                 }
    235             }
    236         }
    237 
    238         virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
    239             if (U_FAILURE(errorCode)) { return; }
    240             if (uprv_strcmp(key, "dnam") == 0) {
    241                 // Skip the unit display name for now.
    242             } else if (uprv_strcmp(key, "per") == 0) {
    243                 // For example, "{0}/h".
    244                 // TODO: Set minPlaceholders=1
    245                 // after http://unicode.org/cldr/trac/ticket/9129 is fixed.
    246                 setFormatterIfAbsent(MeasureFormatCacheData::PER_UNIT_INDEX, value, 0, errorCode);
    247             } else {
    248                 // The key must be one of the plural form strings. For example:
    249                 // one{"{0} hr"}
    250                 // other{"{0} hrs"}
    251                 setFormatterIfAbsent(StandardPlural::indexFromString(key, errorCode), value, 0,
    252                                      errorCode);
    253             }
    254         }
    255         UnitDataSink &outer;
    256     } patternSink;
    257 
    258     /**
    259      * Sink for a table of per-unit tables. For example,
    260      * unitsShort/duration contains tables for duration-unit subtypes day & hour.
    261      */
    262     struct UnitSubtypeSink : public ResourceTableSink {
    263         UnitSubtypeSink(UnitDataSink &sink) : outer(sink) {}
    264         ~UnitSubtypeSink();
    265         virtual ResourceTableSink *getOrCreateTableSink(
    266                 const char *key, int32_t /* initialSize */, UErrorCode &errorCode) {
    267             if (U_FAILURE(errorCode)) { return NULL; }
    268             outer.unitIndex = MeasureUnit::internalGetIndexForTypeAndSubtype(outer.type, key);
    269             if (outer.unitIndex >= 0) {
    270                 return &outer.patternSink;
    271             }
    272             return NULL;
    273         }
    274         UnitDataSink &outer;
    275     } subtypeSink;
    276 
    277     /**
    278      * Sink for compound x-per-y display pattern. For example,
    279      * unitsShort/compound/per may be "{0}/{1}".
    280      */
    281     struct UnitCompoundSink : public ResourceTableSink {
    282         UnitCompoundSink(UnitDataSink &sink) : outer(sink) {}
    283         ~UnitCompoundSink();
    284         virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
    285             if (U_SUCCESS(errorCode) && uprv_strcmp(key, "per") == 0) {
    286                 outer.cacheData.perFormatters[outer.width].
    287                         compileMinMaxPlaceholders(value.getUnicodeString(errorCode), 2, 2, errorCode);
    288             }
    289         }
    290         UnitDataSink &outer;
    291     } compoundSink;
    292 
    293     /**
    294      * Sink for a table of unit type tables. For example,
    295      * unitsShort contains tables for area & duration.
    296      * It also contains a table for the compound/per pattern.
    297      */
    298     struct UnitTypeSink : public ResourceTableSink {
    299         UnitTypeSink(UnitDataSink &sink) : outer(sink) {}
    300         ~UnitTypeSink();
    301         virtual ResourceTableSink *getOrCreateTableSink(
    302                 const char *key, int32_t /* initialSize */, UErrorCode &errorCode) {
    303             if (U_FAILURE(errorCode)) { return NULL; }
    304             if (uprv_strcmp(key, "currency") == 0) {
    305                 // Skip.
    306             } else if (uprv_strcmp(key, "compound") == 0) {
    307                 if (!outer.cacheData.hasPerFormatter(outer.width)) {
    308                     return &outer.compoundSink;
    309                 }
    310             } else {
    311                 outer.type = key;
    312                 return &outer.subtypeSink;
    313             }
    314             return NULL;
    315         }
    316         UnitDataSink &outer;
    317     } typeSink;
    318 
    319     UnitDataSink(MeasureFormatCacheData &outputData)
    320             : patternSink(*this), subtypeSink(*this), compoundSink(*this), typeSink(*this),
    321               cacheData(outputData),
    322               width(UMEASFMT_WIDTH_COUNT), type(NULL), unitIndex(0) {}
    323     ~UnitDataSink();
    324     virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
    325         // Handle aliases like
    326         // units:alias{"/LOCALE/unitsShort"}
    327         // which should only occur in the root bundle.
    328         if (U_FAILURE(errorCode) || value.getType() != URES_ALIAS) { return; }
    329         UMeasureFormatWidth sourceWidth = widthFromKey(key);
    330         if (sourceWidth == UMEASFMT_WIDTH_COUNT) {
    331             // Alias from something we don't care about.
    332             return;
    333         }
    334         UMeasureFormatWidth targetWidth = widthFromAlias(value, errorCode);
    335         if (targetWidth == UMEASFMT_WIDTH_COUNT) {
    336             // We do not recognize what to fall back to.
    337             errorCode = U_INVALID_FORMAT_ERROR;
    338             return;
    339         }
    340         // Check that we do not fall back to another fallback.
    341         if (cacheData.widthFallback[targetWidth] != UMEASFMT_WIDTH_COUNT) {
    342             errorCode = U_INVALID_FORMAT_ERROR;
    343             return;
    344         }
    345         cacheData.widthFallback[sourceWidth] = targetWidth;
    346     }
    347     virtual ResourceTableSink *getOrCreateTableSink(
    348             const char *key, int32_t /* initialSize */, UErrorCode &errorCode) {
    349         if (U_SUCCESS(errorCode) && (width = widthFromKey(key)) != UMEASFMT_WIDTH_COUNT) {
    350             return &typeSink;
    351         }
    352         return NULL;
    353     }
    354 
    355     static UMeasureFormatWidth widthFromKey(const char *key) {
    356         if (uprv_strncmp(key, "units", 5) == 0) {
    357             key += 5;
    358             if (*key == 0) {
    359                 return UMEASFMT_WIDTH_WIDE;
    360             } else if (uprv_strcmp(key, "Short") == 0) {
    361                 return UMEASFMT_WIDTH_SHORT;
    362             } else if (uprv_strcmp(key, "Narrow") == 0) {
    363                 return UMEASFMT_WIDTH_NARROW;
    364             }
    365         }
    366         return UMEASFMT_WIDTH_COUNT;
    367     }
    368 
    369     static UMeasureFormatWidth widthFromAlias(const ResourceValue &value, UErrorCode &errorCode) {
    370         int32_t length;
    371         const UChar *s = value.getAliasString(length, errorCode);
    372         // For example: "/LOCALE/unitsShort"
    373         if (U_SUCCESS(errorCode) && length >= 13 && u_memcmp(s, g_LOCALE_units, 13) == 0) {
    374             s += 13;
    375             length -= 13;
    376             if (*s == 0) {
    377                 return UMEASFMT_WIDTH_WIDE;
    378             } else if (u_strCompare(s, length, gShort, 5, FALSE) == 0) {
    379                 return UMEASFMT_WIDTH_SHORT;
    380             } else if (u_strCompare(s, length, gNarrow, 6, FALSE) == 0) {
    381                 return UMEASFMT_WIDTH_NARROW;
    382             }
    383         }
    384         return UMEASFMT_WIDTH_COUNT;
    385     }
    386 
    387     // Output data.
    388     MeasureFormatCacheData &cacheData;
    389 
    390     // Path to current data.
    391     UMeasureFormatWidth width;
    392     const char *type;
    393     int32_t unitIndex;
    394 };
    395 
    396 // Virtual destructors must be defined out of line.
    397 UnitDataSink::UnitPatternSink::~UnitPatternSink() {}
    398 UnitDataSink::UnitSubtypeSink::~UnitSubtypeSink() {}
    399 UnitDataSink::UnitCompoundSink::~UnitCompoundSink() {}
    400 UnitDataSink::UnitTypeSink::~UnitTypeSink() {}
    401 UnitDataSink::~UnitDataSink() {}
    402 
    403 }  // namespace
    404 
    405 static UBool loadMeasureUnitData(
    406         const UResourceBundle *resource,
    407         MeasureFormatCacheData &cacheData,
    408         UErrorCode &status) {
    409     UnitDataSink sink(cacheData);
    410     ures_getAllTableItemsWithFallback(resource, "", sink, status);
    411     return U_SUCCESS(status);
    412 }
    413 
    414 static UnicodeString loadNumericDateFormatterPattern(
    415         const UResourceBundle *resource,
    416         const char *pattern,
    417         UErrorCode &status) {
    418     UnicodeString result;
    419     if (U_FAILURE(status)) {
    420         return result;
    421     }
    422     CharString chs;
    423     chs.append("durationUnits", status)
    424             .append("/", status).append(pattern, status);
    425     LocalUResourceBundlePointer patternBundle(
    426             ures_getByKeyWithFallback(
    427                 resource,
    428                 chs.data(),
    429                 NULL,
    430                 &status));
    431     if (U_FAILURE(status)) {
    432         return result;
    433     }
    434     getString(patternBundle.getAlias(), result, status);
    435     // Replace 'h' with 'H'
    436     int32_t len = result.length();
    437     UChar *buffer = result.getBuffer(len);
    438     for (int32_t i = 0; i < len; ++i) {
    439         if (buffer[i] == 0x68) { // 'h'
    440             buffer[i] = 0x48; // 'H'
    441         }
    442     }
    443     result.releaseBuffer(len);
    444     return result;
    445 }
    446 
    447 static NumericDateFormatters *loadNumericDateFormatters(
    448         const UResourceBundle *resource,
    449         UErrorCode &status) {
    450     if (U_FAILURE(status)) {
    451         return NULL;
    452     }
    453     NumericDateFormatters *result = new NumericDateFormatters(
    454         loadNumericDateFormatterPattern(resource, "hm", status),
    455         loadNumericDateFormatterPattern(resource, "ms", status),
    456         loadNumericDateFormatterPattern(resource, "hms", status),
    457         status);
    458     if (U_FAILURE(status)) {
    459         delete result;
    460         return NULL;
    461     }
    462     return result;
    463 }
    464 
    465 template<> U_I18N_API
    466 const MeasureFormatCacheData *LocaleCacheKey<MeasureFormatCacheData>::createObject(
    467         const void * /*unused*/, UErrorCode &status) const {
    468     const char *localeId = fLoc.getName();
    469     LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, localeId, &status));
    470     static UNumberFormatStyle currencyStyles[] = {
    471             UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY};
    472     LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData(), status);
    473     if (U_FAILURE(status)) {
    474         return NULL;
    475     }
    476     if (!loadMeasureUnitData(
    477             unitsBundle.getAlias(),
    478             *result,
    479             status)) {
    480         return NULL;
    481     }
    482     result->adoptNumericDateFormatters(loadNumericDateFormatters(
    483             unitsBundle.getAlias(), status));
    484     if (U_FAILURE(status)) {
    485         return NULL;
    486     }
    487 
    488     for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
    489         result->adoptCurrencyFormat(i, NumberFormat::createInstance(
    490                 localeId, currencyStyles[i], status));
    491         if (U_FAILURE(status)) {
    492             return NULL;
    493         }
    494     }
    495     NumberFormat *inf = NumberFormat::createInstance(
    496             localeId, UNUM_DECIMAL, status);
    497     if (U_FAILURE(status)) {
    498         return NULL;
    499     }
    500     inf->setMaximumFractionDigits(0);
    501     DecimalFormat *decfmt = dynamic_cast<DecimalFormat *>(inf);
    502     if (decfmt != NULL) {
    503         decfmt->setRoundingMode(DecimalFormat::kRoundDown);
    504     }
    505     result->adoptIntegerFormat(inf);
    506     result->addRef();
    507     return result.orphan();
    508 }
    509 
    510 static UBool isTimeUnit(const MeasureUnit &mu, const char *tu) {
    511     return uprv_strcmp(mu.getType(), "duration") == 0 &&
    512             uprv_strcmp(mu.getSubtype(), tu) == 0;
    513 }
    514 
    515 // Converts a composite measure into hours-minutes-seconds and stores at hms
    516 // array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
    517 // units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
    518 // contains hours-minutes, this function would return 3.
    519 //
    520 // If measures cannot be converted into hours, minutes, seconds or if amounts
    521 // are negative, or if hours, minutes, seconds are out of order, returns 0.
    522 static int32_t toHMS(
    523         const Measure *measures,
    524         int32_t measureCount,
    525         Formattable *hms,
    526         UErrorCode &status) {
    527     if (U_FAILURE(status)) {
    528         return 0;
    529     }
    530     int32_t result = 0;
    531     if (U_FAILURE(status)) {
    532         return 0;
    533     }
    534     // We use copy constructor to ensure that both sides of equality operator
    535     // are instances of MeasureUnit base class and not a subclass. Otherwise,
    536     // operator== will immediately return false.
    537     for (int32_t i = 0; i < measureCount; ++i) {
    538         if (isTimeUnit(measures[i].getUnit(), "hour")) {
    539             // hour must come first
    540             if (result >= 1) {
    541                 return 0;
    542             }
    543             hms[0] = measures[i].getNumber();
    544             if (hms[0].getDouble() < 0.0) {
    545                 return 0;
    546             }
    547             result |= 1;
    548         } else if (isTimeUnit(measures[i].getUnit(), "minute")) {
    549             // minute must come after hour
    550             if (result >= 2) {
    551                 return 0;
    552             }
    553             hms[1] = measures[i].getNumber();
    554             if (hms[1].getDouble() < 0.0) {
    555                 return 0;
    556             }
    557             result |= 2;
    558         } else if (isTimeUnit(measures[i].getUnit(), "second")) {
    559             // second must come after hour and minute
    560             if (result >= 4) {
    561                 return 0;
    562             }
    563             hms[2] = measures[i].getNumber();
    564             if (hms[2].getDouble() < 0.0) {
    565                 return 0;
    566             }
    567             result |= 4;
    568         } else {
    569             return 0;
    570         }
    571     }
    572     return result;
    573 }
    574 
    575 
    576 MeasureFormat::MeasureFormat(
    577         const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
    578         : cache(NULL),
    579           numberFormat(NULL),
    580           pluralRules(NULL),
    581           width(w),
    582           listFormatter(NULL) {
    583     initMeasureFormat(locale, w, NULL, status);
    584 }
    585 
    586 MeasureFormat::MeasureFormat(
    587         const Locale &locale,
    588         UMeasureFormatWidth w,
    589         NumberFormat *nfToAdopt,
    590         UErrorCode &status)
    591         : cache(NULL),
    592           numberFormat(NULL),
    593           pluralRules(NULL),
    594           width(w),
    595           listFormatter(NULL) {
    596     initMeasureFormat(locale, w, nfToAdopt, status);
    597 }
    598 
    599 MeasureFormat::MeasureFormat(const MeasureFormat &other) :
    600         Format(other),
    601         cache(other.cache),
    602         numberFormat(other.numberFormat),
    603         pluralRules(other.pluralRules),
    604         width(other.width),
    605         listFormatter(NULL) {
    606     cache->addRef();
    607     numberFormat->addRef();
    608     pluralRules->addRef();
    609     listFormatter = new ListFormatter(*other.listFormatter);
    610 }
    611 
    612 MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
    613     if (this == &other) {
    614         return *this;
    615     }
    616     Format::operator=(other);
    617     SharedObject::copyPtr(other.cache, cache);
    618     SharedObject::copyPtr(other.numberFormat, numberFormat);
    619     SharedObject::copyPtr(other.pluralRules, pluralRules);
    620     width = other.width;
    621     delete listFormatter;
    622     listFormatter = new ListFormatter(*other.listFormatter);
    623     return *this;
    624 }
    625 
    626 MeasureFormat::MeasureFormat() :
    627         cache(NULL),
    628         numberFormat(NULL),
    629         pluralRules(NULL),
    630         width(UMEASFMT_WIDTH_SHORT),
    631         listFormatter(NULL) {
    632 }
    633 
    634 MeasureFormat::~MeasureFormat() {
    635     if (cache != NULL) {
    636         cache->removeRef();
    637     }
    638     if (numberFormat != NULL) {
    639         numberFormat->removeRef();
    640     }
    641     if (pluralRules != NULL) {
    642         pluralRules->removeRef();
    643     }
    644     delete listFormatter;
    645 }
    646 
    647 UBool MeasureFormat::operator==(const Format &other) const {
    648     if (this == &other) { // Same object, equal
    649         return TRUE;
    650     }
    651     if (!Format::operator==(other)) {
    652         return FALSE;
    653     }
    654     const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other);
    655 
    656     // Note: Since the ListFormatter depends only on Locale and width, we
    657     // don't have to check it here.
    658 
    659     // differing widths aren't equivalent
    660     if (width != rhs.width) {
    661         return FALSE;
    662     }
    663     // Width the same check locales.
    664     // We don't need to check locales if both objects have same cache.
    665     if (cache != rhs.cache) {
    666         UErrorCode status = U_ZERO_ERROR;
    667         const char *localeId = getLocaleID(status);
    668         const char *rhsLocaleId = rhs.getLocaleID(status);
    669         if (U_FAILURE(status)) {
    670             // On failure, assume not equal
    671             return FALSE;
    672         }
    673         if (uprv_strcmp(localeId, rhsLocaleId) != 0) {
    674             return FALSE;
    675         }
    676     }
    677     // Locales same, check NumberFormat if shared data differs.
    678     return (
    679             numberFormat == rhs.numberFormat ||
    680             **numberFormat == **rhs.numberFormat);
    681 }
    682 
    683 Format *MeasureFormat::clone() const {
    684     return new MeasureFormat(*this);
    685 }
    686 
    687 UnicodeString &MeasureFormat::format(
    688         const Formattable &obj,
    689         UnicodeString &appendTo,
    690         FieldPosition &pos,
    691         UErrorCode &status) const {
    692     if (U_FAILURE(status)) return appendTo;
    693     if (obj.getType() == Formattable::kObject) {
    694         const UObject* formatObj = obj.getObject();
    695         const Measure* amount = dynamic_cast<const Measure*>(formatObj);
    696         if (amount != NULL) {
    697             return formatMeasure(
    698                     *amount, **numberFormat, appendTo, pos, status);
    699         }
    700     }
    701     status = U_ILLEGAL_ARGUMENT_ERROR;
    702     return appendTo;
    703 }
    704 
    705 void MeasureFormat::parseObject(
    706         const UnicodeString & /*source*/,
    707         Formattable & /*result*/,
    708         ParsePosition& /*pos*/) const {
    709     return;
    710 }
    711 
    712 UnicodeString &MeasureFormat::formatMeasurePerUnit(
    713         const Measure &measure,
    714         const MeasureUnit &perUnit,
    715         UnicodeString &appendTo,
    716         FieldPosition &pos,
    717         UErrorCode &status) const {
    718     if (U_FAILURE(status)) {
    719         return appendTo;
    720     }
    721     MeasureUnit *resolvedUnit =
    722             MeasureUnit::resolveUnitPerUnit(measure.getUnit(), perUnit);
    723     if (resolvedUnit != NULL) {
    724         Measure newMeasure(measure.getNumber(), resolvedUnit, status);
    725         return formatMeasure(
    726                 newMeasure, **numberFormat, appendTo, pos, status);
    727     }
    728     FieldPosition fpos(pos.getField());
    729     UnicodeString result;
    730     int32_t offset = withPerUnitAndAppend(
    731             formatMeasure(
    732                     measure, **numberFormat, result, fpos, status),
    733             perUnit,
    734             appendTo,
    735             status);
    736     if (U_FAILURE(status)) {
    737         return appendTo;
    738     }
    739     if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
    740         pos.setBeginIndex(fpos.getBeginIndex() + offset);
    741         pos.setEndIndex(fpos.getEndIndex() + offset);
    742     }
    743     return appendTo;
    744 }
    745 
    746 UnicodeString &MeasureFormat::formatMeasures(
    747         const Measure *measures,
    748         int32_t measureCount,
    749         UnicodeString &appendTo,
    750         FieldPosition &pos,
    751         UErrorCode &status) const {
    752     if (U_FAILURE(status)) {
    753         return appendTo;
    754     }
    755     if (measureCount == 0) {
    756         return appendTo;
    757     }
    758     if (measureCount == 1) {
    759         return formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
    760     }
    761     if (width == UMEASFMT_WIDTH_NUMERIC) {
    762         Formattable hms[3];
    763         int32_t bitMap = toHMS(measures, measureCount, hms, status);
    764         if (bitMap > 0) {
    765             return formatNumeric(hms, bitMap, appendTo, status);
    766         }
    767     }
    768     if (pos.getField() != FieldPosition::DONT_CARE) {
    769         return formatMeasuresSlowTrack(
    770                 measures, measureCount, appendTo, pos, status);
    771     }
    772     UnicodeString *results = new UnicodeString[measureCount];
    773     if (results == NULL) {
    774         status = U_MEMORY_ALLOCATION_ERROR;
    775         return appendTo;
    776     }
    777     for (int32_t i = 0; i < measureCount; ++i) {
    778         const NumberFormat *nf = cache->getIntegerFormat();
    779         if (i == measureCount - 1) {
    780             nf = numberFormat->get();
    781         }
    782         formatMeasure(
    783                 measures[i],
    784                 *nf,
    785                 results[i],
    786                 pos,
    787                 status);
    788     }
    789     listFormatter->format(results, measureCount, appendTo, status);
    790     delete [] results;
    791     return appendTo;
    792 }
    793 
    794 void MeasureFormat::initMeasureFormat(
    795         const Locale &locale,
    796         UMeasureFormatWidth w,
    797         NumberFormat *nfToAdopt,
    798         UErrorCode &status) {
    799     static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
    800     LocalPointer<NumberFormat> nf(nfToAdopt);
    801     if (U_FAILURE(status)) {
    802         return;
    803     }
    804     const char *name = locale.getName();
    805     setLocaleIDs(name, name);
    806 
    807     UnifiedCache::getByLocale(locale, cache, status);
    808     if (U_FAILURE(status)) {
    809         return;
    810     }
    811 
    812     const SharedPluralRules *pr = PluralRules::createSharedInstance(
    813             locale, UPLURAL_TYPE_CARDINAL, status);
    814     if (U_FAILURE(status)) {
    815         return;
    816     }
    817     SharedObject::copyPtr(pr, pluralRules);
    818     pr->removeRef();
    819     if (nf.isNull()) {
    820         const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
    821                 locale, UNUM_DECIMAL, status);
    822         if (U_FAILURE(status)) {
    823             return;
    824         }
    825         SharedObject::copyPtr(shared, numberFormat);
    826         shared->removeRef();
    827     } else {
    828         adoptNumberFormat(nf.orphan(), status);
    829         if (U_FAILURE(status)) {
    830             return;
    831         }
    832     }
    833     width = w;
    834     delete listFormatter;
    835     listFormatter = ListFormatter::createInstance(
    836             locale,
    837             listStyles[getRegularWidth(width)],
    838             status);
    839 }
    840 
    841 void MeasureFormat::adoptNumberFormat(
    842         NumberFormat *nfToAdopt, UErrorCode &status) {
    843     LocalPointer<NumberFormat> nf(nfToAdopt);
    844     if (U_FAILURE(status)) {
    845         return;
    846     }
    847     SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
    848     if (shared == NULL) {
    849         status = U_MEMORY_ALLOCATION_ERROR;
    850         return;
    851     }
    852     nf.orphan();
    853     SharedObject::copyPtr(shared, numberFormat);
    854 }
    855 
    856 UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) {
    857     if (U_FAILURE(status) || locale == getLocale(status)) {
    858         return FALSE;
    859     }
    860     initMeasureFormat(locale, width, NULL, status);
    861     return U_SUCCESS(status);
    862 }
    863 
    864 const NumberFormat &MeasureFormat::getNumberFormat() const {
    865     return **numberFormat;
    866 }
    867 
    868 const PluralRules &MeasureFormat::getPluralRules() const {
    869     return **pluralRules;
    870 }
    871 
    872 Locale MeasureFormat::getLocale(UErrorCode &status) const {
    873     return Format::getLocale(ULOC_VALID_LOCALE, status);
    874 }
    875 
    876 const char *MeasureFormat::getLocaleID(UErrorCode &status) const {
    877     return Format::getLocaleID(ULOC_VALID_LOCALE, status);
    878 }
    879 
    880 UnicodeString &MeasureFormat::formatMeasure(
    881         const Measure &measure,
    882         const NumberFormat &nf,
    883         UnicodeString &appendTo,
    884         FieldPosition &pos,
    885         UErrorCode &status) const {
    886     if (U_FAILURE(status)) {
    887         return appendTo;
    888     }
    889     const Formattable& amtNumber = measure.getNumber();
    890     const MeasureUnit& amtUnit = measure.getUnit();
    891     if (isCurrency(amtUnit)) {
    892         UChar isoCode[4];
    893         u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
    894         return cache->getCurrencyFormat(width)->format(
    895                 new CurrencyAmount(amtNumber, isoCode, status),
    896                 appendTo,
    897                 pos,
    898                 status);
    899     }
    900     UnicodeString formattedNumber;
    901     StandardPlural::Form pluralForm = QuantityFormatter::selectPlural(
    902             amtNumber, nf, **pluralRules, formattedNumber, pos, status);
    903     const SimplePatternFormatter *formatter = getPluralFormatter(amtUnit, width, pluralForm, status);
    904     return QuantityFormatter::format(*formatter, formattedNumber, appendTo, pos, status);
    905 }
    906 
    907 // Formats hours-minutes-seconds as 5:37:23 or similar.
    908 UnicodeString &MeasureFormat::formatNumeric(
    909         const Formattable *hms,  // always length 3
    910         int32_t bitMap,   // 1=hourset, 2=minuteset, 4=secondset
    911         UnicodeString &appendTo,
    912         UErrorCode &status) const {
    913     if (U_FAILURE(status)) {
    914         return appendTo;
    915     }
    916     UDate millis =
    917         (UDate) (((uprv_trunc(hms[0].getDouble(status)) * 60.0
    918              + uprv_trunc(hms[1].getDouble(status))) * 60.0
    919                   + uprv_trunc(hms[2].getDouble(status))) * 1000.0);
    920     switch (bitMap) {
    921     case 5: // hs
    922     case 7: // hms
    923         return formatNumeric(
    924                 millis,
    925                 cache->getNumericDateFormatters()->hourMinuteSecond,
    926                 UDAT_SECOND_FIELD,
    927                 hms[2],
    928                 appendTo,
    929                 status);
    930         break;
    931     case 6: // ms
    932         return formatNumeric(
    933                 millis,
    934                 cache->getNumericDateFormatters()->minuteSecond,
    935                 UDAT_SECOND_FIELD,
    936                 hms[2],
    937                 appendTo,
    938                 status);
    939         break;
    940     case 3: // hm
    941         return formatNumeric(
    942                 millis,
    943                 cache->getNumericDateFormatters()->hourMinute,
    944                 UDAT_MINUTE_FIELD,
    945                 hms[1],
    946                 appendTo,
    947                 status);
    948         break;
    949     default:
    950         status = U_INTERNAL_PROGRAM_ERROR;
    951         return appendTo;
    952         break;
    953     }
    954     return appendTo;
    955 }
    956 
    957 static void appendRange(
    958         const UnicodeString &src,
    959         int32_t start,
    960         int32_t end,
    961         UnicodeString &dest) {
    962     dest.append(src, start, end - start);
    963 }
    964 
    965 static void appendRange(
    966         const UnicodeString &src,
    967         int32_t end,
    968         UnicodeString &dest) {
    969     dest.append(src, end, src.length() - end);
    970 }
    971 
    972 // Formats time like 5:37:23
    973 UnicodeString &MeasureFormat::formatNumeric(
    974         UDate date, // Time since epoch 1:30:00 would be 5400000
    975         const DateFormat &dateFmt, // h:mm, m:ss, or h:mm:ss
    976         UDateFormatField smallestField, // seconds in 5:37:23.5
    977         const Formattable &smallestAmount, // 23.5 for 5:37:23.5
    978         UnicodeString &appendTo,
    979         UErrorCode &status) const {
    980     if (U_FAILURE(status)) {
    981         return appendTo;
    982     }
    983     // Format the smallest amount with this object's NumberFormat
    984     UnicodeString smallestAmountFormatted;
    985 
    986     // We keep track of the integer part of smallest amount so that
    987     // we can replace it later so that we get '0:00:09.3' instead of
    988     // '0:00:9.3'
    989     FieldPosition intFieldPosition(UNUM_INTEGER_FIELD);
    990     (*numberFormat)->format(
    991             smallestAmount, smallestAmountFormatted, intFieldPosition, status);
    992     if (
    993             intFieldPosition.getBeginIndex() == 0 &&
    994             intFieldPosition.getEndIndex() == 0) {
    995         status = U_INTERNAL_PROGRAM_ERROR;
    996         return appendTo;
    997     }
    998 
    999     // Format time. draft becomes something like '5:30:45'
   1000     FieldPosition smallestFieldPosition(smallestField);
   1001     UnicodeString draft;
   1002     dateFmt.format(date, draft, smallestFieldPosition, status);
   1003 
   1004     // If we find field for smallest amount replace it with the formatted
   1005     // smallest amount from above taking care to replace the integer part
   1006     // with what is in original time. For example, If smallest amount
   1007     // is 9.35s and the formatted time is 0:00:09 then 9.35 becomes 09.35
   1008     // and replacing yields 0:00:09.35
   1009     if (smallestFieldPosition.getBeginIndex() != 0 ||
   1010             smallestFieldPosition.getEndIndex() != 0) {
   1011         appendRange(draft, 0, smallestFieldPosition.getBeginIndex(), appendTo);
   1012         appendRange(
   1013                 smallestAmountFormatted,
   1014                 0,
   1015                 intFieldPosition.getBeginIndex(),
   1016                 appendTo);
   1017         appendRange(
   1018                 draft,
   1019                 smallestFieldPosition.getBeginIndex(),
   1020                 smallestFieldPosition.getEndIndex(),
   1021                 appendTo);
   1022         appendRange(
   1023                 smallestAmountFormatted,
   1024                 intFieldPosition.getEndIndex(),
   1025                 appendTo);
   1026         appendRange(
   1027                 draft,
   1028                 smallestFieldPosition.getEndIndex(),
   1029                 appendTo);
   1030     } else {
   1031         appendTo.append(draft);
   1032     }
   1033     return appendTo;
   1034 }
   1035 
   1036 const SimplePatternFormatter *MeasureFormat::getFormatterOrNull(
   1037         const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index) const {
   1038     width = getRegularWidth(width);
   1039     SimplePatternFormatter *const (*unitPatterns)[MeasureFormatCacheData::PATTERN_COUNT] =
   1040             &cache->patterns[unit.getIndex()][0];
   1041     if (unitPatterns[width][index] != NULL) {
   1042         return unitPatterns[width][index];
   1043     }
   1044     int32_t fallbackWidth = cache->widthFallback[width];
   1045     if (fallbackWidth != UMEASFMT_WIDTH_COUNT && unitPatterns[fallbackWidth][index] != NULL) {
   1046         return unitPatterns[fallbackWidth][index];
   1047     }
   1048     return NULL;
   1049 }
   1050 
   1051 const SimplePatternFormatter *MeasureFormat::getFormatter(
   1052         const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index,
   1053         UErrorCode &errorCode) const {
   1054     if (U_FAILURE(errorCode)) {
   1055         return NULL;
   1056     }
   1057     const SimplePatternFormatter *pattern = getFormatterOrNull(unit, width, index);
   1058     if (pattern == NULL) {
   1059         errorCode = U_MISSING_RESOURCE_ERROR;
   1060     }
   1061     return pattern;
   1062 }
   1063 
   1064 const SimplePatternFormatter *MeasureFormat::getPluralFormatter(
   1065         const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index,
   1066         UErrorCode &errorCode) const {
   1067     if (U_FAILURE(errorCode)) {
   1068         return NULL;
   1069     }
   1070     if (index != StandardPlural::OTHER) {
   1071         const SimplePatternFormatter *pattern = getFormatterOrNull(unit, width, index);
   1072         if (pattern != NULL) {
   1073             return pattern;
   1074         }
   1075     }
   1076     return getFormatter(unit, width, StandardPlural::OTHER, errorCode);
   1077 }
   1078 
   1079 const SimplePatternFormatter *MeasureFormat::getPerFormatter(
   1080         UMeasureFormatWidth width,
   1081         UErrorCode &status) const {
   1082     if (U_FAILURE(status)) {
   1083         return NULL;
   1084     }
   1085     width = getRegularWidth(width);
   1086     const SimplePatternFormatter * perFormatters = cache->perFormatters;
   1087     if (perFormatters[width].getPlaceholderCount() == 2) {
   1088         return &perFormatters[width];
   1089     }
   1090     int32_t fallbackWidth = cache->widthFallback[width];
   1091     if (fallbackWidth != UMEASFMT_WIDTH_COUNT &&
   1092             perFormatters[fallbackWidth].getPlaceholderCount() == 2) {
   1093         return &perFormatters[fallbackWidth];
   1094     }
   1095     status = U_MISSING_RESOURCE_ERROR;
   1096     return NULL;
   1097 }
   1098 
   1099 int32_t MeasureFormat::withPerUnitAndAppend(
   1100         const UnicodeString &formatted,
   1101         const MeasureUnit &perUnit,
   1102         UnicodeString &appendTo,
   1103         UErrorCode &status) const {
   1104     int32_t offset = -1;
   1105     if (U_FAILURE(status)) {
   1106         return offset;
   1107     }
   1108     const SimplePatternFormatter *perUnitFormatter =
   1109             getFormatterOrNull(perUnit, width, MeasureFormatCacheData::PER_UNIT_INDEX);
   1110     if (perUnitFormatter != NULL) {
   1111         const UnicodeString *params[] = {&formatted};
   1112         perUnitFormatter->formatAndAppend(
   1113                 params,
   1114                 UPRV_LENGTHOF(params),
   1115                 appendTo,
   1116                 &offset,
   1117                 1,
   1118                 status);
   1119         return offset;
   1120     }
   1121     const SimplePatternFormatter *perFormatter = getPerFormatter(width, status);
   1122     const SimplePatternFormatter *pattern =
   1123             getPluralFormatter(perUnit, width, StandardPlural::ONE, status);
   1124     if (U_FAILURE(status)) {
   1125         return offset;
   1126     }
   1127     UnicodeString perUnitString = pattern->getTextWithNoPlaceholders();
   1128     perUnitString.trim();
   1129     const UnicodeString *params[] = {&formatted, &perUnitString};
   1130     perFormatter->formatAndAppend(
   1131             params,
   1132             UPRV_LENGTHOF(params),
   1133             appendTo,
   1134             &offset,
   1135             1,
   1136             status);
   1137     return offset;
   1138 }
   1139 
   1140 UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
   1141         const Measure *measures,
   1142         int32_t measureCount,
   1143         UnicodeString& appendTo,
   1144         FieldPosition& pos,
   1145         UErrorCode& status) const {
   1146     if (U_FAILURE(status)) {
   1147         return appendTo;
   1148     }
   1149     FieldPosition dontCare(FieldPosition::DONT_CARE);
   1150     FieldPosition fpos(pos.getField());
   1151     UnicodeString *results = new UnicodeString[measureCount];
   1152     int32_t fieldPositionFoundIndex = -1;
   1153     for (int32_t i = 0; i < measureCount; ++i) {
   1154         const NumberFormat *nf = cache->getIntegerFormat();
   1155         if (i == measureCount - 1) {
   1156             nf = numberFormat->get();
   1157         }
   1158         if (fieldPositionFoundIndex == -1) {
   1159             formatMeasure(measures[i], *nf, results[i], fpos, status);
   1160             if (U_FAILURE(status)) {
   1161                 delete [] results;
   1162                 return appendTo;
   1163             }
   1164             if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
   1165                 fieldPositionFoundIndex = i;
   1166             }
   1167         } else {
   1168             formatMeasure(measures[i], *nf, results[i], dontCare, status);
   1169         }
   1170     }
   1171     int32_t offset;
   1172     listFormatter->format(
   1173             results,
   1174             measureCount,
   1175             appendTo,
   1176             fieldPositionFoundIndex,
   1177             offset,
   1178             status);
   1179     if (U_FAILURE(status)) {
   1180         delete [] results;
   1181         return appendTo;
   1182     }
   1183     if (offset != -1) {
   1184         pos.setBeginIndex(fpos.getBeginIndex() + offset);
   1185         pos.setEndIndex(fpos.getEndIndex() + offset);
   1186     }
   1187     delete [] results;
   1188     return appendTo;
   1189 }
   1190 
   1191 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
   1192                                                    UErrorCode& ec) {
   1193     CurrencyFormat* fmt = NULL;
   1194     if (U_SUCCESS(ec)) {
   1195         fmt = new CurrencyFormat(locale, ec);
   1196         if (U_FAILURE(ec)) {
   1197             delete fmt;
   1198             fmt = NULL;
   1199         }
   1200     }
   1201     return fmt;
   1202 }
   1203 
   1204 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
   1205     if (U_FAILURE(ec)) {
   1206         return NULL;
   1207     }
   1208     return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
   1209 }
   1210 
   1211 U_NAMESPACE_END
   1212 
   1213 #endif /* #if !UCONFIG_NO_FORMATTING */
   1214