Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 * Copyright (C) 1997-2015, International Business Machines Corporation and    *
      4 * others. All Rights Reserved.                                                *
      5 *******************************************************************************
      6 *
      7 * File COMPACTDECIMALFORMAT.CPP
      8 *
      9 ********************************************************************************
     10 */
     11 #include "unicode/utypes.h"
     12 
     13 #if !UCONFIG_NO_FORMATTING
     14 
     15 #include "charstr.h"
     16 #include "cstring.h"
     17 #include "digitlst.h"
     18 #include "mutex.h"
     19 #include "unicode/compactdecimalformat.h"
     20 #include "unicode/numsys.h"
     21 #include "unicode/plurrule.h"
     22 #include "unicode/ures.h"
     23 #include "ucln_in.h"
     24 #include "uhash.h"
     25 #include "umutex.h"
     26 #include "unicode/ures.h"
     27 #include "uresimp.h"
     28 
     29 // Maps locale name to CDFLocaleData struct.
     30 static UHashtable* gCompactDecimalData = NULL;
     31 static UMutex gCompactDecimalMetaLock = U_MUTEX_INITIALIZER;
     32 
     33 U_NAMESPACE_BEGIN
     34 
     35 static const int32_t MAX_DIGITS = 15;
     36 static const char gOther[] = "other";
     37 static const char gLatnTag[] = "latn";
     38 static const char gNumberElementsTag[] = "NumberElements";
     39 static const char gDecimalFormatTag[] = "decimalFormat";
     40 static const char gPatternsShort[] = "patternsShort";
     41 static const char gPatternsLong[] = "patternsLong";
     42 static const char gRoot[] = "root";
     43 
     44 static const UChar u_0 = 0x30;
     45 static const UChar u_apos = 0x27;
     46 
     47 static const UChar kZero[] = {u_0};
     48 
     49 // Used to unescape single quotes.
     50 enum QuoteState {
     51   OUTSIDE,
     52   INSIDE_EMPTY,
     53   INSIDE_FULL
     54 };
     55 
     56 enum FallbackFlags {
     57   ANY = 0,
     58   MUST = 1,
     59   NOT_ROOT = 2
     60   // Next one will be 4 then 6 etc.
     61 };
     62 
     63 
     64 // CDFUnit represents a prefix-suffix pair for a particular variant
     65 // and log10 value.
     66 struct CDFUnit : public UMemory {
     67   UnicodeString prefix;
     68   UnicodeString suffix;
     69   inline CDFUnit() : prefix(), suffix() {
     70     prefix.setToBogus();
     71   }
     72   inline ~CDFUnit() {}
     73   inline UBool isSet() const {
     74     return !prefix.isBogus();
     75   }
     76   inline void markAsSet() {
     77     prefix.remove();
     78   }
     79 };
     80 
     81 // CDFLocaleStyleData contains formatting data for a particular locale
     82 // and style.
     83 class CDFLocaleStyleData : public UMemory {
     84  public:
     85   // What to divide by for each log10 value when formatting. These values
     86   // will be powers of 10. For English, would be:
     87   // 1, 1, 1, 1000, 1000, 1000, 1000000, 1000000, 1000000, 1000000000 ...
     88   double divisors[MAX_DIGITS];
     89   // Maps plural variants to CDFUnit[MAX_DIGITS] arrays.
     90   // To format a number x,
     91   // first compute log10(x). Compute displayNum = (x / divisors[log10(x)]).
     92   // Compute the plural variant for displayNum
     93   // (e.g zero, one, two, few, many, other).
     94   // Compute cdfUnits = unitsByVariant[pluralVariant].
     95   // Prefix and suffix to use at cdfUnits[log10(x)]
     96   UHashtable* unitsByVariant;
     97   inline CDFLocaleStyleData() : unitsByVariant(NULL) {}
     98   ~CDFLocaleStyleData();
     99   // Init initializes this object.
    100   void Init(UErrorCode& status);
    101   inline UBool isBogus() const {
    102     return unitsByVariant == NULL;
    103   }
    104   void setToBogus();
    105  private:
    106   CDFLocaleStyleData(const CDFLocaleStyleData&);
    107   CDFLocaleStyleData& operator=(const CDFLocaleStyleData&);
    108 };
    109 
    110 // CDFLocaleData contains formatting data for a particular locale.
    111 struct CDFLocaleData : public UMemory {
    112   CDFLocaleStyleData shortData;
    113   CDFLocaleStyleData longData;
    114   inline CDFLocaleData() : shortData(), longData() { }
    115   inline ~CDFLocaleData() { }
    116   // Init initializes this object.
    117   void Init(UErrorCode& status);
    118 };
    119 
    120 U_NAMESPACE_END
    121 
    122 U_CDECL_BEGIN
    123 
    124 static UBool U_CALLCONV cdf_cleanup(void) {
    125   if (gCompactDecimalData != NULL) {
    126     uhash_close(gCompactDecimalData);
    127     gCompactDecimalData = NULL;
    128   }
    129   return TRUE;
    130 }
    131 
    132 static void U_CALLCONV deleteCDFUnits(void* ptr) {
    133   delete [] (icu::CDFUnit*) ptr;
    134 }
    135 
    136 static void U_CALLCONV deleteCDFLocaleData(void* ptr) {
    137   delete (icu::CDFLocaleData*) ptr;
    138 }
    139 
    140 U_CDECL_END
    141 
    142 U_NAMESPACE_BEGIN
    143 
    144 static UBool divisors_equal(const double* lhs, const double* rhs);
    145 static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status);
    146 
    147 static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status);
    148 static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status);
    149 static void initCDFLocaleData(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status);
    150 static UResourceBundle* tryGetDecimalFallback(const UResourceBundle* numberSystemResource, const char* style, UResourceBundle** fillIn, FallbackFlags flags, UErrorCode& status);
    151 static UResourceBundle* tryGetByKeyWithFallback(const UResourceBundle* rb, const char* path, UResourceBundle** fillIn, FallbackFlags flags, UErrorCode& status);
    152 static UBool isRoot(const UResourceBundle* rb, UErrorCode& status);
    153 static void initCDFLocaleStyleData(const UResourceBundle* decimalFormatBundle, CDFLocaleStyleData* result, UErrorCode& status);
    154 static void populatePower10(const UResourceBundle* power10Bundle, CDFLocaleStyleData* result, UErrorCode& status);
    155 static int32_t populatePrefixSuffix(const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UErrorCode& status);
    156 static UBool onlySpaces(UnicodeString u);
    157 static void fixQuotes(UnicodeString& s);
    158 static void fillInMissing(CDFLocaleStyleData* result);
    159 static int32_t computeLog10(double x, UBool inRange);
    160 static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status);
    161 static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value);
    162 
    163 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat)
    164 
    165 CompactDecimalFormat::CompactDecimalFormat(
    166     const DecimalFormat& decimalFormat,
    167     const UHashtable* unitsByVariant,
    168     const double* divisors,
    169     PluralRules* pluralRules)
    170   : DecimalFormat(decimalFormat), _unitsByVariant(unitsByVariant), _divisors(divisors), _pluralRules(pluralRules) {
    171 }
    172 
    173 CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source)
    174     : DecimalFormat(source), _unitsByVariant(source._unitsByVariant), _divisors(source._divisors), _pluralRules(source._pluralRules->clone()) {
    175 }
    176 
    177 CompactDecimalFormat* U_EXPORT2
    178 CompactDecimalFormat::createInstance(
    179     const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
    180   LocalPointer<DecimalFormat> decfmt((DecimalFormat*) NumberFormat::makeInstance(inLocale, UNUM_DECIMAL, TRUE, status));
    181   if (U_FAILURE(status)) {
    182     return NULL;
    183   }
    184   LocalPointer<PluralRules> pluralRules(PluralRules::forLocale(inLocale, status));
    185   if (U_FAILURE(status)) {
    186     return NULL;
    187   }
    188   const CDFLocaleStyleData* data = getCDFLocaleStyleData(inLocale, style, status);
    189   if (U_FAILURE(status)) {
    190     return NULL;
    191   }
    192   CompactDecimalFormat* result =
    193       new CompactDecimalFormat(*decfmt, data->unitsByVariant, data->divisors, pluralRules.getAlias());
    194   if (result == NULL) {
    195     status = U_MEMORY_ALLOCATION_ERROR;
    196     return NULL;
    197   }
    198   pluralRules.orphan();
    199   result->setMaximumSignificantDigits(3);
    200   result->setSignificantDigitsUsed(TRUE);
    201   result->setGroupingUsed(FALSE);
    202   return result;
    203 }
    204 
    205 CompactDecimalFormat&
    206 CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) {
    207   if (this != &rhs) {
    208     DecimalFormat::operator=(rhs);
    209     _unitsByVariant = rhs._unitsByVariant;
    210     _divisors = rhs._divisors;
    211     delete _pluralRules;
    212     _pluralRules = rhs._pluralRules->clone();
    213   }
    214   return *this;
    215 }
    216 
    217 CompactDecimalFormat::~CompactDecimalFormat() {
    218   delete _pluralRules;
    219 }
    220 
    221 
    222 Format*
    223 CompactDecimalFormat::clone(void) const {
    224   return new CompactDecimalFormat(*this);
    225 }
    226 
    227 UBool
    228 CompactDecimalFormat::operator==(const Format& that) const {
    229   if (this == &that) {
    230     return TRUE;
    231   }
    232   return (DecimalFormat::operator==(that) && eqHelper((const CompactDecimalFormat&) that));
    233 }
    234 
    235 UBool
    236 CompactDecimalFormat::eqHelper(const CompactDecimalFormat& that) const {
    237   return uhash_equals(_unitsByVariant, that._unitsByVariant) && divisors_equal(_divisors, that._divisors) && (*_pluralRules == *that._pluralRules);
    238 }
    239 
    240 UnicodeString&
    241 CompactDecimalFormat::format(
    242     double number,
    243     UnicodeString& appendTo,
    244     FieldPosition& pos) const {
    245   UErrorCode status = U_ZERO_ERROR;
    246   return format(number, appendTo, pos, status);
    247 }
    248 
    249 UnicodeString&
    250 CompactDecimalFormat::format(
    251     double number,
    252     UnicodeString& appendTo,
    253     FieldPosition& pos,
    254     UErrorCode &status) const {
    255   if (U_FAILURE(status)) {
    256     return appendTo;
    257   }
    258   DigitList orig, rounded;
    259   orig.set(number);
    260   UBool isNegative;
    261   _round(orig, rounded, isNegative, status);
    262   if (U_FAILURE(status)) {
    263     return appendTo;
    264   }
    265   double roundedDouble = rounded.getDouble();
    266   if (isNegative) {
    267     roundedDouble = -roundedDouble;
    268   }
    269   int32_t baseIdx = computeLog10(roundedDouble, TRUE);
    270   double numberToFormat = roundedDouble / _divisors[baseIdx];
    271   UnicodeString variant = _pluralRules->select(numberToFormat);
    272   if (isNegative) {
    273     numberToFormat = -numberToFormat;
    274   }
    275   const CDFUnit* unit = getCDFUnitFallback(_unitsByVariant, variant, baseIdx);
    276   appendTo += unit->prefix;
    277   DecimalFormat::format(numberToFormat, appendTo, pos);
    278   appendTo += unit->suffix;
    279   return appendTo;
    280 }
    281 
    282 UnicodeString&
    283 CompactDecimalFormat::format(
    284     double /* number */,
    285     UnicodeString& appendTo,
    286     FieldPositionIterator* /* posIter */,
    287     UErrorCode& status) const {
    288   status = U_UNSUPPORTED_ERROR;
    289   return appendTo;
    290 }
    291 
    292 UnicodeString&
    293 CompactDecimalFormat::format(
    294     int32_t number,
    295     UnicodeString& appendTo,
    296     FieldPosition& pos) const {
    297   return format((double) number, appendTo, pos);
    298 }
    299 
    300 UnicodeString&
    301 CompactDecimalFormat::format(
    302     int32_t number,
    303     UnicodeString& appendTo,
    304     FieldPosition& pos,
    305     UErrorCode &status) const {
    306   return format((double) number, appendTo, pos, status);
    307 }
    308 
    309 UnicodeString&
    310 CompactDecimalFormat::format(
    311     int32_t /* number */,
    312     UnicodeString& appendTo,
    313     FieldPositionIterator* /* posIter */,
    314     UErrorCode& status) const {
    315   status = U_UNSUPPORTED_ERROR;
    316   return appendTo;
    317 }
    318 
    319 UnicodeString&
    320 CompactDecimalFormat::format(
    321     int64_t number,
    322     UnicodeString& appendTo,
    323     FieldPosition& pos) const {
    324   return format((double) number, appendTo, pos);
    325 }
    326 
    327 UnicodeString&
    328 CompactDecimalFormat::format(
    329     int64_t number,
    330     UnicodeString& appendTo,
    331     FieldPosition& pos,
    332     UErrorCode &status) const {
    333   return format((double) number, appendTo, pos, status);
    334 }
    335 
    336 UnicodeString&
    337 CompactDecimalFormat::format(
    338     int64_t /* number */,
    339     UnicodeString& appendTo,
    340     FieldPositionIterator* /* posIter */,
    341     UErrorCode& status) const {
    342   status = U_UNSUPPORTED_ERROR;
    343   return appendTo;
    344 }
    345 
    346 UnicodeString&
    347 CompactDecimalFormat::format(
    348     const StringPiece& /* number */,
    349     UnicodeString& appendTo,
    350     FieldPositionIterator* /* posIter */,
    351     UErrorCode& status) const {
    352   status = U_UNSUPPORTED_ERROR;
    353   return appendTo;
    354 }
    355 
    356 UnicodeString&
    357 CompactDecimalFormat::format(
    358     const DigitList& /* number */,
    359     UnicodeString& appendTo,
    360     FieldPositionIterator* /* posIter */,
    361     UErrorCode& status) const {
    362   status = U_UNSUPPORTED_ERROR;
    363   return appendTo;
    364 }
    365 
    366 UnicodeString&
    367 CompactDecimalFormat::format(const DigitList& /* number */,
    368                              UnicodeString& appendTo,
    369                              FieldPosition& /* pos */,
    370                              UErrorCode& status) const {
    371   status = U_UNSUPPORTED_ERROR;
    372   return appendTo;
    373 }
    374 
    375 void
    376 CompactDecimalFormat::parse(
    377     const UnicodeString& /* text */,
    378     Formattable& /* result */,
    379     ParsePosition& /* parsePosition */) const {
    380 }
    381 
    382 void
    383 CompactDecimalFormat::parse(
    384     const UnicodeString& /* text */,
    385     Formattable& /* result */,
    386     UErrorCode& status) const {
    387   status = U_UNSUPPORTED_ERROR;
    388 }
    389 
    390 CurrencyAmount*
    391 CompactDecimalFormat::parseCurrency(
    392     const UnicodeString& /* text */,
    393     ParsePosition& /* pos */) const {
    394   return NULL;
    395 }
    396 
    397 void CDFLocaleStyleData::Init(UErrorCode& status) {
    398   if (unitsByVariant != NULL) {
    399     return;
    400   }
    401   unitsByVariant = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
    402   if (U_FAILURE(status)) {
    403     return;
    404   }
    405   uhash_setKeyDeleter(unitsByVariant, uprv_free);
    406   uhash_setValueDeleter(unitsByVariant, deleteCDFUnits);
    407 }
    408 
    409 CDFLocaleStyleData::~CDFLocaleStyleData() {
    410   setToBogus();
    411 }
    412 
    413 void CDFLocaleStyleData::setToBogus() {
    414   if (unitsByVariant != NULL) {
    415     uhash_close(unitsByVariant);
    416     unitsByVariant = NULL;
    417   }
    418 }
    419 
    420 void CDFLocaleData::Init(UErrorCode& status) {
    421   shortData.Init(status);
    422   if (U_FAILURE(status)) {
    423     return;
    424   }
    425   longData.Init(status);
    426 }
    427 
    428 // Helper method for operator=
    429 static UBool divisors_equal(const double* lhs, const double* rhs) {
    430   for (int32_t i = 0; i < MAX_DIGITS; ++i) {
    431     if (lhs[i] != rhs[i]) {
    432       return FALSE;
    433     }
    434   }
    435   return TRUE;
    436 }
    437 
    438 // getCDFLocaleStyleData returns pointer to formatting data for given locale and
    439 // style within the global cache. On cache miss, getCDFLocaleStyleData loads
    440 // the data from CLDR into the global cache before returning the pointer. If a
    441 // UNUM_LONG data is requested for a locale, and that locale does not have
    442 // UNUM_LONG data, getCDFLocaleStyleData will fall back to UNUM_SHORT data for
    443 // that locale.
    444 static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
    445   if (U_FAILURE(status)) {
    446     return NULL;
    447   }
    448   CDFLocaleData* result = NULL;
    449   const char* key = inLocale.getName();
    450   {
    451     Mutex lock(&gCompactDecimalMetaLock);
    452     if (gCompactDecimalData == NULL) {
    453       gCompactDecimalData = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
    454       if (U_FAILURE(status)) {
    455         return NULL;
    456       }
    457       uhash_setKeyDeleter(gCompactDecimalData, uprv_free);
    458       uhash_setValueDeleter(gCompactDecimalData, deleteCDFLocaleData);
    459       ucln_i18n_registerCleanup(UCLN_I18N_CDFINFO, cdf_cleanup);
    460     } else {
    461       result = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
    462     }
    463   }
    464   if (result != NULL) {
    465     return extractDataByStyleEnum(*result, style, status);
    466   }
    467 
    468   result = loadCDFLocaleData(inLocale, status);
    469   if (U_FAILURE(status)) {
    470     return NULL;
    471   }
    472 
    473   {
    474     Mutex lock(&gCompactDecimalMetaLock);
    475     CDFLocaleData* temp = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
    476     if (temp != NULL) {
    477       delete result;
    478       result = temp;
    479     } else {
    480       uhash_put(gCompactDecimalData, uprv_strdup(key), (void*) result, &status);
    481       if (U_FAILURE(status)) {
    482         return NULL;
    483       }
    484     }
    485   }
    486   return extractDataByStyleEnum(*result, style, status);
    487 }
    488 
    489 static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status) {
    490   switch (style) {
    491     case UNUM_SHORT:
    492       return &data.shortData;
    493     case UNUM_LONG:
    494       if (!data.longData.isBogus()) {
    495         return &data.longData;
    496       }
    497       return &data.shortData;
    498     default:
    499       status = U_ILLEGAL_ARGUMENT_ERROR;
    500       return NULL;
    501   }
    502 }
    503 
    504 // loadCDFLocaleData loads formatting data from CLDR for a given locale. The
    505 // caller owns the returned pointer.
    506 static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status) {
    507   if (U_FAILURE(status)) {
    508     return NULL;
    509   }
    510   CDFLocaleData* result = new CDFLocaleData;
    511   if (result == NULL) {
    512     status = U_MEMORY_ALLOCATION_ERROR;
    513     return NULL;
    514   }
    515   result->Init(status);
    516   if (U_FAILURE(status)) {
    517     delete result;
    518     return NULL;
    519   }
    520 
    521   initCDFLocaleData(inLocale, result, status);
    522   if (U_FAILURE(status)) {
    523     delete result;
    524     return NULL;
    525   }
    526   return result;
    527 }
    528 
    529 // initCDFLocaleData initializes result with data from CLDR.
    530 // inLocale is the locale, the CLDR data is stored in result.
    531 // We load the UNUM_SHORT  and UNUM_LONG data looking first in local numbering
    532 // system and not including root locale in fallback. Next we try in the latn
    533 // numbering system where we fallback all the way to root. If we don't find
    534 // UNUM_SHORT data in these three places, we report an error. If we find
    535 // UNUM_SHORT data before finding UNUM_LONG data we make UNUM_LONG data fall
    536 // back to UNUM_SHORT data.
    537 static void initCDFLocaleData(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status) {
    538   LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(inLocale, status));
    539   if (U_FAILURE(status)) {
    540     return;
    541   }
    542   const char* numberingSystemName = ns->getName();
    543   UResourceBundle* rb = ures_open(NULL, inLocale.getName(), &status);
    544   rb = ures_getByKeyWithFallback(rb, gNumberElementsTag, rb, &status);
    545   if (U_FAILURE(status)) {
    546     ures_close(rb);
    547     return;
    548   }
    549   UResourceBundle* shortDataFillIn = NULL;
    550   UResourceBundle* longDataFillIn = NULL;
    551   UResourceBundle* shortData = NULL;
    552   UResourceBundle* longData = NULL;
    553 
    554   if (uprv_strcmp(numberingSystemName, gLatnTag) != 0) {
    555     LocalUResourceBundlePointer localResource(
    556         tryGetByKeyWithFallback(rb, numberingSystemName, NULL, NOT_ROOT, status));
    557     shortData = tryGetDecimalFallback(
    558         localResource.getAlias(), gPatternsShort, &shortDataFillIn, NOT_ROOT, status);
    559     longData = tryGetDecimalFallback(
    560         localResource.getAlias(), gPatternsLong, &longDataFillIn, NOT_ROOT, status);
    561   }
    562   if (U_FAILURE(status)) {
    563     ures_close(shortDataFillIn);
    564     ures_close(longDataFillIn);
    565     ures_close(rb);
    566     return;
    567   }
    568 
    569   // If we haven't found UNUM_SHORT look in latn numbering system. We must
    570   // succeed at finding UNUM_SHORT here.
    571   if (shortData == NULL) {
    572     LocalUResourceBundlePointer latnResource(tryGetByKeyWithFallback(rb, gLatnTag, NULL, MUST, status));
    573     shortData = tryGetDecimalFallback(latnResource.getAlias(), gPatternsShort, &shortDataFillIn, MUST, status);
    574     if (longData == NULL) {
    575       longData = tryGetDecimalFallback(latnResource.getAlias(), gPatternsLong, &longDataFillIn, ANY, status);
    576       if (longData != NULL && isRoot(longData, status) && !isRoot(shortData, status)) {
    577         longData = NULL;
    578       }
    579     }
    580   }
    581   initCDFLocaleStyleData(shortData, &result->shortData, status);
    582   ures_close(shortDataFillIn);
    583   if (U_FAILURE(status)) {
    584     ures_close(longDataFillIn);
    585     ures_close(rb);
    586   }
    587 
    588   if (longData == NULL) {
    589     result->longData.setToBogus();
    590   } else {
    591     initCDFLocaleStyleData(longData, &result->longData, status);
    592   }
    593   ures_close(longDataFillIn);
    594   ures_close(rb);
    595 }
    596 
    597 /**
    598  * tryGetDecimalFallback attempts to fetch the "decimalFormat" resource bundle
    599  * with a particular style. style is either "patternsShort" or "patternsLong."
    600  * FillIn, flags, and status work in the same way as in tryGetByKeyWithFallback.
    601  */
    602 static UResourceBundle* tryGetDecimalFallback(const UResourceBundle* numberSystemResource, const char* style, UResourceBundle** fillIn, FallbackFlags flags, UErrorCode& status) {
    603   UResourceBundle* first = tryGetByKeyWithFallback(numberSystemResource, style, fillIn, flags, status);
    604   UResourceBundle* second = tryGetByKeyWithFallback(first, gDecimalFormatTag, fillIn, flags, status);
    605   if (fillIn == NULL) {
    606     ures_close(first);
    607   }
    608   return second;
    609 }
    610 
    611 // tryGetByKeyWithFallback returns a sub-resource bundle that matches given
    612 // criteria or NULL if none found. rb is the resource bundle that we are
    613 // searching. If rb == NULL then this function behaves as if no sub-resource
    614 // is found; path is the key of the sub-resource,
    615 // (i.e "foo" but not "foo/bar"); If fillIn is NULL, caller must always call
    616 // ures_close() on returned resource. See below for example when fillIn is
    617 // not NULL. flags is ANY or NOT_ROOT. Optionally, these values
    618 // can be ored with MUST. MUST by itself is the same as ANY | MUST.
    619 // The locale of the returned sub-resource will either match the
    620 // flags or the returned sub-resouce will be NULL. If MUST is included in
    621 // flags, and not suitable sub-resource is found then in addition to returning
    622 // NULL, this function also sets status to U_MISSING_RESOURCE_ERROR. If MUST
    623 // is not included in flags, then this function just returns NULL if no
    624 // such sub-resource is found and will never set status to
    625 // U_MISSING_RESOURCE_ERROR.
    626 //
    627 // Example: This code first searches for "foo/bar" sub-resource without falling
    628 // back to ROOT. Then searches for "baz" sub-resource as last resort.
    629 //
    630 // UResourcebundle* fillIn = NULL;
    631 // UResourceBundle* data = tryGetByKeyWithFallback(rb, "foo", &fillIn, NON_ROOT, status);
    632 // data = tryGetByKeyWithFallback(data, "bar", &fillIn, NON_ROOT, status);
    633 // if (!data) {
    634 //   data = tryGetbyKeyWithFallback(rb, "baz", &fillIn, MUST,  status);
    635 // }
    636 // if (U_FAILURE(status)) {
    637 //   ures_close(fillIn);
    638 //   return;
    639 // }
    640 // doStuffWithNonNullSubresource(data);
    641 //
    642 // /* Wrong! don't do the following as it can leak memory if fillIn gets set
    643 // to NULL. */
    644 // fillIn = tryGetByKeyWithFallback(rb, "wrong", &fillIn, ANY, status);
    645 //
    646 // ures_close(fillIn);
    647 //
    648 static UResourceBundle* tryGetByKeyWithFallback(const UResourceBundle* rb, const char* path, UResourceBundle** fillIn, FallbackFlags flags, UErrorCode& status) {
    649   if (U_FAILURE(status)) {
    650     return NULL;
    651   }
    652   UBool must = (flags & MUST);
    653   if (rb == NULL) {
    654     if (must) {
    655       status = U_MISSING_RESOURCE_ERROR;
    656     }
    657     return NULL;
    658   }
    659   UResourceBundle* result = NULL;
    660   UResourceBundle* ownedByUs = NULL;
    661   if (fillIn == NULL) {
    662     ownedByUs = ures_getByKeyWithFallback(rb, path, NULL, &status);
    663     result = ownedByUs;
    664   } else {
    665     *fillIn = ures_getByKeyWithFallback(rb, path, *fillIn, &status);
    666     result = *fillIn;
    667   }
    668   if (U_FAILURE(status)) {
    669     ures_close(ownedByUs);
    670     if (status == U_MISSING_RESOURCE_ERROR && !must) {
    671       status = U_ZERO_ERROR;
    672     }
    673     return NULL;
    674   }
    675   flags = (FallbackFlags) (flags & ~MUST);
    676   switch (flags) {
    677     case NOT_ROOT:
    678       {
    679         UBool bRoot = isRoot(result, status);
    680         if (bRoot || U_FAILURE(status)) {
    681           ures_close(ownedByUs);
    682           if (must && (status == U_ZERO_ERROR)) {
    683             status = U_MISSING_RESOURCE_ERROR;
    684           }
    685           return NULL;
    686         }
    687         return result;
    688       }
    689     case ANY:
    690       return result;
    691     default:
    692       ures_close(ownedByUs);
    693       status = U_ILLEGAL_ARGUMENT_ERROR;
    694       return NULL;
    695   }
    696 }
    697 
    698 static UBool isRoot(const UResourceBundle* rb, UErrorCode& status) {
    699   const char* actualLocale = ures_getLocaleByType(
    700       rb, ULOC_ACTUAL_LOCALE, &status);
    701   if (U_FAILURE(status)) {
    702     return FALSE;
    703   }
    704   return uprv_strcmp(actualLocale, gRoot) == 0;
    705 }
    706 
    707 
    708 // initCDFLocaleStyleData loads formatting data for a particular style.
    709 // decimalFormatBundle is the "decimalFormat" resource bundle in CLDR.
    710 // Loaded data stored in result.
    711 static void initCDFLocaleStyleData(const UResourceBundle* decimalFormatBundle, CDFLocaleStyleData* result, UErrorCode& status) {
    712   if (U_FAILURE(status)) {
    713     return;
    714   }
    715   // Iterate through all the powers of 10.
    716   int32_t size = ures_getSize(decimalFormatBundle);
    717   UResourceBundle* power10 = NULL;
    718   for (int32_t i = 0; i < size; ++i) {
    719     power10 = ures_getByIndex(decimalFormatBundle, i, power10, &status);
    720     if (U_FAILURE(status)) {
    721       ures_close(power10);
    722       return;
    723     }
    724     populatePower10(power10, result, status);
    725     if (U_FAILURE(status)) {
    726       ures_close(power10);
    727       return;
    728     }
    729   }
    730   ures_close(power10);
    731   fillInMissing(result);
    732 }
    733 
    734 // populatePower10 grabs data for a particular power of 10 from CLDR.
    735 // The loaded data is stored in result.
    736 static void populatePower10(const UResourceBundle* power10Bundle, CDFLocaleStyleData* result, UErrorCode& status) {
    737   if (U_FAILURE(status)) {
    738     return;
    739   }
    740   char* endPtr = NULL;
    741   double power10 = uprv_strtod(ures_getKey(power10Bundle), &endPtr);
    742   if (*endPtr != 0) {
    743     status = U_INTERNAL_PROGRAM_ERROR;
    744     return;
    745   }
    746   int32_t log10Value = computeLog10(power10, FALSE);
    747   // Silently ignore divisors that are too big.
    748   if (log10Value == MAX_DIGITS) {
    749     return;
    750   }
    751   int32_t size = ures_getSize(power10Bundle);
    752   int32_t numZeros = 0;
    753   UBool otherVariantDefined = FALSE;
    754   UResourceBundle* variantBundle = NULL;
    755   // Iterate over all the plural variants for the power of 10
    756   for (int32_t i = 0; i < size; ++i) {
    757     variantBundle = ures_getByIndex(power10Bundle, i, variantBundle, &status);
    758     if (U_FAILURE(status)) {
    759       ures_close(variantBundle);
    760       return;
    761     }
    762     const char* variant = ures_getKey(variantBundle);
    763     int32_t resLen;
    764     const UChar* formatStrP = ures_getString(variantBundle, &resLen, &status);
    765     if (U_FAILURE(status)) {
    766       ures_close(variantBundle);
    767       return;
    768     }
    769     UnicodeString formatStr(false, formatStrP, resLen);
    770     if (uprv_strcmp(variant, gOther) == 0) {
    771       otherVariantDefined = TRUE;
    772     }
    773     int32_t nz = populatePrefixSuffix(
    774         variant, log10Value, formatStr, result->unitsByVariant, status);
    775     if (U_FAILURE(status)) {
    776       ures_close(variantBundle);
    777       return;
    778     }
    779     if (nz != numZeros) {
    780       // We expect all format strings to have the same number of 0's
    781       // left of the decimal point.
    782       if (numZeros != 0) {
    783         status = U_INTERNAL_PROGRAM_ERROR;
    784         ures_close(variantBundle);
    785         return;
    786       }
    787       numZeros = nz;
    788     }
    789   }
    790   ures_close(variantBundle);
    791   // We expect to find an OTHER variant for each power of 10.
    792   if (!otherVariantDefined) {
    793     status = U_INTERNAL_PROGRAM_ERROR;
    794     return;
    795   }
    796   double divisor = power10;
    797   for (int32_t i = 1; i < numZeros; ++i) {
    798     divisor /= 10.0;
    799   }
    800   result->divisors[log10Value] = divisor;
    801 }
    802 
    803 // populatePrefixSuffix Adds a specific prefix-suffix pair to result for a
    804 // given variant and log10 value.
    805 // variant is 'zero', 'one', 'two', 'few', 'many', or 'other'.
    806 // formatStr is the format string from which the prefix and suffix are
    807 // extracted. It is usually of form 'Pefix 000 suffix'.
    808 // populatePrefixSuffix returns the number of 0's found in formatStr
    809 // before the decimal point.
    810 // In the special case that formatStr contains only spaces for prefix
    811 // and suffix, populatePrefixSuffix returns log10Value + 1.
    812 static int32_t populatePrefixSuffix(
    813     const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UErrorCode& status) {
    814   if (U_FAILURE(status)) {
    815     return 0;
    816   }
    817   int32_t firstIdx = formatStr.indexOf(kZero, UPRV_LENGTHOF(kZero), 0);
    818   // We must have 0's in format string.
    819   if (firstIdx == -1) {
    820     status = U_INTERNAL_PROGRAM_ERROR;
    821     return 0;
    822   }
    823   int32_t lastIdx = formatStr.lastIndexOf(kZero, UPRV_LENGTHOF(kZero), firstIdx);
    824   CDFUnit* unit = createCDFUnit(variant, log10Value, result, status);
    825   if (U_FAILURE(status)) {
    826     return 0;
    827   }
    828   // Everything up to first 0 is the prefix
    829   unit->prefix = formatStr.tempSubString(0, firstIdx);
    830   fixQuotes(unit->prefix);
    831   // Everything beyond the last 0 is the suffix
    832   unit->suffix = formatStr.tempSubString(lastIdx + 1);
    833   fixQuotes(unit->suffix);
    834 
    835   // If there is effectively no prefix or suffix, ignore the actual number of
    836   // 0's and act as if the number of 0's matches the size of the number.
    837   if (onlySpaces(unit->prefix) && onlySpaces(unit->suffix)) {
    838     return log10Value + 1;
    839   }
    840 
    841   // Calculate number of zeros before decimal point
    842   int32_t idx = firstIdx + 1;
    843   while (idx <= lastIdx && formatStr.charAt(idx) == u_0) {
    844     ++idx;
    845   }
    846   return (idx - firstIdx);
    847 }
    848 
    849 static UBool onlySpaces(UnicodeString u) {
    850   return u.trim().length() == 0;
    851 }
    852 
    853 // fixQuotes unescapes single quotes. Don''t -> Don't. Letter 'j' -> Letter j.
    854 // Modifies s in place.
    855 static void fixQuotes(UnicodeString& s) {
    856   QuoteState state = OUTSIDE;
    857   int32_t len = s.length();
    858   int32_t dest = 0;
    859   for (int32_t i = 0; i < len; ++i) {
    860     UChar ch = s.charAt(i);
    861     if (ch == u_apos) {
    862       if (state == INSIDE_EMPTY) {
    863         s.setCharAt(dest, ch);
    864         ++dest;
    865       }
    866     } else {
    867       s.setCharAt(dest, ch);
    868       ++dest;
    869     }
    870 
    871     // Update state
    872     switch (state) {
    873       case OUTSIDE:
    874         state = ch == u_apos ? INSIDE_EMPTY : OUTSIDE;
    875         break;
    876       case INSIDE_EMPTY:
    877       case INSIDE_FULL:
    878         state = ch == u_apos ? OUTSIDE : INSIDE_FULL;
    879         break;
    880       default:
    881         break;
    882     }
    883   }
    884   s.truncate(dest);
    885 }
    886 
    887 // fillInMissing ensures that the data in result is complete.
    888 // result data is complete if for each variant in result, there exists
    889 // a prefix-suffix pair for each log10 value and there also exists
    890 // a divisor for each log10 value.
    891 //
    892 // First this function figures out for which log10 values, the other
    893 // variant already had data. These are the same log10 values defined
    894 // in CLDR.
    895 //
    896 // For each log10 value not defined in CLDR, it uses the divisor for
    897 // the last defined log10 value or 1.
    898 //
    899 // Then for each variant, it does the following. For each log10
    900 // value not defined in CLDR, copy the prefix-suffix pair from the
    901 // previous log10 value. If log10 value is defined in CLDR but is
    902 // missing from given variant, copy the prefix-suffix pair for that
    903 // log10 value from the 'other' variant.
    904 static void fillInMissing(CDFLocaleStyleData* result) {
    905   const CDFUnit* otherUnits =
    906       (const CDFUnit*) uhash_get(result->unitsByVariant, gOther);
    907   UBool definedInCLDR[MAX_DIGITS];
    908   double lastDivisor = 1.0;
    909   for (int32_t i = 0; i < MAX_DIGITS; ++i) {
    910     if (!otherUnits[i].isSet()) {
    911       result->divisors[i] = lastDivisor;
    912       definedInCLDR[i] = FALSE;
    913     } else {
    914       lastDivisor = result->divisors[i];
    915       definedInCLDR[i] = TRUE;
    916     }
    917   }
    918   // Iterate over each variant.
    919   int32_t pos = UHASH_FIRST;
    920   const UHashElement* element = uhash_nextElement(result->unitsByVariant, &pos);
    921   for (;element != NULL; element = uhash_nextElement(result->unitsByVariant, &pos)) {
    922     CDFUnit* units = (CDFUnit*) element->value.pointer;
    923     for (int32_t i = 0; i < MAX_DIGITS; ++i) {
    924       if (definedInCLDR[i]) {
    925         if (!units[i].isSet()) {
    926           units[i] = otherUnits[i];
    927         }
    928       } else {
    929         if (i == 0) {
    930           units[0].markAsSet();
    931         } else {
    932           units[i] = units[i - 1];
    933         }
    934       }
    935     }
    936   }
    937 }
    938 
    939 // computeLog10 computes floor(log10(x)). If inRange is TRUE, the biggest
    940 // value computeLog10 will return MAX_DIGITS -1 even for
    941 // numbers > 10^MAX_DIGITS. If inRange is FALSE, computeLog10 will return
    942 // up to MAX_DIGITS.
    943 static int32_t computeLog10(double x, UBool inRange) {
    944   int32_t result = 0;
    945   int32_t max = inRange ? MAX_DIGITS - 1 : MAX_DIGITS;
    946   while (x >= 10.0) {
    947     x /= 10.0;
    948     ++result;
    949     if (result == max) {
    950       break;
    951     }
    952   }
    953   return result;
    954 }
    955 
    956 // createCDFUnit returns a pointer to the prefix-suffix pair for a given
    957 // variant and log10 value within table. If no such prefix-suffix pair is
    958 // stored in table, one is created within table before returning pointer.
    959 static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status) {
    960   if (U_FAILURE(status)) {
    961     return NULL;
    962   }
    963   CDFUnit *cdfUnit = (CDFUnit*) uhash_get(table, variant);
    964   if (cdfUnit == NULL) {
    965     cdfUnit = new CDFUnit[MAX_DIGITS];
    966     if (cdfUnit == NULL) {
    967       status = U_MEMORY_ALLOCATION_ERROR;
    968       return NULL;
    969     }
    970     uhash_put(table, uprv_strdup(variant), cdfUnit, &status);
    971     if (U_FAILURE(status)) {
    972       return NULL;
    973     }
    974   }
    975   CDFUnit* result = &cdfUnit[log10Value];
    976   result->markAsSet();
    977   return result;
    978 }
    979 
    980 // getCDFUnitFallback returns a pointer to the prefix-suffix pair for a given
    981 // variant and log10 value within table. If the given variant doesn't exist, it
    982 // falls back to the OTHER variant. Therefore, this method will always return
    983 // some non-NULL value.
    984 static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value) {
    985   CharString cvariant;
    986   UErrorCode status = U_ZERO_ERROR;
    987   const CDFUnit *cdfUnit = NULL;
    988   cvariant.appendInvariantChars(variant, status);
    989   if (!U_FAILURE(status)) {
    990     cdfUnit = (const CDFUnit*) uhash_get(table, cvariant.data());
    991   }
    992   if (cdfUnit == NULL) {
    993     cdfUnit = (const CDFUnit*) uhash_get(table, gOther);
    994   }
    995   return &cdfUnit[log10Value];
    996 }
    997 
    998 U_NAMESPACE_END
    999 #endif
   1000