10596faeddefbf198de137d5e893708495ab1584cFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html
38393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*
48393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius*******************************************************************************
5c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert* Copyright (C) 1997-2015, International Business Machines Corporation and    *
68393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius* others. All Rights Reserved.                                                *
78393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius*******************************************************************************
88393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius*
98393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius* File COMPACTDECIMALFORMAT.CPP
108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius*
118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius********************************************************************************
128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius*/
138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "unicode/utypes.h"
148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#if !UCONFIG_NO_FORMATTING
168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "charstr.h"
188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "cstring.h"
198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "digitlst.h"
208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "mutex.h"
218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "unicode/compactdecimalformat.h"
228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "unicode/numsys.h"
238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "unicode/plurrule.h"
248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "unicode/ures.h"
258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "ucln_in.h"
268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "uhash.h"
278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "umutex.h"
288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "unicode/ures.h"
298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "uresimp.h"
308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// Maps locale name to CDFLocaleData struct.
328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic UHashtable* gCompactDecimalData = NULL;
338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic UMutex gCompactDecimalMetaLock = U_MUTEX_INITIALIZER;
348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusU_NAMESPACE_BEGIN
368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const int32_t MAX_DIGITS = 15;
388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char gOther[] = "other";
398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char gLatnTag[] = "latn";
408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char gNumberElementsTag[] = "NumberElements";
418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char gDecimalFormatTag[] = "decimalFormat";
428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char gPatternsShort[] = "patternsShort";
438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char gPatternsLong[] = "patternsLong";
4464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic const char gLatnPath[] = "NumberElements/latn";
458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const UChar u_0 = 0x30;
478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const UChar u_apos = 0x27;
488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const UChar kZero[] = {u_0};
508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// Used to unescape single quotes.
528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusenum QuoteState {
538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  OUTSIDE,
548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  INSIDE_EMPTY,
558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  INSIDE_FULL
568393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius};
578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusenum FallbackFlags {
598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  ANY = 0,
608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  MUST = 1,
618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  NOT_ROOT = 2
628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Next one will be 4 then 6 etc.
638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius};
648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// CDFUnit represents a prefix-suffix pair for a particular variant
678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// and log10 value.
688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstruct CDFUnit : public UMemory {
698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  UnicodeString prefix;
708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  UnicodeString suffix;
718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  inline CDFUnit() : prefix(), suffix() {
728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    prefix.setToBogus();
738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  inline ~CDFUnit() {}
758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  inline UBool isSet() const {
768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return !prefix.isBogus();
778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  inline void markAsSet() {
798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    prefix.remove();
808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius};
828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// CDFLocaleStyleData contains formatting data for a particular locale
848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// and style.
858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusclass CDFLocaleStyleData : public UMemory {
868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius public:
878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // What to divide by for each log10 value when formatting. These values
888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // will be powers of 10. For English, would be:
898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // 1, 1, 1, 1000, 1000, 1000, 1000000, 1000000, 1000000, 1000000000 ...
908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  double divisors[MAX_DIGITS];
918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Maps plural variants to CDFUnit[MAX_DIGITS] arrays.
928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // To format a number x,
938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // first compute log10(x). Compute displayNum = (x / divisors[log10(x)]).
948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Compute the plural variant for displayNum
958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // (e.g zero, one, two, few, many, other).
968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Compute cdfUnits = unitsByVariant[pluralVariant].
978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Prefix and suffix to use at cdfUnits[log10(x)]
988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  UHashtable* unitsByVariant;
9964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // A flag for whether or not this CDFLocaleStyleData was loaded from the
10064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // Latin numbering system as a fallback from the locale numbering system.
10164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // This value is meaningless if the object is bogus or empty.
10264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  UBool fromFallback;
10364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  inline CDFLocaleStyleData() : unitsByVariant(NULL), fromFallback(FALSE) {
10464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    uprv_memset(divisors, 0, sizeof(divisors));
10564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  }
1068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  ~CDFLocaleStyleData();
1078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Init initializes this object.
1088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  void Init(UErrorCode& status);
1098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  inline UBool isBogus() const {
1108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return unitsByVariant == NULL;
1118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
1128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  void setToBogus();
11364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  UBool isEmpty() {
11464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    return unitsByVariant == NULL || unitsByVariant->count == 0;
11564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  }
1168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius private:
1178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFLocaleStyleData(const CDFLocaleStyleData&);
1188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFLocaleStyleData& operator=(const CDFLocaleStyleData&);
1198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius};
1208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// CDFLocaleData contains formatting data for a particular locale.
1228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstruct CDFLocaleData : public UMemory {
1238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFLocaleStyleData shortData;
1248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFLocaleStyleData longData;
1258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  inline CDFLocaleData() : shortData(), longData() { }
1268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  inline ~CDFLocaleData() { }
1278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Init initializes this object.
1288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  void Init(UErrorCode& status);
1298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius};
1308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusU_NAMESPACE_END
1328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusU_CDECL_BEGIN
1348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic UBool U_CALLCONV cdf_cleanup(void) {
1368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (gCompactDecimalData != NULL) {
1378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    uhash_close(gCompactDecimalData);
1388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    gCompactDecimalData = NULL;
1398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
1408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return TRUE;
1418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
1428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic void U_CALLCONV deleteCDFUnits(void* ptr) {
1448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  delete [] (icu::CDFUnit*) ptr;
1458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
1468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic void U_CALLCONV deleteCDFLocaleData(void* ptr) {
1488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  delete (icu::CDFLocaleData*) ptr;
1498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
1508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusU_CDECL_END
1528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusU_NAMESPACE_BEGIN
1548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic UBool divisors_equal(const double* lhs, const double* rhs);
1568393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status);
1578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status);
1598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status);
16064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status);
16164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic int32_t populatePrefixSuffix(const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UBool overwrite, UErrorCode& status);
16264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic double calculateDivisor(double power10, int32_t numZeros);
1638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic UBool onlySpaces(UnicodeString u);
1648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic void fixQuotes(UnicodeString& s);
16564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic void checkForOtherVariants(CDFLocaleStyleData* result, UErrorCode& status);
1668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic void fillInMissing(CDFLocaleStyleData* result);
1678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic int32_t computeLog10(double x, UBool inRange);
1688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status);
1698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value);
1708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat)
1728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::CompactDecimalFormat(
1748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const DecimalFormat& decimalFormat,
1758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const UHashtable* unitsByVariant,
1768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const double* divisors,
1778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    PluralRules* pluralRules)
1788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  : DecimalFormat(decimalFormat), _unitsByVariant(unitsByVariant), _divisors(divisors), _pluralRules(pluralRules) {
1798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
1808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source)
1828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    : DecimalFormat(source), _unitsByVariant(source._unitsByVariant), _divisors(source._divisors), _pluralRules(source._pluralRules->clone()) {
1838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
1848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
1858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat* U_EXPORT2
1868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::createInstance(
1878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
1888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  LocalPointer<DecimalFormat> decfmt((DecimalFormat*) NumberFormat::makeInstance(inLocale, UNUM_DECIMAL, TRUE, status));
1898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
1908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
1918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
1928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  LocalPointer<PluralRules> pluralRules(PluralRules::forLocale(inLocale, status));
1938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
1948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
1958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
1968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  const CDFLocaleStyleData* data = getCDFLocaleStyleData(inLocale, style, status);
1978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
1988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
1998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
2008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CompactDecimalFormat* result =
2018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      new CompactDecimalFormat(*decfmt, data->unitsByVariant, data->divisors, pluralRules.getAlias());
2028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (result == NULL) {
2038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    status = U_MEMORY_ALLOCATION_ERROR;
2048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
2058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
2068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  pluralRules.orphan();
2078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  result->setMaximumSignificantDigits(3);
2088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  result->setSignificantDigitsUsed(TRUE);
2098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  result->setGroupingUsed(FALSE);
2108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return result;
2118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
2128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
2138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat&
2148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) {
2158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (this != &rhs) {
2168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    DecimalFormat::operator=(rhs);
2178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    _unitsByVariant = rhs._unitsByVariant;
2188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    _divisors = rhs._divisors;
2198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    delete _pluralRules;
2208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    _pluralRules = rhs._pluralRules->clone();
2218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
2228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return *this;
2238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
2248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
2258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::~CompactDecimalFormat() {
2268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  delete _pluralRules;
2278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
2288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
2298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
2308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusFormat*
2318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::clone(void) const {
2328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return new CompactDecimalFormat(*this);
2338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
2348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
2358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUBool
2368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::operator==(const Format& that) const {
2378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (this == &that) {
2388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return TRUE;
2398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
2408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return (DecimalFormat::operator==(that) && eqHelper((const CompactDecimalFormat&) that));
2418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
2428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
2438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUBool
2448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::eqHelper(const CompactDecimalFormat& that) const {
2458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return uhash_equals(_unitsByVariant, that._unitsByVariant) && divisors_equal(_divisors, that._divisors) && (*_pluralRules == *that._pluralRules);
2468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
2478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
2488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUnicodeString&
2498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::format(
2508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    double number,
2518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UnicodeString& appendTo,
2528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    FieldPosition& pos) const {
253c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  UErrorCode status = U_ZERO_ERROR;
254c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  return format(number, appendTo, pos, status);
255c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
256c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
257c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString&
258c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertCompactDecimalFormat::format(
259c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    double number,
260c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UnicodeString& appendTo,
261c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    FieldPosition& pos,
262c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UErrorCode &status) const {
263c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  if (U_FAILURE(status)) {
264c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    return appendTo;
265c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  }
2668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  DigitList orig, rounded;
2678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  orig.set(number);
2688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  UBool isNegative;
2698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  _round(orig, rounded, isNegative, status);
2708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
2718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return appendTo;
2728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
2738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  double roundedDouble = rounded.getDouble();
2748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (isNegative) {
2758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    roundedDouble = -roundedDouble;
2768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
2778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  int32_t baseIdx = computeLog10(roundedDouble, TRUE);
2788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  double numberToFormat = roundedDouble / _divisors[baseIdx];
2798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  UnicodeString variant = _pluralRules->select(numberToFormat);
2808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (isNegative) {
2818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    numberToFormat = -numberToFormat;
2828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
2838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  const CDFUnit* unit = getCDFUnitFallback(_unitsByVariant, variant, baseIdx);
2848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  appendTo += unit->prefix;
2858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  DecimalFormat::format(numberToFormat, appendTo, pos);
2868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  appendTo += unit->suffix;
2878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return appendTo;
2888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
2898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
2908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUnicodeString&
2918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::format(
2928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    double /* number */,
2938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UnicodeString& appendTo,
2948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    FieldPositionIterator* /* posIter */,
2958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UErrorCode& status) const {
2968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  status = U_UNSUPPORTED_ERROR;
2978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return appendTo;
2988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
2998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
3008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUnicodeString&
3018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::format(
302c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    int32_t number,
303c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UnicodeString& appendTo,
304c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    FieldPosition& pos) const {
305c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  return format((double) number, appendTo, pos);
306c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
307c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
308c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString&
309c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertCompactDecimalFormat::format(
310c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    int32_t number,
311c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UnicodeString& appendTo,
312c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    FieldPosition& pos,
313c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UErrorCode &status) const {
314c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  return format((double) number, appendTo, pos, status);
315c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
316c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
317c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString&
318c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertCompactDecimalFormat::format(
319c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    int32_t /* number */,
320c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UnicodeString& appendTo,
321c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    FieldPositionIterator* /* posIter */,
322c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UErrorCode& status) const {
323c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  status = U_UNSUPPORTED_ERROR;
324c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  return appendTo;
325c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
326c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
327c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString&
328c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertCompactDecimalFormat::format(
3298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    int64_t number,
3308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UnicodeString& appendTo,
3318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    FieldPosition& pos) const {
3328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return format((double) number, appendTo, pos);
3338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
3348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
3358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUnicodeString&
3368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::format(
337c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    int64_t number,
338c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UnicodeString& appendTo,
339c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    FieldPosition& pos,
340c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    UErrorCode &status) const {
341c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert  return format((double) number, appendTo, pos, status);
342c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert}
343c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert
344c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertUnicodeString&
345c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik RoubertCompactDecimalFormat::format(
3468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    int64_t /* number */,
3478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UnicodeString& appendTo,
3488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    FieldPositionIterator* /* posIter */,
3498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UErrorCode& status) const {
3508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  status = U_UNSUPPORTED_ERROR;
3518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return appendTo;
3528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
3538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
3548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUnicodeString&
3558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::format(
35664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    StringPiece /* number */,
3578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UnicodeString& appendTo,
3588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    FieldPositionIterator* /* posIter */,
3598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UErrorCode& status) const {
3608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  status = U_UNSUPPORTED_ERROR;
3618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return appendTo;
3628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
3638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
3648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUnicodeString&
3658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::format(
3668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const DigitList& /* number */,
3678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UnicodeString& appendTo,
3688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    FieldPositionIterator* /* posIter */,
3698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UErrorCode& status) const {
3708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  status = U_UNSUPPORTED_ERROR;
3718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return appendTo;
3728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
3738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
3748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusUnicodeString&
3758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::format(const DigitList& /* number */,
3768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                             UnicodeString& appendTo,
3778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                             FieldPosition& /* pos */,
3788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                             UErrorCode& status) const {
3798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  status = U_UNSUPPORTED_ERROR;
3808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return appendTo;
3818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
3828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
3838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid
3848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::parse(
3858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const UnicodeString& /* text */,
3868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    Formattable& /* result */,
3878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    ParsePosition& /* parsePosition */) const {
3888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
3898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
3908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid
3918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::parse(
3928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const UnicodeString& /* text */,
3938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    Formattable& /* result */,
3948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UErrorCode& status) const {
3958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  status = U_UNSUPPORTED_ERROR;
3968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
3978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
3988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCurrencyAmount*
3998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCompactDecimalFormat::parseCurrency(
4008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const UnicodeString& /* text */,
4018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    ParsePosition& /* pos */) const {
4028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return NULL;
4038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
4048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid CDFLocaleStyleData::Init(UErrorCode& status) {
4068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (unitsByVariant != NULL) {
4078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return;
4088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  unitsByVariant = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
4108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
4118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return;
4128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  uhash_setKeyDeleter(unitsByVariant, uprv_free);
4148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  uhash_setValueDeleter(unitsByVariant, deleteCDFUnits);
4158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
4168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusCDFLocaleStyleData::~CDFLocaleStyleData() {
4188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  setToBogus();
4198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
4208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid CDFLocaleStyleData::setToBogus() {
4228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (unitsByVariant != NULL) {
4238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    uhash_close(unitsByVariant);
4248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    unitsByVariant = NULL;
4258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
4278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid CDFLocaleData::Init(UErrorCode& status) {
4298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  shortData.Init(status);
4308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
4318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return;
4328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  longData.Init(status);
4348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
4358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// Helper method for operator=
4378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic UBool divisors_equal(const double* lhs, const double* rhs) {
4388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  for (int32_t i = 0; i < MAX_DIGITS; ++i) {
4398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (lhs[i] != rhs[i]) {
4408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      return FALSE;
4418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
4428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return TRUE;
4448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
4458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// getCDFLocaleStyleData returns pointer to formatting data for given locale and
4478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// style within the global cache. On cache miss, getCDFLocaleStyleData loads
4488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// the data from CLDR into the global cache before returning the pointer. If a
4498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// UNUM_LONG data is requested for a locale, and that locale does not have
4508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// UNUM_LONG data, getCDFLocaleStyleData will fall back to UNUM_SHORT data for
4518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// that locale.
4528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
4538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
4548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
4558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4568393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFLocaleData* result = NULL;
4578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  const char* key = inLocale.getName();
4588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  {
4598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    Mutex lock(&gCompactDecimalMetaLock);
4608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (gCompactDecimalData == NULL) {
4618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      gCompactDecimalData = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
4628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      if (U_FAILURE(status)) {
4638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        return NULL;
4648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      }
4658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      uhash_setKeyDeleter(gCompactDecimalData, uprv_free);
4668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      uhash_setValueDeleter(gCompactDecimalData, deleteCDFLocaleData);
4678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      ucln_i18n_registerCleanup(UCLN_I18N_CDFINFO, cdf_cleanup);
4688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    } else {
4698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      result = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
4708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
4718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (result != NULL) {
4738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return extractDataByStyleEnum(*result, style, status);
4748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  result = loadCDFLocaleData(inLocale, status);
4778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
4788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
4798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  {
4828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    Mutex lock(&gCompactDecimalMetaLock);
4838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    CDFLocaleData* temp = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
4848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (temp != NULL) {
4858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      delete result;
4868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      result = temp;
4878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    } else {
4888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      uhash_put(gCompactDecimalData, uprv_strdup(key), (void*) result, &status);
4898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      if (U_FAILURE(status)) {
4908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        return NULL;
4918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      }
4928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
4938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
4948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return extractDataByStyleEnum(*result, style, status);
4958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
4968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status) {
4988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  switch (style) {
4998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    case UNUM_SHORT:
5008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      return &data.shortData;
5018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    case UNUM_LONG:
5028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      if (!data.longData.isBogus()) {
5038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        return &data.longData;
5048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      }
5058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      return &data.shortData;
5068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    default:
5078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      status = U_ILLEGAL_ARGUMENT_ERROR;
5088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      return NULL;
5098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
5108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
5118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
5128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// loadCDFLocaleData loads formatting data from CLDR for a given locale. The
5138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// caller owns the returned pointer.
5148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status) {
5158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
5168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
5178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
5188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFLocaleData* result = new CDFLocaleData;
5198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (result == NULL) {
5208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    status = U_MEMORY_ALLOCATION_ERROR;
5218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
5228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
5238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  result->Init(status);
5248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
5258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    delete result;
5268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
5278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
5288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
52964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  load(inLocale, result, status);
53064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
5318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
5328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    delete result;
5338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
5348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
5358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return result;
5368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
5378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
53864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertnamespace {
5398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
54064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstruct CmptDecDataSink : public ResourceSink {
54164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
54264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  CDFLocaleData& dataBundle; // Where to save values when they are read
54364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  UBool isLatin; // Whether or not we are traversing the Latin tree
54464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  UBool isFallback; // Whether or not we are traversing the Latin tree as fallback
54564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
54664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  enum EPatternsTableKey { PATTERNS_SHORT, PATTERNS_LONG };
54764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  enum EFormatsTableKey { DECIMAL_FORMAT, CURRENCY_FORMAT };
5488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
54964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  /*
55064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert   * NumberElements{              <-- top (numbering system table)
55164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert   *  latn{                       <-- patternsTable (one per numbering system)
55264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert   *    patternsLong{             <-- formatsTable (one per pattern)
55364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert   *      decimalFormat{          <-- powersOfTenTable (one per format)
55464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert   *        1000{                 <-- pluralVariantsTable (one per power of ten)
55564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert   *          one{"0 thousand"}   <-- plural variant and template
55664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert   */
55764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
55864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  CmptDecDataSink(CDFLocaleData& _dataBundle)
55964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    : dataBundle(_dataBundle), isLatin(FALSE), isFallback(FALSE) {}
56064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  virtual ~CmptDecDataSink();
56164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
56264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  virtual void put(const char *key, ResourceValue &value, UBool isRoot, UErrorCode &errorCode) {
56364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    // SPECIAL CASE: Don't consume root in the non-Latin numbering system
56464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    if (isRoot && !isLatin) { return; }
56564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
56664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    ResourceTable patternsTable = value.getTable(errorCode);
56764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    if (U_FAILURE(errorCode)) { return; }
56864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    for (int i1 = 0; patternsTable.getKeyAndValue(i1, key, value); ++i1) {
56964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
57064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      // Check for patternsShort or patternsLong
57164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      EPatternsTableKey patternsTableKey;
57264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      if (uprv_strcmp(key, gPatternsShort) == 0) {
57364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        patternsTableKey = PATTERNS_SHORT;
57464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      } else if (uprv_strcmp(key, gPatternsLong) == 0) {
57564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        patternsTableKey = PATTERNS_LONG;
57664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      } else {
57764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        continue;
5788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      }
5798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
58064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      // Traverse into the formats table
58164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      ResourceTable formatsTable = value.getTable(errorCode);
58264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      if (U_FAILURE(errorCode)) { return; }
58364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      for (int i2 = 0; formatsTable.getKeyAndValue(i2, key, value); ++i2) {
58464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
58564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // Check for decimalFormat or currencyFormat
58664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        EFormatsTableKey formatsTableKey;
58764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if (uprv_strcmp(key, gDecimalFormatTag) == 0) {
58864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          formatsTableKey = DECIMAL_FORMAT;
58964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // TODO: Enable this statement when currency support is added
59064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // } else if (uprv_strcmp(key, gCurrencyFormat) == 0) {
59164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //   formatsTableKey = CURRENCY_FORMAT;
59264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        } else {
59364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          continue;
59464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        }
59564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
59664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // Set the current style and destination based on the two keys
59764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        UNumberCompactStyle style;
59864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        CDFLocaleStyleData* destination = NULL;
59964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if (patternsTableKey == PATTERNS_LONG
60064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            && formatsTableKey == DECIMAL_FORMAT) {
60164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          style = UNUM_LONG;
60264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          destination = &dataBundle.longData;
60364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        } else if (patternsTableKey == PATTERNS_SHORT
60464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            && formatsTableKey == DECIMAL_FORMAT) {
60564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          style = UNUM_SHORT;
60664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          destination = &dataBundle.shortData;
60764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // TODO: Enable the following statements when currency support is added
60864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // } else if (patternsTableKey == PATTERNS_SHORT
60964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //     && formatsTableKey == CURRENCY_FORMAT) {
61064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //   style = UNUM_SHORT_CURRENCY; // or whatever the enum gets named
61164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //   destination = &dataBundle.shortCurrencyData;
61264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // } else {
61364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //   // Silently ignore this case
61464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //   continue;
61564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        }
61664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
61764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // SPECIAL CASE: RULES FOR WHETHER OR NOT TO CONSUME THIS TABLE:
61864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //   1) Don't consume longData if shortData was consumed from the non-Latin
61964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //      locale numbering system
62064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //   2) Don't consume longData for the first time if this is the root bundle and
62164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //      shortData is already populated from a more specific locale. Note that if
62264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //      both longData and shortData are both only in root, longData will be
62364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        //      consumed since it is alphabetically before shortData in the bundle.
62464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if (isFallback
62564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                && style == UNUM_LONG
62664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                && !dataBundle.shortData.isEmpty()
62764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                && !dataBundle.shortData.fromFallback) {
62864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            continue;
62964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        }
63064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if (isRoot
63164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                && style == UNUM_LONG
63264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                && dataBundle.longData.isEmpty()
63364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                && !dataBundle.shortData.isEmpty()) {
63464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            continue;
63564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        }
63664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
63764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // Set the "fromFallback" flag on the data object
63864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        destination->fromFallback = isFallback;
63964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
64064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        // Traverse into the powers of ten table
64164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        ResourceTable powersOfTenTable = value.getTable(errorCode);
64264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if (U_FAILURE(errorCode)) { return; }
64364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) {
64464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
64564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          // The key will always be some even power of 10. e.g 10000.
64664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          char* endPtr = NULL;
64764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          double power10 = uprv_strtod(key, &endPtr);
64864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          if (*endPtr != 0) {
64964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            errorCode = U_INTERNAL_PROGRAM_ERROR;
65064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            return;
65164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          }
65264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          int32_t log10Value = computeLog10(power10, FALSE);
65364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
65464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          // Silently ignore divisors that are too big.
65564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          if (log10Value >= MAX_DIGITS) continue;
65664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
65764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          // Iterate over the plural variants ("one", "other", etc)
65864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          ResourceTable pluralVariantsTable = value.getTable(errorCode);
65964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          if (U_FAILURE(errorCode)) { return; }
66064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          for (int i4 = 0; pluralVariantsTable.getKeyAndValue(i4, key, value); ++i4) {
66164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            const char* pluralVariant = key;
66264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            const UnicodeString formatStr = value.getUnicodeString(errorCode);
66364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
66464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // Copy the data into the in-memory data bundle (do not overwrite
66564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // existing values)
66664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            int32_t numZeros = populatePrefixSuffix(
66764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                pluralVariant, log10Value, formatStr,
66864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                destination->unitsByVariant, FALSE, errorCode);
66964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
67064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // If populatePrefixSuffix returns -1, it means that this key has been
67164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // encountered already.
67264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            if (numZeros < 0) {
67364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert              continue;
67464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            }
67564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
67664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // Set the divisor, which is based on the number of zeros in the template
67764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // string.  If the divisor from here is different from the one previously
67864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // stored, it means that the number of zeros in different plural variants
67964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // differs; throw an exception.
68064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // TODO: How should I check for floating-point errors here?
68164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            //       Is there a good reason why "divisor" is double and not long like Java?
68264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            double divisor = calculateDivisor(power10, numZeros);
68364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            if (destination->divisors[log10Value] != 0.0
68464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                && destination->divisors[log10Value] != divisor) {
68564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert              errorCode = U_INTERNAL_PROGRAM_ERROR;
68664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert              return;
68764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            }
68864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            destination->divisors[log10Value] = divisor;
6898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius          }
6908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        }
6918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      }
69264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    }
6938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
69464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert};
6958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
69664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// Virtual destructors must be defined out of line.
69764339d36f8bd4db5025fe2988eda22b491a9219cFredrik RoubertCmptDecDataSink::~CmptDecDataSink() {}
6988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
69964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert} // namespace
7008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
70164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status) {
70264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(inLocale, status));
7038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
7048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return;
7058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
70664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  const char* nsName = ns->getName();
7078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
70864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  LocalUResourceBundlePointer resource(ures_open(NULL, inLocale.getName(), &status));
7098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
7108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return;
7118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
71264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  CmptDecDataSink sink(*result);
71364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  sink.isFallback = FALSE;
71464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
71564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // First load the number elements data if nsName is not Latin.
71664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  if (uprv_strcmp(nsName, gLatnTag) != 0) {
71764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    sink.isLatin = FALSE;
71864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    CharString path;
71964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    path.append(gNumberElementsTag, status)
72064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        .append('/', status)
72164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        .append(nsName, status);
72264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    ures_getAllItemsWithFallback(resource.getAlias(), path.data(), sink, status);
72364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    if (status == U_MISSING_RESOURCE_ERROR) {
72464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      // Silently ignore and use Latin
72564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      status = U_ZERO_ERROR;
72664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    } else if  (U_FAILURE(status)) {
7278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      return;
7288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
72964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    sink.isFallback = TRUE;
7308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
73164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
73264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // Now load Latin.
73364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  sink.isLatin = TRUE;
73464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  ures_getAllItemsWithFallback(resource.getAlias(), gLatnPath, sink, status);
73564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  if (U_FAILURE(status)) return;
73664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
73764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // If longData is empty, default it to be equal to shortData
73864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  if (result->longData.isEmpty()) {
73964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    result->longData.setToBogus();
7408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
74164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
74264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // Check for "other" variants in each of the three data classes, and resolve missing elements.
74364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
74464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  if (!result->longData.isBogus()) {
74564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    checkForOtherVariants(&result->longData, status);
74664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    if (U_FAILURE(status)) return;
74764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    fillInMissing(&result->longData);
7488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
74964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
75064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  checkForOtherVariants(&result->shortData, status);
75164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  if (U_FAILURE(status)) return;
75264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  fillInMissing(&result->shortData);
75364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
75464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // TODO: Enable this statement when currency support is added
75564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // checkForOtherVariants(&result->shortCurrencyData, status);
75664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // if (U_FAILURE(status)) return;
75764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // fillInMissing(&result->shortCurrencyData);
7588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
7598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
7608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// populatePrefixSuffix Adds a specific prefix-suffix pair to result for a
7618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// given variant and log10 value.
7628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// variant is 'zero', 'one', 'two', 'few', 'many', or 'other'.
7638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// formatStr is the format string from which the prefix and suffix are
7648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// extracted. It is usually of form 'Pefix 000 suffix'.
7658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// populatePrefixSuffix returns the number of 0's found in formatStr
7668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// before the decimal point.
7678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// In the special case that formatStr contains only spaces for prefix
7688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// and suffix, populatePrefixSuffix returns log10Value + 1.
7698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic int32_t populatePrefixSuffix(
77064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UBool overwrite, UErrorCode& status) {
7718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
7728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return 0;
7738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
7740596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
7750596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  // ICU 59 HACK: Ignore negative part of format string, mimicking ICU 58 behavior.
7760596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  // TODO(sffc): Make sure this is fixed during the overhaul port in ICU 60.
7770596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  int32_t semiPos = formatStr.indexOf(';', 0);
7780596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  if (semiPos == -1) {
7790596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    semiPos = formatStr.length();
7800596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  }
7810596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  UnicodeString positivePart = formatStr.tempSubString(0, semiPos);
7820596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
7830596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  int32_t firstIdx = positivePart.indexOf(kZero, UPRV_LENGTHOF(kZero), 0);
7848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // We must have 0's in format string.
7858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (firstIdx == -1) {
7868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    status = U_INTERNAL_PROGRAM_ERROR;
7878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return 0;
7888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
7890596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  int32_t lastIdx = positivePart.lastIndexOf(kZero, UPRV_LENGTHOF(kZero), firstIdx);
7908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFUnit* unit = createCDFUnit(variant, log10Value, result, status);
7918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
7928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return 0;
7938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
79464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
79564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // Return -1 if we are not overwriting an existing value
79664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  if (unit->isSet() && !overwrite) {
79764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    return -1;
79864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  }
79964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  unit->markAsSet();
80064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
8018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Everything up to first 0 is the prefix
8020596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  unit->prefix = positivePart.tempSubString(0, firstIdx);
8038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  fixQuotes(unit->prefix);
8048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Everything beyond the last 0 is the suffix
8050596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  unit->suffix = positivePart.tempSubString(lastIdx + 1);
8068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  fixQuotes(unit->suffix);
8078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
8088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // If there is effectively no prefix or suffix, ignore the actual number of
8098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // 0's and act as if the number of 0's matches the size of the number.
8108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (onlySpaces(unit->prefix) && onlySpaces(unit->suffix)) {
8118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return log10Value + 1;
8128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
8138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
8148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Calculate number of zeros before decimal point
8158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  int32_t idx = firstIdx + 1;
8160596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  while (idx <= lastIdx && positivePart.charAt(idx) == u_0) {
8178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    ++idx;
8188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
8198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return (idx - firstIdx);
8208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
8218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
82264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// Calculate a divisor based on the magnitude and number of zeros in the
82364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// template string.
82464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic double calculateDivisor(double power10, int32_t numZeros) {
82564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  double divisor = power10;
82664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  for (int32_t i = 1; i < numZeros; ++i) {
82764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    divisor /= 10.0;
82864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  }
82964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  return divisor;
83064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert}
83164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
8328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic UBool onlySpaces(UnicodeString u) {
8338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return u.trim().length() == 0;
8348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
8358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
8368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// fixQuotes unescapes single quotes. Don''t -> Don't. Letter 'j' -> Letter j.
8378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// Modifies s in place.
8388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic void fixQuotes(UnicodeString& s) {
8398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  QuoteState state = OUTSIDE;
8408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  int32_t len = s.length();
8418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  int32_t dest = 0;
8428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  for (int32_t i = 0; i < len; ++i) {
8438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UChar ch = s.charAt(i);
8448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (ch == u_apos) {
8458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      if (state == INSIDE_EMPTY) {
8468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        s.setCharAt(dest, ch);
8478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        ++dest;
8488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      }
8498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    } else {
8508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      s.setCharAt(dest, ch);
8518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      ++dest;
8528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
8538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
8548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    // Update state
8558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    switch (state) {
8568393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      case OUTSIDE:
8578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        state = ch == u_apos ? INSIDE_EMPTY : OUTSIDE;
8588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        break;
8598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      case INSIDE_EMPTY:
8608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      case INSIDE_FULL:
8618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        state = ch == u_apos ? OUTSIDE : INSIDE_FULL;
8628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        break;
8638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      default:
8648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        break;
8658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
8668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
8678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  s.truncate(dest);
8688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
8698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
87064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// Checks to make sure that an "other" variant is present in all
87164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// powers of 10.
87264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic void checkForOtherVariants(CDFLocaleStyleData* result,
87364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    UErrorCode& status) {
87464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  if (result == NULL || result->unitsByVariant == NULL) {
87564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    return;
87664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  }
87764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
87864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  const CDFUnit* otherByBase =
87964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      (const CDFUnit*) uhash_get(result->unitsByVariant, gOther);
88064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  if (otherByBase == NULL) {
88164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    status = U_INTERNAL_PROGRAM_ERROR;
88264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    return;
88364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  }
88464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
88564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // Check all other plural variants, and make sure that if
88664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  // any of them are populated, then other is also populated
88764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  int32_t pos = UHASH_FIRST;
88864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  const UHashElement* element;
88964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  while ((element = uhash_nextElement(result->unitsByVariant, &pos)) != NULL) {
89064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    CDFUnit* variantsByBase = (CDFUnit*) element->value.pointer;
89164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    if (variantsByBase == otherByBase) continue;
89264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    for (int32_t log10Value = 0; log10Value < MAX_DIGITS; ++log10Value) {
89364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      if (variantsByBase[log10Value].isSet()
89464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          && !otherByBase[log10Value].isSet()) {
89564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        status = U_INTERNAL_PROGRAM_ERROR;
89664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        return;
89764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert      }
89864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    }
89964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  }
90064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert}
90164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
9028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// fillInMissing ensures that the data in result is complete.
9038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// result data is complete if for each variant in result, there exists
9048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// a prefix-suffix pair for each log10 value and there also exists
9058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// a divisor for each log10 value.
9068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius//
9078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// First this function figures out for which log10 values, the other
9088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// variant already had data. These are the same log10 values defined
9098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// in CLDR.
9108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius//
9118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// For each log10 value not defined in CLDR, it uses the divisor for
9128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// the last defined log10 value or 1.
9138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius//
9148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// Then for each variant, it does the following. For each log10
9158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// value not defined in CLDR, copy the prefix-suffix pair from the
9168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// previous log10 value. If log10 value is defined in CLDR but is
9178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// missing from given variant, copy the prefix-suffix pair for that
9188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// log10 value from the 'other' variant.
9198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic void fillInMissing(CDFLocaleStyleData* result) {
9208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  const CDFUnit* otherUnits =
9218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      (const CDFUnit*) uhash_get(result->unitsByVariant, gOther);
9228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  UBool definedInCLDR[MAX_DIGITS];
9238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  double lastDivisor = 1.0;
9248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  for (int32_t i = 0; i < MAX_DIGITS; ++i) {
9258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (!otherUnits[i].isSet()) {
9268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      result->divisors[i] = lastDivisor;
9278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      definedInCLDR[i] = FALSE;
9288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    } else {
9298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      lastDivisor = result->divisors[i];
9308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      definedInCLDR[i] = TRUE;
9318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
9328393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
9338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  // Iterate over each variant.
9341b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert  int32_t pos = UHASH_FIRST;
9358393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  const UHashElement* element = uhash_nextElement(result->unitsByVariant, &pos);
9368393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  for (;element != NULL; element = uhash_nextElement(result->unitsByVariant, &pos)) {
9378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    CDFUnit* units = (CDFUnit*) element->value.pointer;
9388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    for (int32_t i = 0; i < MAX_DIGITS; ++i) {
9398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      if (definedInCLDR[i]) {
9408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        if (!units[i].isSet()) {
9418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius          units[i] = otherUnits[i];
9428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        }
9438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      } else {
9448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        if (i == 0) {
9458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius          units[0].markAsSet();
9468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        } else {
9478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius          units[i] = units[i - 1];
9488393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        }
9498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      }
9508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
9518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
9528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
9538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
9548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// computeLog10 computes floor(log10(x)). If inRange is TRUE, the biggest
9558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// value computeLog10 will return MAX_DIGITS -1 even for
9568393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// numbers > 10^MAX_DIGITS. If inRange is FALSE, computeLog10 will return
9578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// up to MAX_DIGITS.
9588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic int32_t computeLog10(double x, UBool inRange) {
9598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  int32_t result = 0;
9608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  int32_t max = inRange ? MAX_DIGITS - 1 : MAX_DIGITS;
9618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  while (x >= 10.0) {
9628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    x /= 10.0;
9638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    ++result;
9648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (result == max) {
9658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      break;
9668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
9678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
9688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return result;
9698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
9708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
9718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// createCDFUnit returns a pointer to the prefix-suffix pair for a given
9728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// variant and log10 value within table. If no such prefix-suffix pair is
9738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// stored in table, one is created within table before returning pointer.
9748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status) {
9758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (U_FAILURE(status)) {
9768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return NULL;
9778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
9788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFUnit *cdfUnit = (CDFUnit*) uhash_get(table, variant);
9798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (cdfUnit == NULL) {
9808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    cdfUnit = new CDFUnit[MAX_DIGITS];
9818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (cdfUnit == NULL) {
9828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      status = U_MEMORY_ALLOCATION_ERROR;
9838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      return NULL;
9848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
9858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    uhash_put(table, uprv_strdup(variant), cdfUnit, &status);
9868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (U_FAILURE(status)) {
9878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius      return NULL;
9888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
9898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
9908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CDFUnit* result = &cdfUnit[log10Value];
9918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return result;
9928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
9938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
9948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// getCDFUnitFallback returns a pointer to the prefix-suffix pair for a given
9958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// variant and log10 value within table. If the given variant doesn't exist, it
9968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// falls back to the OTHER variant. Therefore, this method will always return
9978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius// some non-NULL value.
9988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value) {
9998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  CharString cvariant;
10008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  UErrorCode status = U_ZERO_ERROR;
10018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  const CDFUnit *cdfUnit = NULL;
10028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  cvariant.appendInvariantChars(variant, status);
10038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (!U_FAILURE(status)) {
10048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    cdfUnit = (const CDFUnit*) uhash_get(table, cvariant.data());
10058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
10068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  if (cdfUnit == NULL) {
10078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    cdfUnit = (const CDFUnit*) uhash_get(table, gOther);
10088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  }
10098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius  return &cdfUnit[log10Value];
10108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
10118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
10128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusU_NAMESPACE_END
10138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#endif
1014