• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 package com.ibm.icu.impl.number.range;
4 
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.Map;
8 
9 import com.ibm.icu.impl.ICUData;
10 import com.ibm.icu.impl.ICUResourceBundle;
11 import com.ibm.icu.impl.StandardPlural;
12 import com.ibm.icu.impl.UResource;
13 import com.ibm.icu.util.ULocale;
14 import com.ibm.icu.util.UResourceBundle;
15 import com.ibm.icu.util.UResourceTypeMismatchException;
16 
17 /**
18  * @author sffc
19  *
20  */
21 public class StandardPluralRanges {
22 
23     StandardPlural[] flatTriples;
24     int numTriples = 0;
25 
26     /**
27      * An immutable map from language codes to set IDs.
28      * Pre-computed and cached in Java since it is used as a cache key for PluralRules.
29      */
30     private static volatile Map<String, String> languageToSet;
31 
32     /** An empty StandardPluralRanges instance. */
33     public static final StandardPluralRanges DEFAULT = new StandardPluralRanges();
34 
35     ////////////////////
36 
37     private static final class PluralRangeSetsDataSink extends UResource.Sink {
38 
39         Map<String, String> output;
40 
PluralRangeSetsDataSink(Map<String, String> output)41         PluralRangeSetsDataSink(Map<String, String> output) {
42             this.output = output;
43         }
44 
45         @Override
put(UResource.Key key, UResource.Value value, boolean noFallback)46         public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
47             UResource.Table table = value.getTable();
48             for (int i = 0; table.getKeyAndValue(i, key, value); ++i) {
49                 // The data has only languages; no regions/scripts. If this changes, this
50                 // code and languageToSet will need to change.
51                 assert key.toString().equals(new ULocale(key.toString()).getLanguage());
52                 output.put(key.toString(), value.toString());
53             }
54         }
55     }
56 
getLanguageToSet()57     private static Map<String, String> getLanguageToSet() {
58         Map<String, String> candidate = languageToSet;
59         if (candidate == null) {
60             Map<String, String> map = new HashMap<String, String>();
61             PluralRangeSetsDataSink sink = new PluralRangeSetsDataSink(map);
62             ICUResourceBundle resource = (ICUResourceBundle)
63                 UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, "pluralRanges");
64             resource.getAllItemsWithFallback("locales", sink);
65             candidate = Collections.unmodifiableMap(map);
66         }
67         // Check if another thread set languageToSet in the mean time
68         if (languageToSet == null) {
69             languageToSet = candidate;
70         }
71         return languageToSet;
72     }
73 
74     private static final class PluralRangesDataSink extends UResource.Sink {
75 
76         StandardPluralRanges output;
77 
PluralRangesDataSink(StandardPluralRanges output)78         PluralRangesDataSink(StandardPluralRanges output) {
79             this.output = output;
80         }
81 
82         @Override
put(UResource.Key key, UResource.Value value, boolean noFallback)83         public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
84             UResource.Array entriesArray = value.getArray();
85             output.setCapacity(entriesArray.getSize());
86             for (int i = 0; entriesArray.getValue(i, value); ++i) {
87                 UResource.Array pluralFormsArray = value.getArray();
88                 if (pluralFormsArray.getSize() != 3) {
89                     throw new UResourceTypeMismatchException(
90                         "Expected 3 elements in pluralRanges.txt array");
91                 }
92                 pluralFormsArray.getValue(0, value);
93                 StandardPlural first = StandardPlural.fromString(value.getString());
94                 pluralFormsArray.getValue(1, value);
95                 StandardPlural second = StandardPlural.fromString(value.getString());
96                 pluralFormsArray.getValue(2, value);
97                 StandardPlural result = StandardPlural.fromString(value.getString());
98                 output.addPluralRange(first, second, result);
99             }
100         }
101     }
102 
getPluralRangesData( String set, StandardPluralRanges out)103     private static void getPluralRangesData(
104             String set,
105             StandardPluralRanges out) {
106         StringBuilder sb = new StringBuilder();
107         ICUResourceBundle resource;
108         resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, "pluralRanges");
109         sb.setLength(0);
110         sb.append("rules/");
111         sb.append(set);
112         String key = sb.toString();
113         PluralRangesDataSink sink = new PluralRangesDataSink(out);
114         resource.getAllItemsWithFallback(key, sink);
115     }
116 
117     ////////////////////
118 
119     /** Create a StandardPluralRanges based on locale. */
forLocale(ULocale locale)120     public static StandardPluralRanges forLocale(ULocale locale) {
121         return forSet(getSetForLocale(locale));
122     }
123 
124     /** Create a StandardPluralRanges based on set name. */
forSet(String set)125     public static StandardPluralRanges forSet(String set) {
126         StandardPluralRanges result = new StandardPluralRanges();
127         if (set == null) {
128             // Not all languages are covered: fail gracefully
129             return DEFAULT;
130         }
131         getPluralRangesData(set, result);
132         return result;
133     }
134 
135     /** Get the set name from the locale. */
getSetForLocale(ULocale locale)136     public static String getSetForLocale(ULocale locale) {
137         return getLanguageToSet().get(locale.getLanguage());
138     }
139 
StandardPluralRanges()140     private StandardPluralRanges() {
141     }
142 
143     /** Used for data loading. */
addPluralRange(StandardPlural first, StandardPlural second, StandardPlural result)144     private void addPluralRange(StandardPlural first, StandardPlural second, StandardPlural result) {
145         flatTriples[3 * numTriples] = first;
146         flatTriples[3 * numTriples + 1] = second;
147         flatTriples[3 * numTriples + 2] = result;
148         numTriples++;
149     }
150 
151     /** Used for data loading. */
setCapacity(int length)152     private void setCapacity(int length) {
153         flatTriples = new StandardPlural[length*3];
154     }
155 
resolve(StandardPlural first, StandardPlural second)156     public StandardPlural resolve(StandardPlural first, StandardPlural second) {
157         for (int i = 0; i < numTriples; i++) {
158             if (first == flatTriples[3 * i] && second == flatTriples[3 * i + 1]) {
159                 return flatTriples[3 * i + 2];
160             }
161         }
162         // Default fallback
163         return StandardPlural.OTHER;
164     }
165 
166 }
167