From e489a8b318e77369e46a3dad6cbac6db7dbbd48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kaz=C3=A8de=20king?= Date: Fri, 24 Jun 2016 00:59:03 +0000 Subject: [PATCH] ICU-12605 convert data enumeration to resource sink for TimeUnitFormat, Java X-SVN-Rev: 38879 --- .../src/com/ibm/icu/text/TimeUnitFormat.java | 123 ++++++++++++------ 1 file changed, 80 insertions(+), 43 deletions(-) diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/TimeUnitFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/TimeUnitFormat.java index 427b9a6a665..bb94194e927 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/TimeUnitFormat.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/TimeUnitFormat.java @@ -22,6 +22,7 @@ import java.util.TreeMap; import com.ibm.icu.impl.ICUData; import com.ibm.icu.impl.ICUResourceBundle; +import com.ibm.icu.impl.UResource; import com.ibm.icu.util.Measure; import com.ibm.icu.util.TimeUnit; import com.ibm.icu.util.TimeUnitAmount; @@ -34,7 +35,7 @@ import com.ibm.icu.util.UResourceBundle; * Format or parse a TimeUnitAmount, using plural rules for the units where available. * *

- * Code Sample: + * Code Sample: *

  *   // create a time unit instance.
  *   // only SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, and YEAR are supported
@@ -51,7 +52,7 @@ import com.ibm.icu.util.UResourceBundle;
  *   try {
  *       // parse a string into time unit amount
  *       TimeUnitAmount result = (TimeUnitAmount) format.parseObject(formatted);
- *       // result should equal to source 
+ *       // result should equal to source
  *   } catch (ParseException e) {
  *   }
  * 
@@ -66,41 +67,41 @@ import com.ibm.icu.util.UResourceBundle; public class TimeUnitFormat extends MeasureFormat { /** - * Constant for full name style format. + * Constant for full name style format. * For example, the full name for "hour" in English is "hour" or "hours". * @deprecated ICU 53 see {@link MeasureFormat.FormatWidth} */ @Deprecated public static final int FULL_NAME = 0; /** - * Constant for abbreviated name style format. + * Constant for abbreviated name style format. * For example, the abbreviated name for "hour" in English is "hr" or "hrs". * @deprecated ICU 53 see {@link MeasureFormat.FormatWidth} */ @Deprecated public static final int ABBREVIATED_NAME = 1; - + private static final int TOTAL_STYLES = 2; private static final long serialVersionUID = -3707773153184971529L; - + // These fields are supposed to be the same as the fields in mf. They // are here for serialization backward compatibility and to support parsing. private NumberFormat format; private ULocale locale; private int style; - + // We use this field in lieu of the super class because the super class // is immutable while this class is mutable. The contents of the super class // is an empty shell. Every public method of the super class is overridden to // delegate to this field. Each time this object mutates, it replaces this field with // a new immutable instance. private transient MeasureFormat mf; - + private transient Map> timeUnitToCountToPatterns; private transient PluralRules pluralRules; private transient boolean isReady; - + private static final String DEFAULT_PATTERN_FOR_SECOND = "{0} s"; private static final String DEFAULT_PATTERN_FOR_MINUTE = "{0} min"; private static final String DEFAULT_PATTERN_FOR_HOUR = "{0} h"; @@ -110,7 +111,7 @@ public class TimeUnitFormat extends MeasureFormat { private static final String DEFAULT_PATTERN_FOR_YEAR = "{0} y"; /** - * Create empty format using full name style, for example, "hours". + * Create empty format using full name style, for example, "hours". * Use setLocale and/or setFormat to modify. * @deprecated ICU 53 use {@link MeasureFormat} instead. */ @@ -157,13 +158,13 @@ public class TimeUnitFormat extends MeasureFormat { mf = MeasureFormat.getInstance( locale, style == FULL_NAME ? FormatWidth.WIDE : FormatWidth.SHORT); this.style = style; - + // Needed for getLocale(ULocale.VALID_LOCALE) setLocale(locale, locale); this.locale = locale; isReady = false; } - + private TimeUnitFormat(ULocale locale, int style, NumberFormat numberFormat) { this(locale, style); if (numberFormat != null) { @@ -190,7 +191,7 @@ public class TimeUnitFormat extends MeasureFormat { public TimeUnitFormat setLocale(ULocale locale) { if (locale != this.locale){ mf = mf.withLocale(locale); - + // Needed for getLocale(ULocale.VALID_LOCALE) setLocale(locale, locale); this.locale = locale; @@ -198,7 +199,7 @@ public class TimeUnitFormat extends MeasureFormat { } return this; } - + /** * Set the locale used for formatting or parsing. * @param locale locale of this time unit formatter. @@ -209,7 +210,7 @@ public class TimeUnitFormat extends MeasureFormat { public TimeUnitFormat setLocale(Locale locale) { return setLocale(ULocale.forLocale(locale)); } - + /** * Set the format used for formatting or parsing. Passing null is equivalent to passing * {@link NumberFormat#getNumberInstance(ULocale)}. @@ -248,7 +249,7 @@ public class TimeUnitFormat extends MeasureFormat { FieldPosition pos) { return mf.format(obj, toAppendTo, pos); } - + /** * Parse a TimeUnitAmount. * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition) @@ -341,7 +342,7 @@ public class TimeUnitFormat extends MeasureFormat { return new TimeUnitAmount(resultNumber, resultTimeUnit); } } - + private void setup() { if (locale == null) { if (format != null) { @@ -362,18 +363,37 @@ public class TimeUnitFormat extends MeasureFormat { setup("unitsShort/duration", timeUnitToCountToPatterns, ABBREVIATED_NAME, pluralKeywords); isReady = true; } - - private void setup(String resourceKey, Map> timeUnitToCountToPatterns, int style, - Set pluralKeywords) { - // fill timeUnitToCountToPatterns from resource file - try { - ICUResourceBundle resource = (ICUResourceBundle) UResourceBundle.getBundleInstance( - ICUData.ICU_UNIT_BASE_NAME, locale); - ICUResourceBundle unitsRes = resource.getWithFallback(resourceKey); - int size = unitsRes.getSize(); - for (int index = 0; index < size; ++index) { - String timeUnitName = unitsRes.get(index).getKey(); + + private static final class TimeUnitFormatSetupSink extends UResource.Sink { + Map> timeUnitToCountToPatterns; + int style; + Set pluralKeywords; + ULocale locale; + boolean beenHere; + + TimeUnitFormatSetupSink(Map> timeUnitToCountToPatterns, + int style, Set pluralKeywords, ULocale locale) { + this.timeUnitToCountToPatterns = timeUnitToCountToPatterns; + this.style = style; + this.pluralKeywords = pluralKeywords; + this.locale = locale; + this.beenHere = false; + } + + @Override + public void put(UResource.Key key, UResource.Value value, boolean noFallback) { + // Skip all put() calls except the first one -- discard all fallback data. + if (beenHere) { + return; + } else { + beenHere = true; + } + + UResource.Table units = value.getTable(); + for (int i = 0; units.getKeyAndValue(i, key, value); ++i) { + String timeUnitName = key.toString(); TimeUnit timeUnit = null; + if (timeUnitName.equals("year")) { timeUnit = TimeUnit.YEAR; } else if (timeUnitName.equals("month")) { @@ -391,19 +411,18 @@ public class TimeUnitFormat extends MeasureFormat { } else { continue; } - ICUResourceBundle oneUnitRes = unitsRes.getWithFallback(timeUnitName); - int count = oneUnitRes.getSize(); + Map countToPatterns = timeUnitToCountToPatterns.get(timeUnit); if (countToPatterns == null) { countToPatterns = new TreeMap(); timeUnitToCountToPatterns.put(timeUnit, countToPatterns); } - for (int pluralIndex = 0; pluralIndex < count; ++pluralIndex) { - String pluralCount = oneUnitRes.get(pluralIndex).getKey(); + + UResource.Table countsToPatternTable = value.getTable(); + for (int j = 0; countsToPatternTable.getKeyAndValue(j, key, value); ++j) { + String pluralCount = key.toString(); if (!pluralKeywords.contains(pluralCount)) continue; - String pattern = oneUnitRes.get(pluralIndex).getString(); - final MessageFormat messageFormat = new MessageFormat(pattern, locale); // save both full name and abbreviated name in one table // is good space-wise, but it degrades performance, // since it needs to check whether the needed space @@ -413,9 +432,27 @@ public class TimeUnitFormat extends MeasureFormat { pair = new Object[2]; countToPatterns.put(pluralCount, pair); } - pair[style] = messageFormat; + if (pair[style] == null) { + String pattern = value.getString(); + final MessageFormat messageFormat = new MessageFormat(pattern, locale); + pair[style] = messageFormat; + } } } + } + } + + private void setup(String resourceKey, Map> timeUnitToCountToPatterns, int style, + Set pluralKeywords) { + // fill timeUnitToCountToPatterns from resource file + try { + + ICUResourceBundle resource = (ICUResourceBundle) UResourceBundle.getBundleInstance( + ICUData.ICU_UNIT_BASE_NAME, locale); + + TimeUnitFormatSetupSink sink = new TimeUnitFormatSetupSink( + timeUnitToCountToPatterns, style, pluralKeywords, locale); + resource.getAllItemsWithFallback(resourceKey, sink); } catch (MissingResourceException e) { } // there should be patterns for each plural rule in each time unit. @@ -528,11 +565,11 @@ public class TimeUnitFormat extends MeasureFormat { searchInTree(resourceKey, styl, timeUnit, srcPluralCount, "other", countToPatterns); } } - + // boilerplate code to make TimeUnitFormat otherwise follow the contract of // MeasureFormat - + /** * @internal * @deprecated This API is ICU internal only. @@ -543,7 +580,7 @@ public class TimeUnitFormat extends MeasureFormat { StringBuilder appendTo, FieldPosition fieldPosition, Measure... measures) { return mf.formatMeasures(appendTo, fieldPosition, measures); } - + /** * @internal * @deprecated This API is ICU internal only. @@ -553,7 +590,7 @@ public class TimeUnitFormat extends MeasureFormat { public MeasureFormat.FormatWidth getWidth() { return mf.getWidth(); } - + /** * @internal * @deprecated This API is ICU internal only. @@ -563,7 +600,7 @@ public class TimeUnitFormat extends MeasureFormat { public NumberFormat getNumberFormat() { return mf.getNumberFormat(); } - + /** * @internal * @deprecated This API is ICU internal only. @@ -576,13 +613,13 @@ public class TimeUnitFormat extends MeasureFormat { return result; } // End boilerplate. - + // Serialization - + private Object writeReplace() throws ObjectStreamException { return mf.toTimeUnitProxy(); } - + // Preserve backward serialize backward compatibility. private Object readResolve() throws ObjectStreamException { return new TimeUnitFormat(locale, style, format);