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