From 11ddfe3376d7d0af51e55fc0d366ae3cebf7c029 Mon Sep 17 00:00:00 2001 From: Markus Scherer Date: Mon, 16 May 2016 17:23:18 +0000 Subject: [PATCH] ICU-7434 switch DecimalFormatSymbols from SimpleCache to SoftCache X-SVN-Rev: 38744 --- .../ibm/icu/text/DecimalFormatSymbols.java | 205 ++++++++++-------- 1 file changed, 109 insertions(+), 96 deletions(-) diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormatSymbols.java b/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormatSymbols.java index e44b887902e..154a85da008 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormatSymbols.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormatSymbols.java @@ -13,14 +13,14 @@ import java.util.Arrays; import java.util.Locale; import java.util.MissingResourceException; +import com.ibm.icu.impl.CacheBase; import com.ibm.icu.impl.CurrencyData; import com.ibm.icu.impl.CurrencyData.CurrencyDisplayInfo; import com.ibm.icu.impl.CurrencyData.CurrencyFormatInfo; import com.ibm.icu.impl.CurrencyData.CurrencySpacingInfo; -import com.ibm.icu.impl.ICUCache; import com.ibm.icu.impl.ICUData; import com.ibm.icu.impl.ICUResourceBundle; -import com.ibm.icu.impl.SimpleCache; +import com.ibm.icu.impl.SoftCache; import com.ibm.icu.util.Currency; import com.ibm.icu.util.ICUCloneNotSupportedException; import com.ibm.icu.util.ULocale; @@ -212,6 +212,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { */ public void setZeroDigit(char zeroDigit) { if ( digits != null ) { + digits = digits.clone(); // Do not change cached digits. this.digits[0] = zeroDigit; if (Character.digit(zeroDigit,10) == 0) { for ( int i = 1 ; i < 10 ; i++ ) { @@ -921,102 +922,15 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { } /** - * Initializes the symbols from the LocaleElements resource bundle. - * Note: The organization of LocaleElements badly needs to be - * cleaned up. + * Initializes the symbols from the locale data. */ private void initialize( ULocale locale ) { this.requestedLocale = locale.toLocale(); this.ulocale = locale; - - String nsName; - // Attempt to set the zero digit based on the numbering system for the locale requested - NumberingSystem ns = NumberingSystem.getInstance(locale); - digits = new char[10]; - if ( ns != null && ns.getRadix() == 10 && !ns.isAlgorithmic() && - NumberingSystem.isValidDigitString(ns.getDescription())) { - String digitString = ns.getDescription(); - digits[0] = digitString.charAt(0); - digits[1] = digitString.charAt(1); - digits[2] = digitString.charAt(2); - digits[3] = digitString.charAt(3); - digits[4] = digitString.charAt(4); - digits[5] = digitString.charAt(5); - digits[6] = digitString.charAt(6); - digits[7] = digitString.charAt(7); - digits[8] = digitString.charAt(8); - digits[9] = digitString.charAt(9); - nsName = ns.getName(); - } else { - digits[0] = DecimalFormat.PATTERN_ZERO_DIGIT; - digits[1] = DecimalFormat.PATTERN_ONE_DIGIT; - digits[2] = DecimalFormat.PATTERN_TWO_DIGIT; - digits[3] = DecimalFormat.PATTERN_THREE_DIGIT; - digits[4] = DecimalFormat.PATTERN_FOUR_DIGIT; - digits[5] = DecimalFormat.PATTERN_FIVE_DIGIT; - digits[6] = DecimalFormat.PATTERN_SIX_DIGIT; - digits[7] = DecimalFormat.PATTERN_SEVEN_DIGIT; - digits[8] = DecimalFormat.PATTERN_EIGHT_DIGIT; - digits[9] = DecimalFormat.PATTERN_NINE_DIGIT; - nsName = LATIN_NUMBERING_SYSTEM; // Default numbering system - } - - // Open the resource bundle and get the locale IDs - // TODO: Is there a better way to get the locale than making an ICUResourceBundle instance? - ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle. - getBundleInstance(ICUData.ICU_BASE_NAME, locale); - // TODO: Determine actual and valid locale correctly. - ULocale uloc = rb.getULocale(); - setLocale(uloc, uloc); - - // Try loading from the cache - String[][] data = cachedLocaleData.get(locale); - if (data == null) { - // Cache miss! - // TODO: There does not appear to be a good reason why the "data" array is 2-D. - data = new String[1][SYMBOL_KEYS.length]; - - // Load using a data sink - DecFmtDataSink sink = new DecFmtDataSink(data[0]); - try { - rb.getAllItemsWithFallback(NUMBER_ELEMENTS + "/" + nsName + "/" + SYMBOLS, sink); - } catch (MissingResourceException e) { - // The symbols don't exist for the given nsName and resource bundle. - // Silently ignore and fall back to Latin. - } - - // Load the Latin fallback if necessary - boolean hasNull = false; - for (String entry : data[0]) { - if (entry == null) { - hasNull = true; - break; - } - } - if (hasNull && !nsName.equals(LATIN_NUMBERING_SYSTEM)) { - rb.getAllItemsWithFallback(NUMBER_ELEMENTS + "/" + LATIN_NUMBERING_SYSTEM + "/" + SYMBOLS, sink); - } - - // If monetary decimal or grouping were not explicitly set, then set them to be the same as - // their non-monetary counterparts. - if (data[0][10] == null) { - data[0][10] = data[0][0]; - } - if (data[0][11] == null) { - data[0][11] = data[0][1]; - } - - // Fill in any remaining missing values - for (int i = 0; i < SYMBOL_KEYS.length; i++) { - if (data[0][i] == null) { - data[0][i] = SYMBOL_DEFAULTS[i]; - } - } - - // Save in cache - cachedLocaleData.put(locale, data); - } - String[] numberElements = data[0]; + CacheData data = cachedLocaleData.getInstance(locale, null /* unused */); + setLocale(data.validLocale, data.validLocale); + digits = data.digits; + String[] numberElements = data.numberElements; // Copy data from the numberElements map into instance fields decimalSeparator = numberElements[0].charAt(0); @@ -1067,6 +981,88 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { initSpacingInfo(info.getSpacingInfo()); } + private static CacheData loadData(ULocale locale) { + String nsName; + // Attempt to set the decimal digits based on the numbering system for the requested locale. + NumberingSystem ns = NumberingSystem.getInstance(locale); + char[] digits = new char[10]; + if (ns != null && ns.getRadix() == 10 && !ns.isAlgorithmic() && + NumberingSystem.isValidDigitString(ns.getDescription())) { + String digitString = ns.getDescription(); + digits[0] = digitString.charAt(0); + digits[1] = digitString.charAt(1); + digits[2] = digitString.charAt(2); + digits[3] = digitString.charAt(3); + digits[4] = digitString.charAt(4); + digits[5] = digitString.charAt(5); + digits[6] = digitString.charAt(6); + digits[7] = digitString.charAt(7); + digits[8] = digitString.charAt(8); + digits[9] = digitString.charAt(9); + nsName = ns.getName(); + } else { + digits[0] = DecimalFormat.PATTERN_ZERO_DIGIT; + digits[1] = DecimalFormat.PATTERN_ONE_DIGIT; + digits[2] = DecimalFormat.PATTERN_TWO_DIGIT; + digits[3] = DecimalFormat.PATTERN_THREE_DIGIT; + digits[4] = DecimalFormat.PATTERN_FOUR_DIGIT; + digits[5] = DecimalFormat.PATTERN_FIVE_DIGIT; + digits[6] = DecimalFormat.PATTERN_SIX_DIGIT; + digits[7] = DecimalFormat.PATTERN_SEVEN_DIGIT; + digits[8] = DecimalFormat.PATTERN_EIGHT_DIGIT; + digits[9] = DecimalFormat.PATTERN_NINE_DIGIT; + nsName = "latn"; // Default numbering system + } + + // Open the resource bundle and get the locale IDs. + // TODO: Is there a better way to get the locale than making an ICUResourceBundle instance? + ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle. + getBundleInstance(ICUData.ICU_BASE_NAME, locale); + // TODO: Determine actual and valid locale correctly. + ULocale validLocale = rb.getULocale(); + + String[] numberElements = new String[SYMBOL_KEYS.length]; + + // Load using a data sink + DecFmtDataSink sink = new DecFmtDataSink(numberElements); + try { + rb.getAllItemsWithFallback(NUMBER_ELEMENTS + "/" + nsName + "/" + SYMBOLS, sink); + } catch (MissingResourceException e) { + // The symbols don't exist for the given nsName and resource bundle. + // Silently ignore and fall back to Latin. + } + + // Load the Latin fallback if necessary + boolean hasNull = false; + for (String entry : numberElements) { + if (entry == null) { + hasNull = true; + break; + } + } + if (hasNull && !nsName.equals(LATIN_NUMBERING_SYSTEM)) { + rb.getAllItemsWithFallback(NUMBER_ELEMENTS + "/" + LATIN_NUMBERING_SYSTEM + "/" + SYMBOLS, sink); + } + + // If monetary decimal or grouping were not explicitly set, then set them to be the same as + // their non-monetary counterparts. + if (numberElements[10] == null) { + numberElements[10] = numberElements[0]; + } + if (numberElements[11] == null) { + numberElements[11] = numberElements[1]; + } + + // Fill in any remaining missing values + for (int i = 0; i < SYMBOL_KEYS.length; i++) { + if (numberElements[i] == null) { + numberElements[i] = SYMBOL_DEFAULTS[i]; + } + } + + return new CacheData(validLocale, digits, numberElements); + } + private void initSpacingInfo(CurrencySpacingInfo spcInfo) { currencySpcBeforeSym[CURRENCY_SPC_CURRENCY_MATCH] = spcInfo.beforeCurrencyMatch; currencySpcBeforeSym[CURRENCY_SPC_SURROUNDING_MATCH] = spcInfo.beforeContextMatch; @@ -1387,8 +1383,13 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { /** * cache to hold the NumberElements of a Locale. */ - private static final ICUCache cachedLocaleData = - new SimpleCache(); + private static final CacheBase cachedLocaleData = + new SoftCache() { + @Override + protected CacheData createInstance(ULocale locale, Void unused) { + return DecimalFormatSymbols.loadData(locale); + } + }; /** * @@ -1470,4 +1471,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { private transient Currency currency; // -------- END ULocale boilerplate -------- + + private static class CacheData { + final ULocale validLocale; + final char[] digits; + final String[] numberElements; + + public CacheData(ULocale loc, char[] digits, String[] numberElements) { + validLocale = loc; + this.digits = digits; + this.numberElements = numberElements; + } + } } -- 2.40.0