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