xref: /third_party/icu/icu4c/source/i18n/measfmt.cpp (revision 2e5b6d6d)
12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci/*
42e5b6d6dSopenharmony_ci**********************************************************************
52e5b6d6dSopenharmony_ci* Copyright (c) 2004-2016, International Business Machines
62e5b6d6dSopenharmony_ci* Corporation and others.  All Rights Reserved.
72e5b6d6dSopenharmony_ci**********************************************************************
82e5b6d6dSopenharmony_ci* Author: Alan Liu
92e5b6d6dSopenharmony_ci* Created: April 20, 2004
102e5b6d6dSopenharmony_ci* Since: ICU 3.0
112e5b6d6dSopenharmony_ci**********************************************************************
122e5b6d6dSopenharmony_ci*/
132e5b6d6dSopenharmony_ci#include "utypeinfo.h"  // for 'typeid' to work
142e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
152e5b6d6dSopenharmony_ci
162e5b6d6dSopenharmony_ci#if !UCONFIG_NO_FORMATTING
172e5b6d6dSopenharmony_ci
182e5b6d6dSopenharmony_ci#include "unicode/measfmt.h"
192e5b6d6dSopenharmony_ci#include "unicode/numfmt.h"
202e5b6d6dSopenharmony_ci#include "currfmt.h"
212e5b6d6dSopenharmony_ci#include "unicode/localpointer.h"
222e5b6d6dSopenharmony_ci#include "resource.h"
232e5b6d6dSopenharmony_ci#include "unicode/simpleformatter.h"
242e5b6d6dSopenharmony_ci#include "quantityformatter.h"
252e5b6d6dSopenharmony_ci#include "unicode/plurrule.h"
262e5b6d6dSopenharmony_ci#include "unicode/decimfmt.h"
272e5b6d6dSopenharmony_ci#include "uresimp.h"
282e5b6d6dSopenharmony_ci#include "unicode/ures.h"
292e5b6d6dSopenharmony_ci#include "unicode/ustring.h"
302e5b6d6dSopenharmony_ci#include "ureslocs.h"
312e5b6d6dSopenharmony_ci#include "cstring.h"
322e5b6d6dSopenharmony_ci#include "mutex.h"
332e5b6d6dSopenharmony_ci#include "ucln_in.h"
342e5b6d6dSopenharmony_ci#include "unicode/listformatter.h"
352e5b6d6dSopenharmony_ci#include "charstr.h"
362e5b6d6dSopenharmony_ci#include "unicode/putil.h"
372e5b6d6dSopenharmony_ci#include "unicode/smpdtfmt.h"
382e5b6d6dSopenharmony_ci#include "uassert.h"
392e5b6d6dSopenharmony_ci#include "unicode/numberformatter.h"
402e5b6d6dSopenharmony_ci#include "number_longnames.h"
412e5b6d6dSopenharmony_ci#include "number_utypes.h"
422e5b6d6dSopenharmony_ci
432e5b6d6dSopenharmony_ci#include "sharednumberformat.h"
442e5b6d6dSopenharmony_ci#include "sharedpluralrules.h"
452e5b6d6dSopenharmony_ci#include "standardplural.h"
462e5b6d6dSopenharmony_ci#include "unifiedcache.h"
472e5b6d6dSopenharmony_ci
482e5b6d6dSopenharmony_ci
492e5b6d6dSopenharmony_ciU_NAMESPACE_BEGIN
502e5b6d6dSopenharmony_ci
512e5b6d6dSopenharmony_ciusing number::impl::UFormattedNumberData;
522e5b6d6dSopenharmony_ci
532e5b6d6dSopenharmony_cistatic constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
542e5b6d6dSopenharmony_ci
552e5b6d6dSopenharmony_ciUOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
562e5b6d6dSopenharmony_ci
572e5b6d6dSopenharmony_ci// Used to format durations like 5:47 or 21:35:42.
582e5b6d6dSopenharmony_ciclass NumericDateFormatters : public UMemory {
592e5b6d6dSopenharmony_cipublic:
602e5b6d6dSopenharmony_ci    // Formats like H:mm
612e5b6d6dSopenharmony_ci    UnicodeString hourMinute;
622e5b6d6dSopenharmony_ci
632e5b6d6dSopenharmony_ci    // formats like M:ss
642e5b6d6dSopenharmony_ci    UnicodeString minuteSecond;
652e5b6d6dSopenharmony_ci
662e5b6d6dSopenharmony_ci    // formats like H:mm:ss
672e5b6d6dSopenharmony_ci    UnicodeString hourMinuteSecond;
682e5b6d6dSopenharmony_ci
692e5b6d6dSopenharmony_ci    // Constructor that takes the actual patterns for hour-minute,
702e5b6d6dSopenharmony_ci    // minute-second, and hour-minute-second respectively.
712e5b6d6dSopenharmony_ci    NumericDateFormatters(
722e5b6d6dSopenharmony_ci            const UnicodeString &hm,
732e5b6d6dSopenharmony_ci            const UnicodeString &ms,
742e5b6d6dSopenharmony_ci            const UnicodeString &hms) :
752e5b6d6dSopenharmony_ci            hourMinute(hm),
762e5b6d6dSopenharmony_ci            minuteSecond(ms),
772e5b6d6dSopenharmony_ci            hourMinuteSecond(hms) {
782e5b6d6dSopenharmony_ci    }
792e5b6d6dSopenharmony_ciprivate:
802e5b6d6dSopenharmony_ci    NumericDateFormatters(const NumericDateFormatters &other);
812e5b6d6dSopenharmony_ci    NumericDateFormatters &operator=(const NumericDateFormatters &other);
822e5b6d6dSopenharmony_ci};
832e5b6d6dSopenharmony_ci
842e5b6d6dSopenharmony_cistatic UMeasureFormatWidth getRegularWidth(UMeasureFormatWidth width) {
852e5b6d6dSopenharmony_ci    if (width >= WIDTH_INDEX_COUNT) {
862e5b6d6dSopenharmony_ci        return UMEASFMT_WIDTH_NARROW;
872e5b6d6dSopenharmony_ci    }
882e5b6d6dSopenharmony_ci    return width;
892e5b6d6dSopenharmony_ci}
902e5b6d6dSopenharmony_ci
912e5b6d6dSopenharmony_cistatic UNumberUnitWidth getUnitWidth(UMeasureFormatWidth width) {
922e5b6d6dSopenharmony_ci    switch (width) {
932e5b6d6dSopenharmony_ci    case UMEASFMT_WIDTH_WIDE:
942e5b6d6dSopenharmony_ci        return UNUM_UNIT_WIDTH_FULL_NAME;
952e5b6d6dSopenharmony_ci    case UMEASFMT_WIDTH_NARROW:
962e5b6d6dSopenharmony_ci    case UMEASFMT_WIDTH_NUMERIC:
972e5b6d6dSopenharmony_ci        return UNUM_UNIT_WIDTH_NARROW;
982e5b6d6dSopenharmony_ci    case UMEASFMT_WIDTH_SHORT:
992e5b6d6dSopenharmony_ci    default:
1002e5b6d6dSopenharmony_ci        return UNUM_UNIT_WIDTH_SHORT;
1012e5b6d6dSopenharmony_ci    }
1022e5b6d6dSopenharmony_ci}
1032e5b6d6dSopenharmony_ci
1042e5b6d6dSopenharmony_ci/**
1052e5b6d6dSopenharmony_ci * Instances contain all MeasureFormat specific data for a particular locale.
1062e5b6d6dSopenharmony_ci * This data is cached. It is never copied, but is shared via shared pointers.
1072e5b6d6dSopenharmony_ci *
1082e5b6d6dSopenharmony_ci * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of
1092e5b6d6dSopenharmony_ci * complete sets of unit & per patterns,
1102e5b6d6dSopenharmony_ci * to correspond to the resource data and its aliases.
1112e5b6d6dSopenharmony_ci *
1122e5b6d6dSopenharmony_ci * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
1132e5b6d6dSopenharmony_ci */
1142e5b6d6dSopenharmony_ciclass MeasureFormatCacheData : public SharedObject {
1152e5b6d6dSopenharmony_cipublic:
1162e5b6d6dSopenharmony_ci
1172e5b6d6dSopenharmony_ci    /**
1182e5b6d6dSopenharmony_ci     * Redirection data from root-bundle, top-level sideways aliases.
1192e5b6d6dSopenharmony_ci     * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root
1202e5b6d6dSopenharmony_ci     * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data
1212e5b6d6dSopenharmony_ci     */
1222e5b6d6dSopenharmony_ci    UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT];
1232e5b6d6dSopenharmony_ci
1242e5b6d6dSopenharmony_ci    MeasureFormatCacheData();
1252e5b6d6dSopenharmony_ci    virtual ~MeasureFormatCacheData();
1262e5b6d6dSopenharmony_ci
1272e5b6d6dSopenharmony_ci    void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) {
1282e5b6d6dSopenharmony_ci        delete currencyFormats[widthIndex];
1292e5b6d6dSopenharmony_ci        currencyFormats[widthIndex] = nfToAdopt;
1302e5b6d6dSopenharmony_ci    }
1312e5b6d6dSopenharmony_ci    const NumberFormat *getCurrencyFormat(UMeasureFormatWidth width) const {
1322e5b6d6dSopenharmony_ci        return currencyFormats[getRegularWidth(width)];
1332e5b6d6dSopenharmony_ci    }
1342e5b6d6dSopenharmony_ci    void adoptIntegerFormat(NumberFormat *nfToAdopt) {
1352e5b6d6dSopenharmony_ci        delete integerFormat;
1362e5b6d6dSopenharmony_ci        integerFormat = nfToAdopt;
1372e5b6d6dSopenharmony_ci    }
1382e5b6d6dSopenharmony_ci    const NumberFormat *getIntegerFormat() const {
1392e5b6d6dSopenharmony_ci        return integerFormat;
1402e5b6d6dSopenharmony_ci    }
1412e5b6d6dSopenharmony_ci    void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) {
1422e5b6d6dSopenharmony_ci        delete numericDateFormatters;
1432e5b6d6dSopenharmony_ci        numericDateFormatters = formattersToAdopt;
1442e5b6d6dSopenharmony_ci    }
1452e5b6d6dSopenharmony_ci    const NumericDateFormatters *getNumericDateFormatters() const {
1462e5b6d6dSopenharmony_ci        return numericDateFormatters;
1472e5b6d6dSopenharmony_ci    }
1482e5b6d6dSopenharmony_ci
1492e5b6d6dSopenharmony_ciprivate:
1502e5b6d6dSopenharmony_ci    NumberFormat* currencyFormats[WIDTH_INDEX_COUNT];
1512e5b6d6dSopenharmony_ci    NumberFormat* integerFormat;
1522e5b6d6dSopenharmony_ci    NumericDateFormatters* numericDateFormatters;
1532e5b6d6dSopenharmony_ci
1542e5b6d6dSopenharmony_ci    MeasureFormatCacheData(const MeasureFormatCacheData &other);
1552e5b6d6dSopenharmony_ci    MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
1562e5b6d6dSopenharmony_ci};
1572e5b6d6dSopenharmony_ci
1582e5b6d6dSopenharmony_ciMeasureFormatCacheData::MeasureFormatCacheData()
1592e5b6d6dSopenharmony_ci        : integerFormat(nullptr), numericDateFormatters(nullptr) {
1602e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
1612e5b6d6dSopenharmony_ci        widthFallback[i] = UMEASFMT_WIDTH_COUNT;
1622e5b6d6dSopenharmony_ci    }
1632e5b6d6dSopenharmony_ci    memset(currencyFormats, 0, sizeof(currencyFormats));
1642e5b6d6dSopenharmony_ci}
1652e5b6d6dSopenharmony_ci
1662e5b6d6dSopenharmony_ciMeasureFormatCacheData::~MeasureFormatCacheData() {
1672e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
1682e5b6d6dSopenharmony_ci        delete currencyFormats[i];
1692e5b6d6dSopenharmony_ci    }
1702e5b6d6dSopenharmony_ci    // Note: the contents of 'dnams' are pointers into the resource bundle
1712e5b6d6dSopenharmony_ci    delete integerFormat;
1722e5b6d6dSopenharmony_ci    delete numericDateFormatters;
1732e5b6d6dSopenharmony_ci}
1742e5b6d6dSopenharmony_ci
1752e5b6d6dSopenharmony_cistatic UBool isCurrency(const MeasureUnit &unit) {
1762e5b6d6dSopenharmony_ci    return (uprv_strcmp(unit.getType(), "currency") == 0);
1772e5b6d6dSopenharmony_ci}
1782e5b6d6dSopenharmony_ci
1792e5b6d6dSopenharmony_cistatic UBool getString(
1802e5b6d6dSopenharmony_ci        const UResourceBundle *resource,
1812e5b6d6dSopenharmony_ci        UnicodeString &result,
1822e5b6d6dSopenharmony_ci        UErrorCode &status) {
1832e5b6d6dSopenharmony_ci    int32_t len = 0;
1842e5b6d6dSopenharmony_ci    const UChar *resStr = ures_getString(resource, &len, &status);
1852e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
1862e5b6d6dSopenharmony_ci        return false;
1872e5b6d6dSopenharmony_ci    }
1882e5b6d6dSopenharmony_ci    result.setTo(true, resStr, len);
1892e5b6d6dSopenharmony_ci    return true;
1902e5b6d6dSopenharmony_ci}
1912e5b6d6dSopenharmony_ci
1922e5b6d6dSopenharmony_cistatic UnicodeString loadNumericDateFormatterPattern(
1932e5b6d6dSopenharmony_ci        const UResourceBundle *resource,
1942e5b6d6dSopenharmony_ci        const char *pattern,
1952e5b6d6dSopenharmony_ci        UErrorCode &status) {
1962e5b6d6dSopenharmony_ci    UnicodeString result;
1972e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
1982e5b6d6dSopenharmony_ci        return result;
1992e5b6d6dSopenharmony_ci    }
2002e5b6d6dSopenharmony_ci    CharString chs;
2012e5b6d6dSopenharmony_ci    chs.append("durationUnits", status)
2022e5b6d6dSopenharmony_ci            .append("/", status).append(pattern, status);
2032e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer patternBundle(
2042e5b6d6dSopenharmony_ci            ures_getByKeyWithFallback(
2052e5b6d6dSopenharmony_ci                resource,
2062e5b6d6dSopenharmony_ci                chs.data(),
2072e5b6d6dSopenharmony_ci                NULL,
2082e5b6d6dSopenharmony_ci                &status));
2092e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
2102e5b6d6dSopenharmony_ci        return result;
2112e5b6d6dSopenharmony_ci    }
2122e5b6d6dSopenharmony_ci    getString(patternBundle.getAlias(), result, status);
2132e5b6d6dSopenharmony_ci    // Replace 'h' with 'H'
2142e5b6d6dSopenharmony_ci    int32_t len = result.length();
2152e5b6d6dSopenharmony_ci    UChar *buffer = result.getBuffer(len);
2162e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < len; ++i) {
2172e5b6d6dSopenharmony_ci        if (buffer[i] == 0x68) { // 'h'
2182e5b6d6dSopenharmony_ci            buffer[i] = 0x48; // 'H'
2192e5b6d6dSopenharmony_ci        }
2202e5b6d6dSopenharmony_ci    }
2212e5b6d6dSopenharmony_ci    result.releaseBuffer(len);
2222e5b6d6dSopenharmony_ci    return result;
2232e5b6d6dSopenharmony_ci}
2242e5b6d6dSopenharmony_ci
2252e5b6d6dSopenharmony_cistatic NumericDateFormatters *loadNumericDateFormatters(
2262e5b6d6dSopenharmony_ci        const UResourceBundle *resource,
2272e5b6d6dSopenharmony_ci        UErrorCode &status) {
2282e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
2292e5b6d6dSopenharmony_ci        return NULL;
2302e5b6d6dSopenharmony_ci    }
2312e5b6d6dSopenharmony_ci    NumericDateFormatters *result = new NumericDateFormatters(
2322e5b6d6dSopenharmony_ci        loadNumericDateFormatterPattern(resource, "hm", status),
2332e5b6d6dSopenharmony_ci        loadNumericDateFormatterPattern(resource, "ms", status),
2342e5b6d6dSopenharmony_ci        loadNumericDateFormatterPattern(resource, "hms", status));
2352e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
2362e5b6d6dSopenharmony_ci        delete result;
2372e5b6d6dSopenharmony_ci        return NULL;
2382e5b6d6dSopenharmony_ci    }
2392e5b6d6dSopenharmony_ci    return result;
2402e5b6d6dSopenharmony_ci}
2412e5b6d6dSopenharmony_ci
2422e5b6d6dSopenharmony_citemplate<>
2432e5b6d6dSopenharmony_ciconst MeasureFormatCacheData *LocaleCacheKey<MeasureFormatCacheData>::createObject(
2442e5b6d6dSopenharmony_ci        const void * /*unused*/, UErrorCode &status) const {
2452e5b6d6dSopenharmony_ci    const char *localeId = fLoc.getName();
2462e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, localeId, &status));
2472e5b6d6dSopenharmony_ci    static UNumberFormatStyle currencyStyles[] = {
2482e5b6d6dSopenharmony_ci            UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY};
2492e5b6d6dSopenharmony_ci    LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData(), status);
2502e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
2512e5b6d6dSopenharmony_ci        return NULL;
2522e5b6d6dSopenharmony_ci    }
2532e5b6d6dSopenharmony_ci    result->adoptNumericDateFormatters(loadNumericDateFormatters(
2542e5b6d6dSopenharmony_ci            unitsBundle.getAlias(), status));
2552e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
2562e5b6d6dSopenharmony_ci        return NULL;
2572e5b6d6dSopenharmony_ci    }
2582e5b6d6dSopenharmony_ci
2592e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
2602e5b6d6dSopenharmony_ci        // NumberFormat::createInstance can erase warning codes from status, so pass it
2612e5b6d6dSopenharmony_ci        // a separate status instance
2622e5b6d6dSopenharmony_ci        UErrorCode localStatus = U_ZERO_ERROR;
2632e5b6d6dSopenharmony_ci        result->adoptCurrencyFormat(i, NumberFormat::createInstance(
2642e5b6d6dSopenharmony_ci                localeId, currencyStyles[i], localStatus));
2652e5b6d6dSopenharmony_ci        if (localStatus != U_ZERO_ERROR) {
2662e5b6d6dSopenharmony_ci            status = localStatus;
2672e5b6d6dSopenharmony_ci        }
2682e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) {
2692e5b6d6dSopenharmony_ci            return NULL;
2702e5b6d6dSopenharmony_ci        }
2712e5b6d6dSopenharmony_ci    }
2722e5b6d6dSopenharmony_ci    NumberFormat *inf = NumberFormat::createInstance(
2732e5b6d6dSopenharmony_ci            localeId, UNUM_DECIMAL, status);
2742e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
2752e5b6d6dSopenharmony_ci        return NULL;
2762e5b6d6dSopenharmony_ci    }
2772e5b6d6dSopenharmony_ci    inf->setMaximumFractionDigits(0);
2782e5b6d6dSopenharmony_ci    DecimalFormat *decfmt = dynamic_cast<DecimalFormat *>(inf);
2792e5b6d6dSopenharmony_ci    if (decfmt != NULL) {
2802e5b6d6dSopenharmony_ci        decfmt->setRoundingMode(DecimalFormat::kRoundDown);
2812e5b6d6dSopenharmony_ci    }
2822e5b6d6dSopenharmony_ci    result->adoptIntegerFormat(inf);
2832e5b6d6dSopenharmony_ci    result->addRef();
2842e5b6d6dSopenharmony_ci    return result.orphan();
2852e5b6d6dSopenharmony_ci}
2862e5b6d6dSopenharmony_ci
2872e5b6d6dSopenharmony_cistatic UBool isTimeUnit(const MeasureUnit &mu, const char *tu) {
2882e5b6d6dSopenharmony_ci    return uprv_strcmp(mu.getType(), "duration") == 0 &&
2892e5b6d6dSopenharmony_ci            uprv_strcmp(mu.getSubtype(), tu) == 0;
2902e5b6d6dSopenharmony_ci}
2912e5b6d6dSopenharmony_ci
2922e5b6d6dSopenharmony_ci// Converts a composite measure into hours-minutes-seconds and stores at hms
2932e5b6d6dSopenharmony_ci// array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
2942e5b6d6dSopenharmony_ci// units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
2952e5b6d6dSopenharmony_ci// contains hours-minutes, this function would return 3.
2962e5b6d6dSopenharmony_ci//
2972e5b6d6dSopenharmony_ci// If measures cannot be converted into hours, minutes, seconds or if amounts
2982e5b6d6dSopenharmony_ci// are negative, or if hours, minutes, seconds are out of order, returns 0.
2992e5b6d6dSopenharmony_cistatic int32_t toHMS(
3002e5b6d6dSopenharmony_ci        const Measure *measures,
3012e5b6d6dSopenharmony_ci        int32_t measureCount,
3022e5b6d6dSopenharmony_ci        Formattable *hms,
3032e5b6d6dSopenharmony_ci        UErrorCode &status) {
3042e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
3052e5b6d6dSopenharmony_ci        return 0;
3062e5b6d6dSopenharmony_ci    }
3072e5b6d6dSopenharmony_ci    int32_t result = 0;
3082e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
3092e5b6d6dSopenharmony_ci        return 0;
3102e5b6d6dSopenharmony_ci    }
3112e5b6d6dSopenharmony_ci    // We use copy constructor to ensure that both sides of equality operator
3122e5b6d6dSopenharmony_ci    // are instances of MeasureUnit base class and not a subclass. Otherwise,
3132e5b6d6dSopenharmony_ci    // operator== will immediately return false.
3142e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < measureCount; ++i) {
3152e5b6d6dSopenharmony_ci        if (isTimeUnit(measures[i].getUnit(), "hour")) {
3162e5b6d6dSopenharmony_ci            // hour must come first
3172e5b6d6dSopenharmony_ci            if (result >= 1) {
3182e5b6d6dSopenharmony_ci                return 0;
3192e5b6d6dSopenharmony_ci            }
3202e5b6d6dSopenharmony_ci            hms[0] = measures[i].getNumber();
3212e5b6d6dSopenharmony_ci            if (hms[0].getDouble() < 0.0) {
3222e5b6d6dSopenharmony_ci                return 0;
3232e5b6d6dSopenharmony_ci            }
3242e5b6d6dSopenharmony_ci            result |= 1;
3252e5b6d6dSopenharmony_ci        } else if (isTimeUnit(measures[i].getUnit(), "minute")) {
3262e5b6d6dSopenharmony_ci            // minute must come after hour
3272e5b6d6dSopenharmony_ci            if (result >= 2) {
3282e5b6d6dSopenharmony_ci                return 0;
3292e5b6d6dSopenharmony_ci            }
3302e5b6d6dSopenharmony_ci            hms[1] = measures[i].getNumber();
3312e5b6d6dSopenharmony_ci            if (hms[1].getDouble() < 0.0) {
3322e5b6d6dSopenharmony_ci                return 0;
3332e5b6d6dSopenharmony_ci            }
3342e5b6d6dSopenharmony_ci            result |= 2;
3352e5b6d6dSopenharmony_ci        } else if (isTimeUnit(measures[i].getUnit(), "second")) {
3362e5b6d6dSopenharmony_ci            // second must come after hour and minute
3372e5b6d6dSopenharmony_ci            if (result >= 4) {
3382e5b6d6dSopenharmony_ci                return 0;
3392e5b6d6dSopenharmony_ci            }
3402e5b6d6dSopenharmony_ci            hms[2] = measures[i].getNumber();
3412e5b6d6dSopenharmony_ci            if (hms[2].getDouble() < 0.0) {
3422e5b6d6dSopenharmony_ci                return 0;
3432e5b6d6dSopenharmony_ci            }
3442e5b6d6dSopenharmony_ci            result |= 4;
3452e5b6d6dSopenharmony_ci        } else {
3462e5b6d6dSopenharmony_ci            return 0;
3472e5b6d6dSopenharmony_ci        }
3482e5b6d6dSopenharmony_ci    }
3492e5b6d6dSopenharmony_ci    return result;
3502e5b6d6dSopenharmony_ci}
3512e5b6d6dSopenharmony_ci
3522e5b6d6dSopenharmony_ci
3532e5b6d6dSopenharmony_ciMeasureFormat::MeasureFormat(
3542e5b6d6dSopenharmony_ci        const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
3552e5b6d6dSopenharmony_ci        : cache(NULL),
3562e5b6d6dSopenharmony_ci          numberFormat(NULL),
3572e5b6d6dSopenharmony_ci          pluralRules(NULL),
3582e5b6d6dSopenharmony_ci          fWidth(w),
3592e5b6d6dSopenharmony_ci          listFormatter(NULL) {
3602e5b6d6dSopenharmony_ci    initMeasureFormat(locale, w, NULL, status);
3612e5b6d6dSopenharmony_ci}
3622e5b6d6dSopenharmony_ci
3632e5b6d6dSopenharmony_ciMeasureFormat::MeasureFormat(
3642e5b6d6dSopenharmony_ci        const Locale &locale,
3652e5b6d6dSopenharmony_ci        UMeasureFormatWidth w,
3662e5b6d6dSopenharmony_ci        NumberFormat *nfToAdopt,
3672e5b6d6dSopenharmony_ci        UErrorCode &status)
3682e5b6d6dSopenharmony_ci        : cache(NULL),
3692e5b6d6dSopenharmony_ci          numberFormat(NULL),
3702e5b6d6dSopenharmony_ci          pluralRules(NULL),
3712e5b6d6dSopenharmony_ci          fWidth(w),
3722e5b6d6dSopenharmony_ci          listFormatter(NULL) {
3732e5b6d6dSopenharmony_ci    initMeasureFormat(locale, w, nfToAdopt, status);
3742e5b6d6dSopenharmony_ci}
3752e5b6d6dSopenharmony_ci
3762e5b6d6dSopenharmony_ciMeasureFormat::MeasureFormat(const MeasureFormat &other) :
3772e5b6d6dSopenharmony_ci        Format(other),
3782e5b6d6dSopenharmony_ci        cache(other.cache),
3792e5b6d6dSopenharmony_ci        numberFormat(other.numberFormat),
3802e5b6d6dSopenharmony_ci        pluralRules(other.pluralRules),
3812e5b6d6dSopenharmony_ci        fWidth(other.fWidth),
3822e5b6d6dSopenharmony_ci        listFormatter(NULL) {
3832e5b6d6dSopenharmony_ci    cache->addRef();
3842e5b6d6dSopenharmony_ci    numberFormat->addRef();
3852e5b6d6dSopenharmony_ci    pluralRules->addRef();
3862e5b6d6dSopenharmony_ci    if (other.listFormatter != NULL) {
3872e5b6d6dSopenharmony_ci        listFormatter = new ListFormatter(*other.listFormatter);
3882e5b6d6dSopenharmony_ci    }
3892e5b6d6dSopenharmony_ci}
3902e5b6d6dSopenharmony_ci
3912e5b6d6dSopenharmony_ciMeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
3922e5b6d6dSopenharmony_ci    if (this == &other) {
3932e5b6d6dSopenharmony_ci        return *this;
3942e5b6d6dSopenharmony_ci    }
3952e5b6d6dSopenharmony_ci    Format::operator=(other);
3962e5b6d6dSopenharmony_ci    SharedObject::copyPtr(other.cache, cache);
3972e5b6d6dSopenharmony_ci    SharedObject::copyPtr(other.numberFormat, numberFormat);
3982e5b6d6dSopenharmony_ci    SharedObject::copyPtr(other.pluralRules, pluralRules);
3992e5b6d6dSopenharmony_ci    fWidth = other.fWidth;
4002e5b6d6dSopenharmony_ci    delete listFormatter;
4012e5b6d6dSopenharmony_ci    if (other.listFormatter != NULL) {
4022e5b6d6dSopenharmony_ci        listFormatter = new ListFormatter(*other.listFormatter);
4032e5b6d6dSopenharmony_ci    } else {
4042e5b6d6dSopenharmony_ci        listFormatter = NULL;
4052e5b6d6dSopenharmony_ci    }
4062e5b6d6dSopenharmony_ci    return *this;
4072e5b6d6dSopenharmony_ci}
4082e5b6d6dSopenharmony_ci
4092e5b6d6dSopenharmony_ciMeasureFormat::MeasureFormat() :
4102e5b6d6dSopenharmony_ci        cache(NULL),
4112e5b6d6dSopenharmony_ci        numberFormat(NULL),
4122e5b6d6dSopenharmony_ci        pluralRules(NULL),
4132e5b6d6dSopenharmony_ci        fWidth(UMEASFMT_WIDTH_SHORT),
4142e5b6d6dSopenharmony_ci        listFormatter(NULL) {
4152e5b6d6dSopenharmony_ci}
4162e5b6d6dSopenharmony_ci
4172e5b6d6dSopenharmony_ciMeasureFormat::~MeasureFormat() {
4182e5b6d6dSopenharmony_ci    if (cache != NULL) {
4192e5b6d6dSopenharmony_ci        cache->removeRef();
4202e5b6d6dSopenharmony_ci    }
4212e5b6d6dSopenharmony_ci    if (numberFormat != NULL) {
4222e5b6d6dSopenharmony_ci        numberFormat->removeRef();
4232e5b6d6dSopenharmony_ci    }
4242e5b6d6dSopenharmony_ci    if (pluralRules != NULL) {
4252e5b6d6dSopenharmony_ci        pluralRules->removeRef();
4262e5b6d6dSopenharmony_ci    }
4272e5b6d6dSopenharmony_ci    delete listFormatter;
4282e5b6d6dSopenharmony_ci}
4292e5b6d6dSopenharmony_ci
4302e5b6d6dSopenharmony_cibool MeasureFormat::operator==(const Format &other) const {
4312e5b6d6dSopenharmony_ci    if (this == &other) { // Same object, equal
4322e5b6d6dSopenharmony_ci        return true;
4332e5b6d6dSopenharmony_ci    }
4342e5b6d6dSopenharmony_ci    if (!Format::operator==(other)) {
4352e5b6d6dSopenharmony_ci        return false;
4362e5b6d6dSopenharmony_ci    }
4372e5b6d6dSopenharmony_ci    const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other);
4382e5b6d6dSopenharmony_ci
4392e5b6d6dSopenharmony_ci    // Note: Since the ListFormatter depends only on Locale and width, we
4402e5b6d6dSopenharmony_ci    // don't have to check it here.
4412e5b6d6dSopenharmony_ci
4422e5b6d6dSopenharmony_ci    // differing widths aren't equivalent
4432e5b6d6dSopenharmony_ci    if (fWidth != rhs.fWidth) {
4442e5b6d6dSopenharmony_ci        return false;
4452e5b6d6dSopenharmony_ci    }
4462e5b6d6dSopenharmony_ci    // Width the same check locales.
4472e5b6d6dSopenharmony_ci    // We don't need to check locales if both objects have same cache.
4482e5b6d6dSopenharmony_ci    if (cache != rhs.cache) {
4492e5b6d6dSopenharmony_ci        UErrorCode status = U_ZERO_ERROR;
4502e5b6d6dSopenharmony_ci        const char *localeId = getLocaleID(status);
4512e5b6d6dSopenharmony_ci        const char *rhsLocaleId = rhs.getLocaleID(status);
4522e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) {
4532e5b6d6dSopenharmony_ci            // On failure, assume not equal
4542e5b6d6dSopenharmony_ci            return false;
4552e5b6d6dSopenharmony_ci        }
4562e5b6d6dSopenharmony_ci        if (uprv_strcmp(localeId, rhsLocaleId) != 0) {
4572e5b6d6dSopenharmony_ci            return false;
4582e5b6d6dSopenharmony_ci        }
4592e5b6d6dSopenharmony_ci    }
4602e5b6d6dSopenharmony_ci    // Locales same, check NumberFormat if shared data differs.
4612e5b6d6dSopenharmony_ci    return (
4622e5b6d6dSopenharmony_ci            numberFormat == rhs.numberFormat ||
4632e5b6d6dSopenharmony_ci            **numberFormat == **rhs.numberFormat);
4642e5b6d6dSopenharmony_ci}
4652e5b6d6dSopenharmony_ci
4662e5b6d6dSopenharmony_ciMeasureFormat *MeasureFormat::clone() const {
4672e5b6d6dSopenharmony_ci    return new MeasureFormat(*this);
4682e5b6d6dSopenharmony_ci}
4692e5b6d6dSopenharmony_ci
4702e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::format(
4712e5b6d6dSopenharmony_ci        const Formattable &obj,
4722e5b6d6dSopenharmony_ci        UnicodeString &appendTo,
4732e5b6d6dSopenharmony_ci        FieldPosition &pos,
4742e5b6d6dSopenharmony_ci        UErrorCode &status) const {
4752e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) return appendTo;
4762e5b6d6dSopenharmony_ci    if (obj.getType() == Formattable::kObject) {
4772e5b6d6dSopenharmony_ci        const UObject* formatObj = obj.getObject();
4782e5b6d6dSopenharmony_ci        const Measure* amount = dynamic_cast<const Measure*>(formatObj);
4792e5b6d6dSopenharmony_ci        if (amount != NULL) {
4802e5b6d6dSopenharmony_ci            return formatMeasure(
4812e5b6d6dSopenharmony_ci                    *amount, **numberFormat, appendTo, pos, status);
4822e5b6d6dSopenharmony_ci        }
4832e5b6d6dSopenharmony_ci    }
4842e5b6d6dSopenharmony_ci    status = U_ILLEGAL_ARGUMENT_ERROR;
4852e5b6d6dSopenharmony_ci    return appendTo;
4862e5b6d6dSopenharmony_ci}
4872e5b6d6dSopenharmony_ci
4882e5b6d6dSopenharmony_civoid MeasureFormat::parseObject(
4892e5b6d6dSopenharmony_ci        const UnicodeString & /*source*/,
4902e5b6d6dSopenharmony_ci        Formattable & /*result*/,
4912e5b6d6dSopenharmony_ci        ParsePosition& /*pos*/) const {
4922e5b6d6dSopenharmony_ci    return;
4932e5b6d6dSopenharmony_ci}
4942e5b6d6dSopenharmony_ci
4952e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatMeasurePerUnit(
4962e5b6d6dSopenharmony_ci        const Measure &measure,
4972e5b6d6dSopenharmony_ci        const MeasureUnit &perUnit,
4982e5b6d6dSopenharmony_ci        UnicodeString &appendTo,
4992e5b6d6dSopenharmony_ci        FieldPosition &pos,
5002e5b6d6dSopenharmony_ci        UErrorCode &status) const {
5012e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
5022e5b6d6dSopenharmony_ci        return appendTo;
5032e5b6d6dSopenharmony_ci    }
5042e5b6d6dSopenharmony_ci    auto* df = dynamic_cast<const DecimalFormat*>(&getNumberFormatInternal());
5052e5b6d6dSopenharmony_ci    if (df == nullptr) {
5062e5b6d6dSopenharmony_ci        // Don't know how to handle other types of NumberFormat
5072e5b6d6dSopenharmony_ci        status = U_UNSUPPORTED_ERROR;
5082e5b6d6dSopenharmony_ci        return appendTo;
5092e5b6d6dSopenharmony_ci    }
5102e5b6d6dSopenharmony_ci    UFormattedNumberData result;
5112e5b6d6dSopenharmony_ci    if (auto* lnf = df->toNumberFormatter(status)) {
5122e5b6d6dSopenharmony_ci        result.quantity.setToDouble(measure.getNumber().getDouble(status));
5132e5b6d6dSopenharmony_ci        lnf->unit(measure.getUnit())
5142e5b6d6dSopenharmony_ci            .perUnit(perUnit)
5152e5b6d6dSopenharmony_ci            .unitWidth(getUnitWidth(fWidth))
5162e5b6d6dSopenharmony_ci            .formatImpl(&result, status);
5172e5b6d6dSopenharmony_ci    }
5182e5b6d6dSopenharmony_ci    DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
5192e5b6d6dSopenharmony_ci    appendTo.append(result.toTempString(status));
5202e5b6d6dSopenharmony_ci    return appendTo;
5212e5b6d6dSopenharmony_ci}
5222e5b6d6dSopenharmony_ci
5232e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatMeasures(
5242e5b6d6dSopenharmony_ci        const Measure *measures,
5252e5b6d6dSopenharmony_ci        int32_t measureCount,
5262e5b6d6dSopenharmony_ci        UnicodeString &appendTo,
5272e5b6d6dSopenharmony_ci        FieldPosition &pos,
5282e5b6d6dSopenharmony_ci        UErrorCode &status) const {
5292e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
5302e5b6d6dSopenharmony_ci        return appendTo;
5312e5b6d6dSopenharmony_ci    }
5322e5b6d6dSopenharmony_ci    if (measureCount == 0) {
5332e5b6d6dSopenharmony_ci        return appendTo;
5342e5b6d6dSopenharmony_ci    }
5352e5b6d6dSopenharmony_ci    if (measureCount == 1) {
5362e5b6d6dSopenharmony_ci        return formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
5372e5b6d6dSopenharmony_ci    }
5382e5b6d6dSopenharmony_ci    if (fWidth == UMEASFMT_WIDTH_NUMERIC) {
5392e5b6d6dSopenharmony_ci        Formattable hms[3];
5402e5b6d6dSopenharmony_ci        int32_t bitMap = toHMS(measures, measureCount, hms, status);
5412e5b6d6dSopenharmony_ci        if (bitMap > 0) {
5422e5b6d6dSopenharmony_ci            return formatNumeric(hms, bitMap, appendTo, status);
5432e5b6d6dSopenharmony_ci        }
5442e5b6d6dSopenharmony_ci    }
5452e5b6d6dSopenharmony_ci    if (pos.getField() != FieldPosition::DONT_CARE) {
5462e5b6d6dSopenharmony_ci        return formatMeasuresSlowTrack(
5472e5b6d6dSopenharmony_ci                measures, measureCount, appendTo, pos, status);
5482e5b6d6dSopenharmony_ci    }
5492e5b6d6dSopenharmony_ci    UnicodeString *results = new UnicodeString[measureCount];
5502e5b6d6dSopenharmony_ci    if (results == NULL) {
5512e5b6d6dSopenharmony_ci        status = U_MEMORY_ALLOCATION_ERROR;
5522e5b6d6dSopenharmony_ci        return appendTo;
5532e5b6d6dSopenharmony_ci    }
5542e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < measureCount; ++i) {
5552e5b6d6dSopenharmony_ci        const NumberFormat *nf = cache->getIntegerFormat();
5562e5b6d6dSopenharmony_ci        if (i == measureCount - 1) {
5572e5b6d6dSopenharmony_ci            nf = numberFormat->get();
5582e5b6d6dSopenharmony_ci        }
5592e5b6d6dSopenharmony_ci        formatMeasure(
5602e5b6d6dSopenharmony_ci                measures[i],
5612e5b6d6dSopenharmony_ci                *nf,
5622e5b6d6dSopenharmony_ci                results[i],
5632e5b6d6dSopenharmony_ci                pos,
5642e5b6d6dSopenharmony_ci                status);
5652e5b6d6dSopenharmony_ci    }
5662e5b6d6dSopenharmony_ci    listFormatter->format(results, measureCount, appendTo, status);
5672e5b6d6dSopenharmony_ci    delete [] results;
5682e5b6d6dSopenharmony_ci    return appendTo;
5692e5b6d6dSopenharmony_ci}
5702e5b6d6dSopenharmony_ci
5712e5b6d6dSopenharmony_ciUnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& status) const {
5722e5b6d6dSopenharmony_ci    return number::impl::LongNameHandler::getUnitDisplayName(
5732e5b6d6dSopenharmony_ci        getLocale(status),
5742e5b6d6dSopenharmony_ci        unit,
5752e5b6d6dSopenharmony_ci        getUnitWidth(fWidth),
5762e5b6d6dSopenharmony_ci        status);
5772e5b6d6dSopenharmony_ci}
5782e5b6d6dSopenharmony_ci
5792e5b6d6dSopenharmony_civoid MeasureFormat::initMeasureFormat(
5802e5b6d6dSopenharmony_ci        const Locale &locale,
5812e5b6d6dSopenharmony_ci        UMeasureFormatWidth w,
5822e5b6d6dSopenharmony_ci        NumberFormat *nfToAdopt,
5832e5b6d6dSopenharmony_ci        UErrorCode &status) {
5842e5b6d6dSopenharmony_ci    static const UListFormatterWidth listWidths[] = {
5852e5b6d6dSopenharmony_ci        ULISTFMT_WIDTH_WIDE,
5862e5b6d6dSopenharmony_ci        ULISTFMT_WIDTH_SHORT,
5872e5b6d6dSopenharmony_ci        ULISTFMT_WIDTH_NARROW};
5882e5b6d6dSopenharmony_ci    LocalPointer<NumberFormat> nf(nfToAdopt);
5892e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
5902e5b6d6dSopenharmony_ci        return;
5912e5b6d6dSopenharmony_ci    }
5922e5b6d6dSopenharmony_ci    const char *name = locale.getName();
5932e5b6d6dSopenharmony_ci    setLocaleIDs(name, name);
5942e5b6d6dSopenharmony_ci
5952e5b6d6dSopenharmony_ci    UnifiedCache::getByLocale(locale, cache, status);
5962e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
5972e5b6d6dSopenharmony_ci        return;
5982e5b6d6dSopenharmony_ci    }
5992e5b6d6dSopenharmony_ci
6002e5b6d6dSopenharmony_ci    const SharedPluralRules *pr = PluralRules::createSharedInstance(
6012e5b6d6dSopenharmony_ci            locale, UPLURAL_TYPE_CARDINAL, status);
6022e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
6032e5b6d6dSopenharmony_ci        return;
6042e5b6d6dSopenharmony_ci    }
6052e5b6d6dSopenharmony_ci    SharedObject::copyPtr(pr, pluralRules);
6062e5b6d6dSopenharmony_ci    pr->removeRef();
6072e5b6d6dSopenharmony_ci    if (nf.isNull()) {
6082e5b6d6dSopenharmony_ci        // TODO: Clean this up
6092e5b6d6dSopenharmony_ci        const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
6102e5b6d6dSopenharmony_ci                locale, UNUM_DECIMAL, status);
6112e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) {
6122e5b6d6dSopenharmony_ci            return;
6132e5b6d6dSopenharmony_ci        }
6142e5b6d6dSopenharmony_ci        SharedObject::copyPtr(shared, numberFormat);
6152e5b6d6dSopenharmony_ci        shared->removeRef();
6162e5b6d6dSopenharmony_ci    } else {
6172e5b6d6dSopenharmony_ci        adoptNumberFormat(nf.orphan(), status);
6182e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) {
6192e5b6d6dSopenharmony_ci            return;
6202e5b6d6dSopenharmony_ci        }
6212e5b6d6dSopenharmony_ci    }
6222e5b6d6dSopenharmony_ci    fWidth = w;
6232e5b6d6dSopenharmony_ci    delete listFormatter;
6242e5b6d6dSopenharmony_ci    listFormatter = ListFormatter::createInstance(
6252e5b6d6dSopenharmony_ci            locale,
6262e5b6d6dSopenharmony_ci            ULISTFMT_TYPE_UNITS,
6272e5b6d6dSopenharmony_ci            listWidths[getRegularWidth(fWidth)],
6282e5b6d6dSopenharmony_ci            status);
6292e5b6d6dSopenharmony_ci}
6302e5b6d6dSopenharmony_ci
6312e5b6d6dSopenharmony_civoid MeasureFormat::adoptNumberFormat(
6322e5b6d6dSopenharmony_ci        NumberFormat *nfToAdopt, UErrorCode &status) {
6332e5b6d6dSopenharmony_ci    LocalPointer<NumberFormat> nf(nfToAdopt);
6342e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
6352e5b6d6dSopenharmony_ci        return;
6362e5b6d6dSopenharmony_ci    }
6372e5b6d6dSopenharmony_ci    SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
6382e5b6d6dSopenharmony_ci    if (shared == NULL) {
6392e5b6d6dSopenharmony_ci        status = U_MEMORY_ALLOCATION_ERROR;
6402e5b6d6dSopenharmony_ci        return;
6412e5b6d6dSopenharmony_ci    }
6422e5b6d6dSopenharmony_ci    nf.orphan();
6432e5b6d6dSopenharmony_ci    SharedObject::copyPtr(shared, numberFormat);
6442e5b6d6dSopenharmony_ci}
6452e5b6d6dSopenharmony_ci
6462e5b6d6dSopenharmony_ciUBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) {
6472e5b6d6dSopenharmony_ci    if (U_FAILURE(status) || locale == getLocale(status)) {
6482e5b6d6dSopenharmony_ci        return false;
6492e5b6d6dSopenharmony_ci    }
6502e5b6d6dSopenharmony_ci    initMeasureFormat(locale, fWidth, NULL, status);
6512e5b6d6dSopenharmony_ci    return U_SUCCESS(status);
6522e5b6d6dSopenharmony_ci}
6532e5b6d6dSopenharmony_ci
6542e5b6d6dSopenharmony_ciconst NumberFormat &MeasureFormat::getNumberFormatInternal() const {
6552e5b6d6dSopenharmony_ci    return **numberFormat;
6562e5b6d6dSopenharmony_ci}
6572e5b6d6dSopenharmony_ci
6582e5b6d6dSopenharmony_ciconst NumberFormat &MeasureFormat::getCurrencyFormatInternal() const {
6592e5b6d6dSopenharmony_ci    return *cache->getCurrencyFormat(UMEASFMT_WIDTH_NARROW);
6602e5b6d6dSopenharmony_ci}
6612e5b6d6dSopenharmony_ci
6622e5b6d6dSopenharmony_ciconst PluralRules &MeasureFormat::getPluralRules() const {
6632e5b6d6dSopenharmony_ci    return **pluralRules;
6642e5b6d6dSopenharmony_ci}
6652e5b6d6dSopenharmony_ci
6662e5b6d6dSopenharmony_ciLocale MeasureFormat::getLocale(UErrorCode &status) const {
6672e5b6d6dSopenharmony_ci    return Format::getLocale(ULOC_VALID_LOCALE, status);
6682e5b6d6dSopenharmony_ci}
6692e5b6d6dSopenharmony_ci
6702e5b6d6dSopenharmony_ciconst char *MeasureFormat::getLocaleID(UErrorCode &status) const {
6712e5b6d6dSopenharmony_ci    return Format::getLocaleID(ULOC_VALID_LOCALE, status);
6722e5b6d6dSopenharmony_ci}
6732e5b6d6dSopenharmony_ci
6742e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatMeasure(
6752e5b6d6dSopenharmony_ci        const Measure &measure,
6762e5b6d6dSopenharmony_ci        const NumberFormat &nf,
6772e5b6d6dSopenharmony_ci        UnicodeString &appendTo,
6782e5b6d6dSopenharmony_ci        FieldPosition &pos,
6792e5b6d6dSopenharmony_ci        UErrorCode &status) const {
6802e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
6812e5b6d6dSopenharmony_ci        return appendTo;
6822e5b6d6dSopenharmony_ci    }
6832e5b6d6dSopenharmony_ci    const Formattable& amtNumber = measure.getNumber();
6842e5b6d6dSopenharmony_ci    const MeasureUnit& amtUnit = measure.getUnit();
6852e5b6d6dSopenharmony_ci    if (isCurrency(amtUnit)) {
6862e5b6d6dSopenharmony_ci        UChar isoCode[4];
6872e5b6d6dSopenharmony_ci        u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
6882e5b6d6dSopenharmony_ci        return cache->getCurrencyFormat(fWidth)->format(
6892e5b6d6dSopenharmony_ci                new CurrencyAmount(amtNumber, isoCode, status),
6902e5b6d6dSopenharmony_ci                appendTo,
6912e5b6d6dSopenharmony_ci                pos,
6922e5b6d6dSopenharmony_ci                status);
6932e5b6d6dSopenharmony_ci    }
6942e5b6d6dSopenharmony_ci    auto* df = dynamic_cast<const DecimalFormat*>(&nf);
6952e5b6d6dSopenharmony_ci    if (df == nullptr) {
6962e5b6d6dSopenharmony_ci        // Handle other types of NumberFormat using the ICU 63 code, modified to
6972e5b6d6dSopenharmony_ci        // get the unitPattern from LongNameHandler and handle fallback to OTHER.
6982e5b6d6dSopenharmony_ci        UnicodeString formattedNumber;
6992e5b6d6dSopenharmony_ci        StandardPlural::Form pluralForm = QuantityFormatter::selectPlural(
7002e5b6d6dSopenharmony_ci                amtNumber, nf, **pluralRules, formattedNumber, pos, status);
7012e5b6d6dSopenharmony_ci        UnicodeString pattern = number::impl::LongNameHandler::getUnitPattern(getLocale(status),
7022e5b6d6dSopenharmony_ci                amtUnit, getUnitWidth(fWidth), pluralForm, status);
7032e5b6d6dSopenharmony_ci        // The above  handles fallback from other widths to short, and from other plural forms to OTHER
7042e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) {
7052e5b6d6dSopenharmony_ci            return appendTo;
7062e5b6d6dSopenharmony_ci        }
7072e5b6d6dSopenharmony_ci        SimpleFormatter formatter(pattern, 0, 1, status);
7082e5b6d6dSopenharmony_ci        return QuantityFormatter::format(formatter, formattedNumber, appendTo, pos, status);
7092e5b6d6dSopenharmony_ci    }
7102e5b6d6dSopenharmony_ci    UFormattedNumberData result;
7112e5b6d6dSopenharmony_ci    if (auto* lnf = df->toNumberFormatter(status)) {
7122e5b6d6dSopenharmony_ci        result.quantity.setToDouble(amtNumber.getDouble(status));
7132e5b6d6dSopenharmony_ci        lnf->unit(amtUnit)
7142e5b6d6dSopenharmony_ci            .unitWidth(getUnitWidth(fWidth))
7152e5b6d6dSopenharmony_ci            .formatImpl(&result, status);
7162e5b6d6dSopenharmony_ci    }
7172e5b6d6dSopenharmony_ci    DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
7182e5b6d6dSopenharmony_ci    appendTo.append(result.toTempString(status));
7192e5b6d6dSopenharmony_ci    return appendTo;
7202e5b6d6dSopenharmony_ci}
7212e5b6d6dSopenharmony_ci
7222e5b6d6dSopenharmony_ci
7232e5b6d6dSopenharmony_ci// Formats numeric time duration as 5:00:47 or 3:54.
7242e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatNumeric(
7252e5b6d6dSopenharmony_ci        const Formattable *hms,  // always length 3
7262e5b6d6dSopenharmony_ci        int32_t bitMap,   // 1=hour set, 2=minute set, 4=second set
7272e5b6d6dSopenharmony_ci        UnicodeString &appendTo,
7282e5b6d6dSopenharmony_ci        UErrorCode &status) const {
7292e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
7302e5b6d6dSopenharmony_ci        return appendTo;
7312e5b6d6dSopenharmony_ci    }
7322e5b6d6dSopenharmony_ci
7332e5b6d6dSopenharmony_ci    UnicodeString pattern;
7342e5b6d6dSopenharmony_ci
7352e5b6d6dSopenharmony_ci    double hours = hms[0].getDouble(status);
7362e5b6d6dSopenharmony_ci    double minutes = hms[1].getDouble(status);
7372e5b6d6dSopenharmony_ci    double seconds = hms[2].getDouble(status);
7382e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
7392e5b6d6dSopenharmony_ci        return appendTo;
7402e5b6d6dSopenharmony_ci    }
7412e5b6d6dSopenharmony_ci
7422e5b6d6dSopenharmony_ci    // All possible combinations: "h", "m", "s", "hm", "hs", "ms", "hms"
7432e5b6d6dSopenharmony_ci    if (bitMap == 5 || bitMap == 7) { // "hms" & "hs" (we add minutes if "hs")
7442e5b6d6dSopenharmony_ci        pattern = cache->getNumericDateFormatters()->hourMinuteSecond;
7452e5b6d6dSopenharmony_ci        hours = uprv_trunc(hours);
7462e5b6d6dSopenharmony_ci        minutes = uprv_trunc(minutes);
7472e5b6d6dSopenharmony_ci    } else if (bitMap == 3) { // "hm"
7482e5b6d6dSopenharmony_ci        pattern = cache->getNumericDateFormatters()->hourMinute;
7492e5b6d6dSopenharmony_ci        hours = uprv_trunc(hours);
7502e5b6d6dSopenharmony_ci    } else if (bitMap == 6) { // "ms"
7512e5b6d6dSopenharmony_ci        pattern = cache->getNumericDateFormatters()->minuteSecond;
7522e5b6d6dSopenharmony_ci        minutes = uprv_trunc(minutes);
7532e5b6d6dSopenharmony_ci    } else { // h m s, handled outside formatNumeric. No value is also an error.
7542e5b6d6dSopenharmony_ci        status = U_INTERNAL_PROGRAM_ERROR;
7552e5b6d6dSopenharmony_ci        return appendTo;
7562e5b6d6dSopenharmony_ci    }
7572e5b6d6dSopenharmony_ci
7582e5b6d6dSopenharmony_ci    const DecimalFormat *numberFormatter = dynamic_cast<const DecimalFormat*>(numberFormat->get());
7592e5b6d6dSopenharmony_ci    if (!numberFormatter) {
7602e5b6d6dSopenharmony_ci        status = U_INTERNAL_PROGRAM_ERROR;
7612e5b6d6dSopenharmony_ci        return appendTo;
7622e5b6d6dSopenharmony_ci    }
7632e5b6d6dSopenharmony_ci    number::LocalizedNumberFormatter numberFormatter2;
7642e5b6d6dSopenharmony_ci    if (auto* lnf = numberFormatter->toNumberFormatter(status)) {
7652e5b6d6dSopenharmony_ci        numberFormatter2 = lnf->integerWidth(number::IntegerWidth::zeroFillTo(2));
7662e5b6d6dSopenharmony_ci    } else {
7672e5b6d6dSopenharmony_ci        return appendTo;
7682e5b6d6dSopenharmony_ci    }
7692e5b6d6dSopenharmony_ci
7702e5b6d6dSopenharmony_ci    FormattedStringBuilder fsb;
7712e5b6d6dSopenharmony_ci
7722e5b6d6dSopenharmony_ci    UBool protect = false;
7732e5b6d6dSopenharmony_ci    const int32_t patternLength = pattern.length();
7742e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < patternLength; i++) {
7752e5b6d6dSopenharmony_ci        char16_t c = pattern[i];
7762e5b6d6dSopenharmony_ci
7772e5b6d6dSopenharmony_ci        // Also set the proper field in this switch
7782e5b6d6dSopenharmony_ci        // We don't use DateFormat.Field because this is not a date / time, is a duration.
7792e5b6d6dSopenharmony_ci        double value = 0;
7802e5b6d6dSopenharmony_ci        switch (c) {
7812e5b6d6dSopenharmony_ci            case u'H': value = hours; break;
7822e5b6d6dSopenharmony_ci            case u'm': value = minutes; break;
7832e5b6d6dSopenharmony_ci            case u's': value = seconds; break;
7842e5b6d6dSopenharmony_ci        }
7852e5b6d6dSopenharmony_ci
7862e5b6d6dSopenharmony_ci        // There is not enough info to add Field(s) for the unit because all we have are plain
7872e5b6d6dSopenharmony_ci        // text patterns. For example in "21:51" there is no text for something like "hour",
7882e5b6d6dSopenharmony_ci        // while in something like "21h51" there is ("h"). But we can't really tell...
7892e5b6d6dSopenharmony_ci        switch (c) {
7902e5b6d6dSopenharmony_ci            case u'H':
7912e5b6d6dSopenharmony_ci            case u'm':
7922e5b6d6dSopenharmony_ci            case u's':
7932e5b6d6dSopenharmony_ci                if (protect) {
7942e5b6d6dSopenharmony_ci                    fsb.appendChar16(c, kUndefinedField, status);
7952e5b6d6dSopenharmony_ci                } else {
7962e5b6d6dSopenharmony_ci                    UnicodeString tmp;
7972e5b6d6dSopenharmony_ci                    if ((i + 1 < patternLength) && pattern[i + 1] == c) { // doubled
7982e5b6d6dSopenharmony_ci                        tmp = numberFormatter2.formatDouble(value, status).toString(status);
7992e5b6d6dSopenharmony_ci                        i++;
8002e5b6d6dSopenharmony_ci                    } else {
8012e5b6d6dSopenharmony_ci                        numberFormatter->format(value, tmp, status);
8022e5b6d6dSopenharmony_ci                    }
8032e5b6d6dSopenharmony_ci                    // TODO: Use proper Field
8042e5b6d6dSopenharmony_ci                    fsb.append(tmp, kUndefinedField, status);
8052e5b6d6dSopenharmony_ci                }
8062e5b6d6dSopenharmony_ci                break;
8072e5b6d6dSopenharmony_ci            case u'\'':
8082e5b6d6dSopenharmony_ci                // '' is escaped apostrophe
8092e5b6d6dSopenharmony_ci                if ((i + 1 < patternLength) && pattern[i + 1] == c) {
8102e5b6d6dSopenharmony_ci                    fsb.appendChar16(c, kUndefinedField, status);
8112e5b6d6dSopenharmony_ci                    i++;
8122e5b6d6dSopenharmony_ci                } else {
8132e5b6d6dSopenharmony_ci                    protect = !protect;
8142e5b6d6dSopenharmony_ci                }
8152e5b6d6dSopenharmony_ci                break;
8162e5b6d6dSopenharmony_ci            default:
8172e5b6d6dSopenharmony_ci                fsb.appendChar16(c, kUndefinedField, status);
8182e5b6d6dSopenharmony_ci        }
8192e5b6d6dSopenharmony_ci    }
8202e5b6d6dSopenharmony_ci
8212e5b6d6dSopenharmony_ci    appendTo.append(fsb.toTempUnicodeString());
8222e5b6d6dSopenharmony_ci
8232e5b6d6dSopenharmony_ci    return appendTo;
8242e5b6d6dSopenharmony_ci}
8252e5b6d6dSopenharmony_ci
8262e5b6d6dSopenharmony_ciUnicodeString &MeasureFormat::formatMeasuresSlowTrack(
8272e5b6d6dSopenharmony_ci        const Measure *measures,
8282e5b6d6dSopenharmony_ci        int32_t measureCount,
8292e5b6d6dSopenharmony_ci        UnicodeString& appendTo,
8302e5b6d6dSopenharmony_ci        FieldPosition& pos,
8312e5b6d6dSopenharmony_ci        UErrorCode& status) const {
8322e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
8332e5b6d6dSopenharmony_ci        return appendTo;
8342e5b6d6dSopenharmony_ci    }
8352e5b6d6dSopenharmony_ci    FieldPosition dontCare(FieldPosition::DONT_CARE);
8362e5b6d6dSopenharmony_ci    FieldPosition fpos(pos.getField());
8372e5b6d6dSopenharmony_ci    LocalArray<UnicodeString> results(new UnicodeString[measureCount], status);
8382e5b6d6dSopenharmony_ci    int32_t fieldPositionFoundIndex = -1;
8392e5b6d6dSopenharmony_ci    for (int32_t i = 0; i < measureCount; ++i) {
8402e5b6d6dSopenharmony_ci        const NumberFormat *nf = cache->getIntegerFormat();
8412e5b6d6dSopenharmony_ci        if (i == measureCount - 1) {
8422e5b6d6dSopenharmony_ci            nf = numberFormat->get();
8432e5b6d6dSopenharmony_ci        }
8442e5b6d6dSopenharmony_ci        if (fieldPositionFoundIndex == -1) {
8452e5b6d6dSopenharmony_ci            formatMeasure(measures[i], *nf, results[i], fpos, status);
8462e5b6d6dSopenharmony_ci            if (U_FAILURE(status)) {
8472e5b6d6dSopenharmony_ci                return appendTo;
8482e5b6d6dSopenharmony_ci            }
8492e5b6d6dSopenharmony_ci            if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
8502e5b6d6dSopenharmony_ci                fieldPositionFoundIndex = i;
8512e5b6d6dSopenharmony_ci            }
8522e5b6d6dSopenharmony_ci        } else {
8532e5b6d6dSopenharmony_ci            formatMeasure(measures[i], *nf, results[i], dontCare, status);
8542e5b6d6dSopenharmony_ci        }
8552e5b6d6dSopenharmony_ci    }
8562e5b6d6dSopenharmony_ci    int32_t offset;
8572e5b6d6dSopenharmony_ci    listFormatter->format(
8582e5b6d6dSopenharmony_ci            results.getAlias(),
8592e5b6d6dSopenharmony_ci            measureCount,
8602e5b6d6dSopenharmony_ci            appendTo,
8612e5b6d6dSopenharmony_ci            fieldPositionFoundIndex,
8622e5b6d6dSopenharmony_ci            offset,
8632e5b6d6dSopenharmony_ci            status);
8642e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) {
8652e5b6d6dSopenharmony_ci        return appendTo;
8662e5b6d6dSopenharmony_ci    }
8672e5b6d6dSopenharmony_ci    // Fix up FieldPosition indexes if our field is found.
8682e5b6d6dSopenharmony_ci    if (fieldPositionFoundIndex != -1 && offset != -1) {
8692e5b6d6dSopenharmony_ci        pos.setBeginIndex(fpos.getBeginIndex() + offset);
8702e5b6d6dSopenharmony_ci        pos.setEndIndex(fpos.getEndIndex() + offset);
8712e5b6d6dSopenharmony_ci    }
8722e5b6d6dSopenharmony_ci    return appendTo;
8732e5b6d6dSopenharmony_ci}
8742e5b6d6dSopenharmony_ci
8752e5b6d6dSopenharmony_ciMeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
8762e5b6d6dSopenharmony_ci                                                   UErrorCode& ec) {
8772e5b6d6dSopenharmony_ci    if (U_FAILURE(ec)) {
8782e5b6d6dSopenharmony_ci        return nullptr;
8792e5b6d6dSopenharmony_ci    }
8802e5b6d6dSopenharmony_ci    LocalPointer<CurrencyFormat> fmt(new CurrencyFormat(locale, ec), ec);
8812e5b6d6dSopenharmony_ci    return fmt.orphan();
8822e5b6d6dSopenharmony_ci}
8832e5b6d6dSopenharmony_ci
8842e5b6d6dSopenharmony_ciMeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
8852e5b6d6dSopenharmony_ci    if (U_FAILURE(ec)) {
8862e5b6d6dSopenharmony_ci        return nullptr;
8872e5b6d6dSopenharmony_ci    }
8882e5b6d6dSopenharmony_ci    return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
8892e5b6d6dSopenharmony_ci}
8902e5b6d6dSopenharmony_ci
8912e5b6d6dSopenharmony_ciU_NAMESPACE_END
8922e5b6d6dSopenharmony_ci
8932e5b6d6dSopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */
894