summaryrefslogtreecommitdiffstats
path: root/icu/src/main/java/com
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2009-12-22 17:20:44 -0800
committerElliott Hughes <enh@google.com>2010-01-04 12:54:29 -0800
commit33aa6eb602478e7f51ac16f30c88db3566022886 (patch)
tree0677f00ecb8912abd8588446784313dfd0826663 /icu/src/main/java/com
parent9e615e92c810a490d73a24b31b326c6141867a10 (diff)
downloadlibcore-33aa6eb602478e7f51ac16f30c88db3566022886.zip
libcore-33aa6eb602478e7f51ac16f30c88db3566022886.tar.gz
libcore-33aa6eb602478e7f51ac16f30c88db3566022886.tar.bz2
Stop using ResourceBundle for locale data.
This offers an additional speed increase and gets rid of a lot of native code.
Diffstat (limited to 'icu/src/main/java/com')
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java14
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/util/LocaleData.java169
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/util/Resources.java111
3 files changed, 218 insertions, 76 deletions
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
index 0ceb287..43ac3f2 100644
--- a/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
+++ b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
@@ -17,6 +17,7 @@
package com.ibm.icu4jni.text;
import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatSymbol;
+import com.ibm.icu4jni.util.LocaleData;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -36,18 +37,15 @@ public class DecimalFormatSymbols implements Cloneable {
}
public DecimalFormatSymbols(Locale locale) {
+ LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
this.loc = locale;
- ResourceBundle bundle = com.ibm.icu4jni.util.Resources.getLocaleInstance(locale);
- String pattern = bundle.getString("Number");
- this.addr = NativeDecimalFormat.openDecimalFormatImpl(
- locale.toString(), pattern);
- String currSymbol = bundle.getString("CurrencySymbol");
- String intCurrSymbol = bundle.getString("IntCurrencySymbol");
+ this.addr = NativeDecimalFormat.openDecimalFormatImpl(locale.toString(),
+ localeData.numberPattern);
NativeDecimalFormat.setSymbol(this.addr,
- UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(), currSymbol);
+ UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(), localeData.currencySymbol);
NativeDecimalFormat.setSymbol(this.addr,
UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal(),
- intCurrSymbol);
+ localeData.internationalCurrencySymbol);
}
@Override
diff --git a/icu/src/main/java/com/ibm/icu4jni/util/LocaleData.java b/icu/src/main/java/com/ibm/icu4jni/util/LocaleData.java
new file mode 100644
index 0000000..1e91574
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/util/LocaleData.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ibm.icu4jni.util;
+
+/**
+ * Passes locale-specific from ICU native code to Java.
+ * <p>
+ * Note that you share these; you must not alter any of the fields, nor their array elements
+ * in the case of arrays. If you ever expose any of these things to user code, you must give
+ * them a clone rather than the original.
+ */
+public class LocaleData {
+ public Integer firstDayOfWeek;
+ public Integer minimalDaysInFirstWeek;
+
+ public String[] amPm;
+
+ public String[] eras;
+
+ public String[] longMonthNames;
+ public String[] shortMonthNames;
+
+ public String[] longWeekdayNames;
+ public String[] shortWeekdayNames;
+
+ public String fullTimeFormat;
+ public String longTimeFormat;
+ public String mediumTimeFormat;
+ public String shortTimeFormat;
+
+ public String fullDateFormat;
+ public String longDateFormat;
+ public String mediumDateFormat;
+ public String shortDateFormat;
+
+ public String decimalPatternChars;
+
+ public String infinity;
+ public String NaN;
+
+ public String currencySymbol;
+ public String internationalCurrencySymbol;
+
+ public String numberPattern;
+ public String integerPattern;
+ public String currencyPattern;
+ public String percentPattern;
+
+ @Override public String toString() {
+ return "LocaleData[" +
+ "firstDayOfWeek=" + firstDayOfWeek + "," +
+ "minimalDaysInFirstWeek=" + minimalDaysInFirstWeek + "," +
+ "amPm=" + amPm + "," +
+ "eras=" + eras + "," +
+ "longMonthNames=" + longMonthNames + "," +
+ "shortMonthNames=" + shortMonthNames + "," +
+ "longWeekdayNames=" + longWeekdayNames + "," +
+ "shortWeekdayNames=" + shortWeekdayNames + "," +
+ "fullTimeFormat=" + fullTimeFormat + "," +
+ "longTimeFormat=" + longTimeFormat + "," +
+ "mediumTimeFormat=" + mediumTimeFormat + "," +
+ "shortTimeFormat=" + shortTimeFormat + "," +
+ "fullDateFormat=" + fullDateFormat + "," +
+ "longDateFormat=" + longDateFormat + "," +
+ "mediumDateFormat=" + mediumDateFormat + "," +
+ "shortDateFormat=" + shortDateFormat + "," +
+ "decimalPatternChars=" + decimalPatternChars + "," +
+ "infinity=" + infinity + "," +
+ "NaN=" + NaN + "," +
+ "currencySymbol=" + currencySymbol + "," +
+ "internationalCurrencySymbol=" + internationalCurrencySymbol + "," +
+ "numberPattern=" + numberPattern + "," +
+ "integerPattern=" + integerPattern + "," +
+ "currencyPattern=" + currencyPattern + "," +
+ "percentPattern=" + percentPattern + "]";
+ }
+
+ public void overrideWithDataFrom(LocaleData overrides) {
+ if (overrides.firstDayOfWeek != null) {
+ firstDayOfWeek = overrides.firstDayOfWeek;
+ }
+ if (overrides.minimalDaysInFirstWeek != null) {
+ minimalDaysInFirstWeek = overrides.minimalDaysInFirstWeek;
+ }
+ if (overrides.amPm != null) {
+ amPm = overrides.amPm;
+ }
+ if (overrides.eras != null) {
+ eras = overrides.eras;
+ }
+ if (overrides.longMonthNames != null) {
+ longMonthNames = overrides.longMonthNames;
+ }
+ if (overrides.shortMonthNames != null) {
+ shortMonthNames = overrides.shortMonthNames;
+ }
+ if (overrides.longWeekdayNames != null) {
+ longWeekdayNames = overrides.longWeekdayNames;
+ }
+ if (overrides.shortWeekdayNames != null) {
+ shortWeekdayNames = overrides.shortWeekdayNames;
+ }
+ if (overrides.fullTimeFormat != null) {
+ fullTimeFormat = overrides.fullTimeFormat;
+ }
+ if (overrides.longTimeFormat != null) {
+ longTimeFormat = overrides.longTimeFormat;
+ }
+ if (overrides.mediumTimeFormat != null) {
+ mediumTimeFormat = overrides.mediumTimeFormat;
+ }
+ if (overrides.shortTimeFormat != null) {
+ shortTimeFormat = overrides.shortTimeFormat;
+ }
+ if (overrides.fullDateFormat != null) {
+ fullDateFormat = overrides.fullDateFormat;
+ }
+ if (overrides.longDateFormat != null) {
+ longDateFormat = overrides.longDateFormat;
+ }
+ if (overrides.mediumDateFormat != null) {
+ mediumDateFormat = overrides.mediumDateFormat;
+ }
+ if (overrides.shortDateFormat != null) {
+ shortDateFormat = overrides.shortDateFormat;
+ }
+ if (overrides.decimalPatternChars != null) {
+ decimalPatternChars = overrides.decimalPatternChars;
+ }
+ if (overrides.NaN != null) {
+ NaN = overrides.NaN;
+ }
+ if (overrides.infinity != null) {
+ infinity = overrides.infinity;
+ }
+ if (overrides.currencySymbol != null) {
+ currencySymbol = overrides.currencySymbol;
+ }
+ if (overrides.internationalCurrencySymbol != null) {
+ internationalCurrencySymbol = overrides.internationalCurrencySymbol;
+ }
+ if (overrides.numberPattern != null) {
+ numberPattern = overrides.numberPattern;
+ }
+ if (overrides.integerPattern != null) {
+ integerPattern = overrides.integerPattern;
+ }
+ if (overrides.currencyPattern != null) {
+ currencyPattern = overrides.currencyPattern;
+ }
+ if (overrides.percentPattern != null) {
+ percentPattern = overrides.percentPattern;
+ }
+ }
+}
diff --git a/icu/src/main/java/com/ibm/icu4jni/util/Resources.java b/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
index 41bf3e3..8f09029 100644
--- a/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
+++ b/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
@@ -33,8 +33,8 @@ import java.util.logging.Logger;
*/
public class Resources {
// A cache for the locale-specific data.
- private static final ConcurrentHashMap<String, LocaleResourceBundle> localeInstanceCache =
- new ConcurrentHashMap<String, LocaleResourceBundle>();
+ private static final ConcurrentHashMap<String, LocaleData> localeDataCache =
+ new ConcurrentHashMap<String, LocaleData>();
/**
* Cache for ISO language names.
@@ -57,40 +57,37 @@ public class Resources {
private static String[] availableTimezones = null;
/**
- * Returns a LocaleResourceBundle corresponding to the given locale.
- * TODO: return something that allows cheap static field lookup rather than
- * expensive chained hash table lookup.
+ * Returns a shared LocaleData for the given locale.
*/
- public static ResourceBundle getLocaleInstance(Locale locale) {
+ public static LocaleData getLocaleData(Locale locale) {
if (locale == null) {
locale = Locale.getDefault();
}
String localeName = locale.toString();
- LocaleResourceBundle bundle = localeInstanceCache.get(localeName);
- if (bundle != null) {
- return bundle;
+ LocaleData localeData = localeDataCache.get(localeName);
+ if (localeData != null) {
+ return localeData;
}
- bundle = makeLocaleResourceBundle(locale);
- localeInstanceCache.put(localeName, bundle);
- boolean absent = (localeInstanceCache.putIfAbsent(localeName, bundle) == null);
- return absent ? bundle : localeInstanceCache.get(localeName);
+ localeData = makeLocaleData(locale);
+ boolean absent = (localeDataCache.putIfAbsent(localeName, localeData) == null);
+ return absent ? localeData : localeDataCache.get(localeName);
}
- private static LocaleResourceBundle makeLocaleResourceBundle(Locale locale) {
- LocaleResourceBundle result = new LocaleResourceBundle(locale);
-
- // Anything not found in this ResourceBundle should be passed on to
- // a parent ResourceBundle corresponding to the next-most-specific locale.
- String country = locale.getCountry();
+ private static LocaleData makeLocaleData(Locale locale) {
String language = locale.getLanguage();
- if (locale.getVariant().length() > 0) {
- result.setParent(getLocaleInstance(new Locale(language, country, "")));
+ String country = locale.getCountry();
+ String variant = locale.getVariant();
+ // Start with data from the parent (next-most-specific) locale...
+ LocaleData result = new LocaleData();
+ if (variant.length() > 0) {
+ result.overrideWithDataFrom(getLocaleData(new Locale(language, country, "")));
} else if (country.length() > 0) {
- result.setParent(getLocaleInstance(new Locale(language, "", "")));
+ result.overrideWithDataFrom(getLocaleData(new Locale(language, "", "")));
} else if (language.length() > 0) {
- result.setParent(getLocaleInstance(new Locale("", "", "")));
+ result.overrideWithDataFrom(getLocaleData(new Locale("", "", "")));
}
-
+ // Override with data from this locale.
+ result.overrideWithDataFrom(initLocaleData(locale));
return result;
}
@@ -270,7 +267,7 @@ public class Resources {
return createTimeZoneNamesFor(locale);
}
- private static String[][] clone2dStringArray(String[][] array) {
+ public static String[][] clone2dStringArray(String[][] array) {
String[][] result = new String[array.length][];
for (int i = 0; i < array.length; ++i) {
result[i] = array[i].clone();
@@ -308,48 +305,6 @@ public class Resources {
}
- /**
- * Internal ResourceBundle mimicking the Harmony "Locale_*" bundles.
- * The content covers a wide range of
- * data items, with values even being arrays in some cases. Note we are
- * cheating with the "timezones" entry, since we normally don't want to
- * waste our precious RAM on several thousand of these Strings.
- */
- private static final class LocaleResourceBundle extends ListResourceBundle {
- private final Locale locale;
-
- public LocaleResourceBundle(Locale locale) {
- this.locale = locale;
- }
-
- // We can't set the superclass' locale field, so we need our own, and our own accessor.
- @Override
- public Locale getLocale() {
- return locale;
- }
-
- @Override
- protected Object[][] getContents() {
- return getContentImpl(locale.toString());
- }
-
- // Increase accessibility of this method so we can call it.
- @Override
- public void setParent(ResourceBundle bundle) {
- this.parent = bundle;
- }
-
- @Override
- public String toString() {
- StringBuilder result = new StringBuilder();
- result.append("LocaleResourceBundle[locale=");
- result.append(getLocale());
- result.append(",contents=");
- result.append(Arrays.deepToString(getContents()));
- return result.toString();
- }
- }
-
// --- Native methods accessing ICU's database ----------------------------
public static native String getDisplayCountryNative(String countryCode, String locale);
@@ -374,5 +329,25 @@ public class Resources {
private static native String getDisplayTimeZoneNative(String id, boolean isDST, int style,
String locale);
- private static native Object[][] getContentImpl(String locale);
+ private static LocaleData initLocaleData(Locale locale) {
+ LocaleData localeData = new LocaleData();
+ if (!initLocaleDataImpl(locale.toString(), localeData)) {
+ throw new AssertionError("couldn't initialize LocaleData for locale " + locale);
+ }
+ if (localeData.fullTimeFormat != null) {
+ // There are some full time format patterns in ICU that use the pattern character 'v'.
+ // Java doesn't accept this, so we replace it with 'z' which has about the same result
+ // as 'v', the timezone name.
+ // 'v' -> "PT", 'z' -> "PST", v is the generic timezone and z the standard tz
+ // "vvvv" -> "Pacific Time", "zzzz" -> "Pacific Standard Time"
+ localeData.fullTimeFormat = localeData.fullTimeFormat.replace('v', 'z');
+ }
+ if (localeData.numberPattern != null) {
+ String numberPattern = localeData.numberPattern;
+ localeData.integerPattern = numberPattern.substring(0, numberPattern.indexOf('.'));
+ }
+ return localeData;
+ }
+
+ private static native boolean initLocaleDataImpl(String locale, LocaleData result);
}