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