]> granicus.if.org Git - icu/commitdiff
ICU-13634 Centralizing data loading for pattern strings.
authorShane Carr <shane@unicode.org>
Sat, 14 Apr 2018 08:10:45 +0000 (08:10 +0000)
committerShane Carr <shane@unicode.org>
Sat, 14 Apr 2018 08:10:45 +0000 (08:10 +0000)
X-SVN-Rev: 41230

icu4c/source/i18n/decimfmt.cpp
icu4c/source/i18n/number_formatimpl.cpp
icu4c/source/i18n/number_scientific.cpp
icu4c/source/i18n/number_skeletons.cpp
icu4c/source/i18n/number_utils.cpp
icu4c/source/i18n/number_utils.h
icu4c/source/i18n/numfmt.cpp

index 46974b3665144957b2507ada029c59a00ab7d047..8ca75eb10a9dee9dae5ec844b3c5398828ebec0b 100644 (file)
@@ -34,6 +34,16 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
 
 DecimalFormat::DecimalFormat(UErrorCode& status)
         : DecimalFormat(nullptr, status) {
+    // Use the default locale and decimal pattern.
+    const char* localeName = Locale::getDefault().getName();
+    LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(status));
+    UnicodeString patternString = utils::getPatternForStyle(
+            localeName,
+            ns->getName(),
+            CLDR_PATTERN_STYLE_DECIMAL,
+            status);
+    setPropertiesFromPattern(patternString, IGNORE_ROUNDING_IF_CURRENCY, status);
+    refreshFormatter(status);
 }
 
 DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status)
index c0dee2e615371e8c4fad61b2290a48ebcd720fe0..f198187921cdef8a74aaf18d4547bd90d2e4ebff 100644 (file)
@@ -26,70 +26,6 @@ using namespace icu::number::impl;
 
 namespace {
 
-// NOTE: In Java, the method to get a pattern from the resource bundle exists in NumberFormat.
-// In C++, we have to implement that logic here.
-// TODO: Make Java and C++ consistent?
-
-enum CldrPatternStyle {
-    CLDR_PATTERN_STYLE_DECIMAL,
-    CLDR_PATTERN_STYLE_CURRENCY,
-    CLDR_PATTERN_STYLE_ACCOUNTING,
-    CLDR_PATTERN_STYLE_PERCENT
-    // TODO: Consider scientific format.
-};
-
-const char16_t*
-doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus,
-             UErrorCode& localStatus) {
-    // Construct the path into the resource bundle
-    CharString key;
-    key.append("NumberElements/", publicStatus);
-    key.append(nsName, publicStatus);
-    key.append("/patterns/", publicStatus);
-    key.append(patternKey, publicStatus);
-    if (U_FAILURE(publicStatus)) {
-        return u"";
-    }
-    return ures_getStringByKeyWithFallback(res, key.data(), nullptr, &localStatus);
-}
-
-const char16_t* getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style,
-                                   UErrorCode& status) {
-    const char* patternKey;
-    switch (style) {
-        case CLDR_PATTERN_STYLE_DECIMAL:
-            patternKey = "decimalFormat";
-            break;
-        case CLDR_PATTERN_STYLE_CURRENCY:
-            patternKey = "currencyFormat";
-            break;
-        case CLDR_PATTERN_STYLE_ACCOUNTING:
-            patternKey = "accountingFormat";
-            break;
-        case CLDR_PATTERN_STYLE_PERCENT:
-        default:
-            patternKey = "percentFormat";
-            break;
-    }
-    LocalUResourceBundlePointer res(ures_open(nullptr, locale.getName(), &status));
-    if (U_FAILURE(status)) { return u""; }
-
-    // Attempt to get the pattern with the native numbering system.
-    UErrorCode localStatus = U_ZERO_ERROR;
-    const char16_t* pattern;
-    pattern = doGetPattern(res.getAlias(), nsName, patternKey, status, localStatus);
-    if (U_FAILURE(status)) { return u""; }
-
-    // Fall back to latn if native numbering system does not have the right pattern
-    if (U_FAILURE(localStatus) && uprv_strcmp("latn", nsName) != 0) {
-        localStatus = U_ZERO_ERROR;
-        pattern = doGetPattern(res.getAlias(), "latn", patternKey, status, localStatus);
-        if (U_FAILURE(status)) { return u""; }
-    }
-
-    return pattern;
-}
-
 struct CurrencyFormatInfoResult {
     bool exists;
     const char16_t* pattern;
@@ -195,10 +131,10 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
     // TODO: Accept currency symbols from DecimalFormatSymbols?
 
     // Pre-compute a few values for efficiency.
-    bool isCurrency = unitIsCurrency(macros.unit);
-    bool isNoUnit = unitIsNoUnit(macros.unit);
-    bool isPercent = isNoUnit && unitIsPercent(macros.unit);
-    bool isPermille = isNoUnit && unitIsPermille(macros.unit);
+    bool isCurrency = utils::unitIsCurrency(macros.unit);
+    bool isNoUnit = utils::unitIsNoUnit(macros.unit);
+    bool isPercent = isNoUnit && utils::unitIsPercent(macros.unit);
+    bool isPermille = isNoUnit && utils::unitIsPermille(macros.unit);
     bool isCldrUnit = !isCurrency && !isNoUnit;
     bool isAccounting =
             macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS ||
@@ -277,7 +213,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
         } else {
             patternStyle = CLDR_PATTERN_STYLE_CURRENCY;
         }
-        pattern = getPatternForStyle(macros.locale, nsName, patternStyle, status);
+        pattern = utils::getPatternForStyle(macros.locale, nsName, patternStyle, status);
     }
     auto patternInfo = new ParsedPatternInfo();
     fPatternInfo.adoptInstead(patternInfo);
@@ -522,7 +458,7 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima
 
         // Get and append the next digit value
         int8_t nextDigit = quantity.getDigit(i);
-        length += insertDigitFromSymbols(
+        length += utils::insertDigitFromSymbols(
                 string, 0, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
     }
     return length;
@@ -535,7 +471,7 @@ int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, Decim
     for (int i = 0; i < fractionCount; i++) {
         // Get and append the next digit value
         int8_t nextDigit = quantity.getDigit(-i - 1);
-        length += insertDigitFromSymbols(
+        length += utils::insertDigitFromSymbols(
                 string, string.length(), nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
     }
     return length;
index 1d8b020e88e9cc7133c8c95b63c2ecd57298b50c..ce7bb3b68936f0f8bb49be2a05a5faa219d85e98 100644 (file)
@@ -64,7 +64,13 @@ int32_t ScientificModifier::apply(NumberStringBuilder &output, int32_t /*leftInd
     int32_t disp = std::abs(fExponent);
     for (int j = 0; j < fHandler->fSettings.fMinExponentDigits || disp > 0; j++, disp /= 10) {
         auto d = static_cast<int8_t>(disp % 10);
-        i += insertDigitFromSymbols(output, i - j, d, *fHandler->fSymbols, UNUM_EXPONENT_FIELD, status);
+        i += utils::insertDigitFromSymbols(
+                output,
+                i - j,
+                d,
+                *fHandler->fSymbols,
+                UNUM_EXPONENT_FIELD,
+                status);
     }
     return i - rightIndex;
 }
index 81be03b15a4c0be8b6bb199b97a1950ef7ba1d86..35de1358cd0498c7f9785fd6d63e08656800cf24 100644 (file)
@@ -1256,15 +1256,15 @@ bool GeneratorHelpers::notation(const MacroProps& macros, UnicodeString& sb, UEr
 }
 
 bool GeneratorHelpers::unit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
-    if (unitIsCurrency(macros.unit)) {
+    if (utils::unitIsCurrency(macros.unit)) {
         sb.append(u"currency/", -1);
         blueprint_helpers::generateCurrencyOption({macros.unit, status}, sb, status);
         return true;
-    } else if (unitIsNoUnit(macros.unit)) {
-        if (unitIsPercent(macros.unit)) {
+    } else if (utils::unitIsNoUnit(macros.unit)) {
+        if (utils::unitIsPercent(macros.unit)) {
             sb.append(u"percent", -1);
             return true;
-        } else if (unitIsPermille(macros.unit)) {
+        } else if (utils::unitIsPermille(macros.unit)) {
             sb.append(u"permille", -1);
             return true;
         } else {
@@ -1280,15 +1280,15 @@ bool GeneratorHelpers::unit(const MacroProps& macros, UnicodeString& sb, UErrorC
 
 bool GeneratorHelpers::perUnit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
     // Per-units are currently expected to be only MeasureUnits.
-    if (unitIsNoUnit(macros.perUnit)) {
-        if (unitIsPercent(macros.perUnit) || unitIsPermille(macros.perUnit)) {
+    if (utils::unitIsNoUnit(macros.perUnit)) {
+        if (utils::unitIsPercent(macros.perUnit) || utils::unitIsPermille(macros.perUnit)) {
             status = U_UNSUPPORTED_ERROR;
             return false;
         } else {
             // Default value: ok to ignore
             return false;
         }
-    } else if (unitIsCurrency(macros.perUnit)) {
+    } else if (utils::unitIsCurrency(macros.perUnit)) {
         status = U_UNSUPPORTED_ERROR;
         return false;
     } else {
index 8cf702dd3361634a2da9a48357b2eeeb14d1894c..d98f061aa3689e7f17d72cf1176be3c3c07b1784 100644 (file)
@@ -17,6 +17,8 @@
 #include "decContext.h"
 #include "decNumber.h"
 #include "double-conversion.h"
+#include "uresimp.h"
+#include "ureslocs.h"
 
 using namespace icu;
 using namespace icu::number;
@@ -25,6 +27,68 @@ using namespace icu::number::impl;
 using icu::double_conversion::DoubleToStringConverter;
 
 
+namespace {
+
+const char16_t*
+doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus,
+             UErrorCode& localStatus) {
+    // Construct the path into the resource bundle
+    CharString key;
+    key.append("NumberElements/", publicStatus);
+    key.append(nsName, publicStatus);
+    key.append("/patterns/", publicStatus);
+    key.append(patternKey, publicStatus);
+    if (U_FAILURE(publicStatus)) {
+        return u"";
+    }
+    return ures_getStringByKeyWithFallback(res, key.data(), nullptr, &localStatus);
+}
+
+}
+
+
+const char16_t* utils::getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style,
+                                          UErrorCode& status) {
+    const char* patternKey;
+    switch (style) {
+        case CLDR_PATTERN_STYLE_DECIMAL:
+            patternKey = "decimalFormat";
+            break;
+        case CLDR_PATTERN_STYLE_CURRENCY:
+            patternKey = "currencyFormat";
+            break;
+        case CLDR_PATTERN_STYLE_ACCOUNTING:
+            patternKey = "accountingFormat";
+            break;
+        case CLDR_PATTERN_STYLE_PERCENT:
+            patternKey = "percentFormat";
+            break;
+        case CLDR_PATTERN_STYLE_SCIENTIFIC:
+            patternKey = "scientificFormat";
+            break;
+        default:
+            U_ASSERT(false);
+    }
+    LocalUResourceBundlePointer res(ures_open(nullptr, locale.getName(), &status));
+    if (U_FAILURE(status)) { return u""; }
+
+    // Attempt to get the pattern with the native numbering system.
+    UErrorCode localStatus = U_ZERO_ERROR;
+    const char16_t* pattern;
+    pattern = doGetPattern(res.getAlias(), nsName, patternKey, status, localStatus);
+    if (U_FAILURE(status)) { return u""; }
+
+    // Fall back to latn if native numbering system does not have the right pattern
+    if (U_FAILURE(localStatus) && uprv_strcmp("latn", nsName) != 0) {
+        localStatus = U_ZERO_ERROR;
+        pattern = doGetPattern(res.getAlias(), "latn", patternKey, status, localStatus);
+        if (U_FAILURE(status)) { return u""; }
+    }
+
+    return pattern;
+}
+
+
 DecNum::DecNum() {
     uprv_decContextDefault(&fContext, DEC_INIT_BASE);
     uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
index 1afd608ae92e7a39ba3c67e75e5c90200b94139d..1b4000d78c1fd209f49aff8335fe002e509524b4 100644 (file)
@@ -105,6 +105,18 @@ struct MicroProps : public MicroPropsGenerator {
     bool exhausted = false;
 };
 
+enum CldrPatternStyle {
+    CLDR_PATTERN_STYLE_DECIMAL,
+    CLDR_PATTERN_STYLE_CURRENCY,
+    CLDR_PATTERN_STYLE_ACCOUNTING,
+    CLDR_PATTERN_STYLE_PERCENT,
+    CLDR_PATTERN_STYLE_SCIENTIFIC,
+    CLDR_PATTERN_STYLE_COUNT,
+};
+
+// Namespace for naked functions
+namespace utils {
+
 inline int32_t insertDigitFromSymbols(NumberStringBuilder& output, int32_t index, int8_t digit,
                                       const DecimalFormatSymbols& symbols, Field field,
                                       UErrorCode& status) {
@@ -130,6 +142,12 @@ inline bool unitIsPermille(const MeasureUnit& unit) {
     return uprv_strcmp("permille", unit.getSubtype()) == 0;
 }
 
+// NOTE: In Java, this method is in NumberFormat.java
+const char16_t*
+getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, UErrorCode& status);
+
+} // namespace utils
+
 
 /** A very thin C++ wrapper around decNumber.h */
 class DecNum : public UMemory {
index 301b9855b11ad9804be8d93a22f32a2828c7d0e2..4b45ce00a19848be62d4e98c90989659795967d1 100644 (file)
@@ -55,6 +55,7 @@
 #include "sharednumberformat.h"
 #include "unifiedcache.h"
 #include "number_decimalquantity.h"
+#include "number_utils.h"
 
 //#define FMT_DEBUG
 
@@ -129,31 +130,28 @@ static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] =
 
 // Keys used for accessing resource bundles
 
-static const char *gNumberElements = "NumberElements";
-static const char *gLatn = "latn";
-static const char *gPatterns = "patterns";
-static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = {
-    NULL,  // UNUM_PATTERN_DECIMAL
-    "decimalFormat",  // UNUM_DECIMAL
-    "currencyFormat",  // UNUM_CURRENCY
-    "percentFormat",  // UNUM_PERCENT
-    "scientificFormat",  // UNUM_SCIENTIFIC
-    NULL,  // UNUM_SPELLOUT
-    NULL,  // UNUM_ORDINAL
-    NULL,  // UNUM_DURATION
-    NULL,  // UNUM_NUMBERING_SYSTEM
-    NULL,  // UNUM_PATTERN_RULEBASED
+static const icu::number::impl::CldrPatternStyle gFormatCldrStyles[UNUM_FORMAT_STYLE_COUNT] = {
+    /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT,  // UNUM_PATTERN_DECIMAL
+    icu::number::impl::CLDR_PATTERN_STYLE_DECIMAL,  // UNUM_DECIMAL
+    icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY,  // UNUM_CURRENCY
+    icu::number::impl::CLDR_PATTERN_STYLE_PERCENT,  // UNUM_PERCENT
+    icu::number::impl::CLDR_PATTERN_STYLE_SCIENTIFIC,  // UNUM_SCIENTIFIC
+    /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT,  // UNUM_SPELLOUT
+    /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT,  // UNUM_ORDINAL
+    /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT,  // UNUM_DURATION
+    /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT,  // UNUM_NUMBERING_SYSTEM
+    /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT,  // UNUM_PATTERN_RULEBASED
     // For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL,
     // the pattern is the same as the pattern of UNUM_CURRENCY
     // except for replacing the single currency sign with
     // double currency sign or triple currency sign.
-    "currencyFormat",  // UNUM_CURRENCY_ISO
-    "currencyFormat",  // UNUM_CURRENCY_PLURAL
-    "accountingFormat",  // UNUM_CURRENCY_ACCOUNTING
-    "currencyFormat",  // UNUM_CASH_CURRENCY
-    NULL,  // UNUM_DECIMAL_COMPACT_SHORT
-    NULL,  // UNUM_DECIMAL_COMPACT_LONG
-    "currencyFormat",  // UNUM_CURRENCY_STANDARD
+    icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY,  // UNUM_CURRENCY_ISO
+    icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY,  // UNUM_CURRENCY_PLURAL
+    icu::number::impl::CLDR_PATTERN_STYLE_ACCOUNTING,  // UNUM_CURRENCY_ACCOUNTING
+    icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY,  // UNUM_CASH_CURRENCY
+    /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT,  // UNUM_DECIMAL_COMPACT_SHORT
+    /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT,  // UNUM_DECIMAL_COMPACT_LONG
+    icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY,  // UNUM_CURRENCY_STANDARD
 };
 
 // Static hashtable cache of NumberingSystem objects used by NumberFormat
@@ -1400,27 +1398,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
             return NULL;
         }
 
-        UResourceBundle *resource = ownedResource.orphan();
-        UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status);
-        resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status);
-        resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
-        ownedResource.adoptInstead(resource);
-
-        int32_t patLen = 0;
-        const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
-
-        // Didn't find a pattern specific to the numbering system, so fall back to "latn"
-        if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) {  
-            status = U_ZERO_ERROR;
-            resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status);
-            resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
-            patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
-        }
-
-        ures_close(numElements);
-
-        // Creates the specified decimal format style of the desired locale.
-        pattern.setTo(TRUE, patResStr, patLen);
+        // Load the pattern from data using the common library function
+        const char16_t* patternPtr = number::impl::utils::getPatternForStyle(
+                desiredLocale,
+                ns->getName(),
+                gFormatCldrStyles[style],
+                status);
+        pattern = UnicodeString(TRUE, patternPtr, -1);
     }
     if (U_FAILURE(status)) {
         return NULL;