• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.util.EnumSet;
4 
5 import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo.Count;
6 
7 import com.ibm.icu.impl.Utility;
8 import com.ibm.icu.util.Freezable;
9 import com.ibm.icu.util.Output;
10 import com.ibm.icu.util.ULocale;
11 
12 /**
13  * Utility class for returning the plural category for a range of numbers, such as 1–5, so that appropriate messages can be chosen.
14  * The rules for determining this value vary widely across locales.
15  * @author markdavis
16  */
17 public final class PluralRanges implements Comparable<PluralRanges>, Freezable<PluralRanges> {
18 
19     /**
20      * Internal class for mapping from two Count values to another.
21      * @internal
22      * @deprecated
23      */
24     @Deprecated
25     public static final class Matrix implements Comparable<Matrix>, Cloneable {
26         private byte[] data = new byte[Count.LENGTH * Count.LENGTH];
27         {
28             for (int i = 0; i < data.length; ++i) {
29                 data[i] = -1;
30             }
31         }
32 
33         /**
34          * Internal method for setting.
35          * @internal
36          * @deprecated
37          */
38         @Deprecated
set(Count start, Count end, Count result)39         public void set(Count start, Count end, Count result) {
40             data[start.ordinal() * Count.LENGTH + end.ordinal()] = result == null ? (byte) -1 : (byte) result.ordinal();
41         }
42 
43         /**
44          * Internal method for setting; throws exception if already set.
45          * @internal
46          * @deprecated
47          */
48         @Deprecated
setIfNew(Count start, Count end, Count result)49         public void setIfNew(Count start, Count end, Count result) {
50             byte old = data[start.ordinal() * Count.LENGTH + end.ordinal()];
51             if (old >= 0) {
52                 throw new IllegalArgumentException("Previously set value for <" +
53                     start + ", " + end + ", " + Count.VALUES.get(old) + ">");
54             }
55             data[start.ordinal() * Count.LENGTH + end.ordinal()] = result == null ? (byte) -1 : (byte) result.ordinal();
56         }
57 
58         /**
59          * Internal method for getting.
60          * @internal
61          * @deprecated
62          */
63         @Deprecated
get(Count start, Count end)64         public Count get(Count start, Count end) {
65             byte result = data[start.ordinal() * Count.LENGTH + end.ordinal()];
66             return result < 0 ? null : Count.VALUES.get(result);
67         }
68 
69         /**
70          * Internal method to see if <*,end> values are all the same.
71          * @internal
72          * @deprecated
73          */
74         @Deprecated
endSame(Count end)75         public Count endSame(Count end) {
76             Count first = null;
77             for (Count start : Count.VALUES) {
78                 Count item = get(start, end);
79                 if (item == null) {
80                     continue;
81                 }
82                 if (first == null) {
83                     first = item;
84                     continue;
85                 }
86                 if (first != item) {
87                     return null;
88                 }
89             }
90             return first;
91         }
92 
93         /**
94          * Internal method to see if <start,*> values are all the same.
95          * @internal
96          * @deprecated
97          */
98         @Deprecated
startSame(Count start, EnumSet<Count> endDone, Output<Boolean> emit)99         public Count startSame(Count start, EnumSet<Count> endDone, Output<Boolean> emit) {
100             emit.value = false;
101             Count first = null;
102             for (Count end : Count.VALUES) {
103                 Count item = get(start, end);
104                 if (item == null) {
105                     continue;
106                 }
107                 if (first == null) {
108                     first = item;
109                     continue;
110                 }
111                 if (first != item) {
112                     return null;
113                 }
114                 // only emit if we didn't cover with the 'end' values
115                 if (!endDone.contains(end)) {
116                     emit.value = true;
117                 }
118             }
119             return first;
120         }
121 
122         @Override
hashCode()123         public int hashCode() {
124             int result = 0;
125             for (int i = 0; i < data.length; ++i) {
126                 result = result * 37 + data[i];
127             }
128             return result;
129         }
130 
131         @Override
equals(Object other)132         public boolean equals(Object other) {
133             if (!(other instanceof Matrix)) {
134                 return false;
135             }
136             return 0 == compareTo((Matrix) other);
137         }
138 
139         @Override
compareTo(Matrix o)140         public int compareTo(Matrix o) {
141             for (int i = 0; i < data.length; ++i) {
142                 int diff = data[i] - o.data[i];
143                 if (diff != 0) {
144                     return diff;
145                 }
146             }
147             return 0;
148         }
149 
150         @Override
clone()151         public Matrix clone() {
152             Matrix result = new Matrix();
153             result.data = data.clone();
154             return result;
155         }
156     }
157 
158     private Matrix matrix = new Matrix();
159     private boolean[] explicit = new boolean[Count.LENGTH];
160 
161     /**
162      * Returns a
163      * @return
164      */
getInstance(ULocale locale)165     public static PluralRanges getInstance(ULocale locale) {
166         return null;
167     }
168 
169     /**
170      * Internal method for building. If the start or end are null, it means everything of that type.
171      * @param rangeStart
172      * @param rangeEnd
173      * @param result
174      * @internal
175      * @deprecated
176      */
177     @Deprecated
add(Count rangeStart, Count rangeEnd, Count result)178     public void add(Count rangeStart, Count rangeEnd, Count result) {
179         explicit[result.ordinal()] = true;
180         if (rangeStart == null) {
181             for (Count rs : Count.values()) {
182                 if (rangeEnd == null) {
183                     for (Count re : Count.values()) {
184                         matrix.setIfNew(rs, re, result);
185                     }
186                 } else {
187                     explicit[rangeEnd.ordinal()] = true;
188                     matrix.setIfNew(rs, rangeEnd, result);
189                 }
190             }
191         } else if (rangeEnd == null) {
192             explicit[rangeStart.ordinal()] = true;
193             for (Count re : Count.values()) {
194                 matrix.setIfNew(rangeStart, re, result);
195             }
196         } else {
197             explicit[rangeStart.ordinal()] = true;
198             explicit[rangeEnd.ordinal()] = true;
199             matrix.setIfNew(rangeStart, rangeEnd, result);
200         }
201     }
202 
203     /**
204      * Internal method to show a range in XML format.
205      * @param start
206      * @param end
207      * @param result
208      * @return
209      * @internal
210      * @deprecated
211      */
212     @Deprecated
showRange(Count start, Count end, Count result)213     public static String showRange(Count start, Count end, Count result) {
214         String startEnd = "start=\"" + start + "\"" + Utility.repeat(" ", 5 - start.toString().length())
215             + " end=\"" + end + "\"" + Utility.repeat(" ", 5 - end.toString().length());
216         return result == null
217             ? "<!--         " + startEnd + " result=? -->"
218             : "<pluralRange " + startEnd + " result=\"" + result + "\"/>";
219     }
220 
221     /**
222      * Returns the appropriate plural category for a range from start to end.
223      * If there is no available data, then 'other' is returned.
224      * @param start
225      * @param end
226      * @return
227      */
get(Count start, Count end)228     public Count get(Count start, Count end) {
229         Count result = matrix.get(start, end);
230         return result == null ? Count.other : result;
231     }
232 
233     /**
234      * Returns the appropriate plural category for a range from start to end. If the combination does not
235      * explicitly occur in the data, returns null.
236      * @param start
237      * @param end
238      * @return
239      */
getExplicit(Count start, Count end)240     public Count getExplicit(Count start, Count end) {
241         return matrix.get(start, end);
242     }
243 
244     /**
245      * Internal method to determines whether the Count was explicitly used in any add statement.
246      * @param count
247      * @return
248      * @internal
249      * @deprecated
250      */
251     @Deprecated
isExplicitlySet(Count count)252     public boolean isExplicitlySet(Count count) {
253         return explicit[count.ordinal()];
254     }
255 
256     @Override
equals(Object other)257     public boolean equals(Object other) {
258         return other instanceof PluralRanges ? matrix.equals(other) : false;
259     }
260 
261     @Override
hashCode()262     public int hashCode() {
263         return matrix.hashCode();
264     }
265 
266     @Override
compareTo(PluralRanges that)267     public int compareTo(PluralRanges that) {
268         return matrix.compareTo(that.matrix);
269     }
270 
271     volatile boolean isFrozen;
272 
273     @Override
isFrozen()274     public boolean isFrozen() {
275         return isFrozen;
276     }
277 
278     @Override
freeze()279     public PluralRanges freeze() {
280         isFrozen = true;
281         return this;
282     }
283 
284     @Override
cloneAsThawed()285     public PluralRanges cloneAsThawed() {
286         PluralRanges result = new PluralRanges();
287         result.explicit = explicit.clone();
288         result.matrix = matrix.clone();
289         return result;
290     }
291 }