blob: 78c5e7a6bff1f17c9ac779cb376bcd1cd06d9895 [file] [log] [blame]
// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
package com.ibm.icu.impl.number.range;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import com.ibm.icu.impl.ICUData;
import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.impl.StandardPlural;
import com.ibm.icu.impl.UResource;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceBundle;
import com.ibm.icu.util.UResourceTypeMismatchException;
/**
* @author sffc
*
*/
public class StandardPluralRanges {
StandardPlural[] flatTriples;
int numTriples = 0;
/**
* An immutable map from language codes to set IDs.
* Pre-computed and cached in Java since it is used as a cache key for PluralRules.
*/
private static volatile Map<String, String> languageToSet;
/** An empty StandardPluralRanges instance. */
public static final StandardPluralRanges DEFAULT = new StandardPluralRanges();
////////////////////
private static final class PluralRangeSetsDataSink extends UResource.Sink {
Map<String, String> output;
PluralRangeSetsDataSink(Map<String, String> output) {
this.output = output;
}
@Override
public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
UResource.Table table = value.getTable();
for (int i = 0; table.getKeyAndValue(i, key, value); ++i) {
// The data has only languages; no regions/scripts. If this changes, this
// code and languageToSet will need to change.
assert key.toString().equals(new ULocale(key.toString()).getLanguage());
output.put(key.toString(), value.toString());
}
}
}
private static Map<String, String> getLanguageToSet() {
Map<String, String> candidate = languageToSet;
if (candidate == null) {
Map<String, String> map = new HashMap<String, String>();
PluralRangeSetsDataSink sink = new PluralRangeSetsDataSink(map);
ICUResourceBundle resource = (ICUResourceBundle)
UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, "pluralRanges");
resource.getAllItemsWithFallback("locales", sink);
candidate = Collections.unmodifiableMap(map);
}
// Check if another thread set languageToSet in the mean time
if (languageToSet == null) {
languageToSet = candidate;
}
return languageToSet;
}
private static final class PluralRangesDataSink extends UResource.Sink {
StandardPluralRanges output;
PluralRangesDataSink(StandardPluralRanges output) {
this.output = output;
}
@Override
public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
UResource.Array entriesArray = value.getArray();
output.setCapacity(entriesArray.getSize());
for (int i = 0; entriesArray.getValue(i, value); ++i) {
UResource.Array pluralFormsArray = value.getArray();
if (pluralFormsArray.getSize() != 3) {
throw new UResourceTypeMismatchException(
"Expected 3 elements in pluralRanges.txt array");
}
pluralFormsArray.getValue(0, value);
StandardPlural first = StandardPlural.fromString(value.getString());
pluralFormsArray.getValue(1, value);
StandardPlural second = StandardPlural.fromString(value.getString());
pluralFormsArray.getValue(2, value);
StandardPlural result = StandardPlural.fromString(value.getString());
output.addPluralRange(first, second, result);
}
}
}
private static void getPluralRangesData(
String set,
StandardPluralRanges out) {
StringBuilder sb = new StringBuilder();
ICUResourceBundle resource;
resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, "pluralRanges");
sb.setLength(0);
sb.append("rules/");
sb.append(set);
String key = sb.toString();
PluralRangesDataSink sink = new PluralRangesDataSink(out);
resource.getAllItemsWithFallback(key, sink);
}
////////////////////
/** Create a StandardPluralRanges based on locale. */
public static StandardPluralRanges forLocale(ULocale locale) {
return forSet(getSetForLocale(locale));
}
/** Create a StandardPluralRanges based on set name. */
public static StandardPluralRanges forSet(String set) {
StandardPluralRanges result = new StandardPluralRanges();
if (set == null) {
// Not all languages are covered: fail gracefully
return DEFAULT;
}
getPluralRangesData(set, result);
return result;
}
/** Get the set name from the locale. */
public static String getSetForLocale(ULocale locale) {
return getLanguageToSet().get(locale.getLanguage());
}
private StandardPluralRanges() {
}
/** Used for data loading. */
private void addPluralRange(StandardPlural first, StandardPlural second, StandardPlural result) {
flatTriples[3 * numTriples] = first;
flatTriples[3 * numTriples + 1] = second;
flatTriples[3 * numTriples + 2] = result;
numTriples++;
}
/** Used for data loading. */
private void setCapacity(int length) {
flatTriples = new StandardPlural[length*3];
}
public StandardPlural resolve(StandardPlural first, StandardPlural second) {
for (int i = 0; i < numTriples; i++) {
if (first == flatTriples[3 * i] && second == flatTriples[3 * i + 1]) {
return flatTriples[3 * i + 2];
}
}
// Default fallback
return StandardPlural.OTHER;
}
}