• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html#License
3 /*
4  *******************************************************************************
5  * Copyright (C) 2008-2015, Google, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  *******************************************************************************
8  */
9 package com.ibm.icu.text;
10 
11 import java.util.Arrays;
12 import java.util.EnumSet;
13 
14 import com.ibm.icu.impl.StandardPlural;
15 import com.ibm.icu.util.Freezable;
16 import com.ibm.icu.util.Output;
17 
18 /**
19  * Utility class for returning the plural category for a range of numbers, such as 1–5, so that appropriate messages can
20  * be chosen. The rules for determining this value vary widely across locales.
21  *
22  * @author markdavis
23  * @internal
24  * @deprecated This API is ICU internal only.
25  */
26 @Deprecated
27 public final class PluralRanges implements Freezable<PluralRanges>, Comparable<PluralRanges> {
28 
29     private volatile boolean isFrozen;
30     private Matrix matrix = new Matrix();
31     private boolean[] explicit = new boolean[StandardPlural.COUNT];
32 
33     /**
34      * Constructor
35      *
36      * @internal
37      * @deprecated This API is ICU internal only.
38      */
39     @Deprecated
PluralRanges()40     public PluralRanges() {
41     }
42 
43     /**
44      * Internal class for mapping from two StandardPluralCategories values to another.
45      */
46     private static final class Matrix implements Comparable<Matrix>, Cloneable {
47         private byte[] data = new byte[StandardPlural.COUNT * StandardPlural.COUNT];
48         {
49             for (int i = 0; i < data.length; ++i) {
50                 data[i] = -1;
51             }
52         }
53 
Matrix()54         Matrix() {
55         }
56 
57         /**
58          * Internal method for setting.
59          */
60         @SuppressWarnings("unused")
set(StandardPlural start, StandardPlural end, StandardPlural result)61         void set(StandardPlural start, StandardPlural end, StandardPlural result) {
62             data[start.ordinal() * StandardPlural.COUNT + end.ordinal()] = result == null ? (byte) -1
63                     : (byte) result.ordinal();
64         }
65 
66         /**
67          * Internal method for setting; throws exception if already set.
68          */
setIfNew(StandardPlural start, StandardPlural end, StandardPlural result)69         void setIfNew(StandardPlural start, StandardPlural end,
70                 StandardPlural result) {
71             byte old = data[start.ordinal() * StandardPlural.COUNT + end.ordinal()];
72             if (old >= 0) {
73                 throw new IllegalArgumentException("Previously set value for <" + start + ", " + end + ", "
74                         + StandardPlural.VALUES.get(old) + ">");
75             }
76             data[start.ordinal() * StandardPlural.COUNT + end.ordinal()] = result == null ? (byte) -1
77                     : (byte) result.ordinal();
78         }
79 
80         /**
81          * Internal method for getting.
82          */
get(StandardPlural start, StandardPlural end)83         StandardPlural get(StandardPlural start, StandardPlural end) {
84             byte result = data[start.ordinal() * StandardPlural.COUNT + end.ordinal()];
85             return result < 0 ? null : StandardPlural.VALUES.get(result);
86         }
87 
88         /**
89          * Internal method to see if <*,end> values are all the same.
90          */
91         @SuppressWarnings("unused")
endSame(StandardPlural end)92         StandardPlural endSame(StandardPlural end) {
93             StandardPlural first = null;
94             for (StandardPlural start : StandardPlural.VALUES) {
95                 StandardPlural item = get(start, end);
96                 if (item == null) {
97                     continue;
98                 }
99                 if (first == null) {
100                     first = item;
101                     continue;
102                 }
103                 if (first != item) {
104                     return null;
105                 }
106             }
107             return first;
108         }
109 
110         /**
111          * Internal method to see if <start,*> values are all the same.
112          */
113         @SuppressWarnings("unused")
startSame(StandardPlural start, EnumSet<StandardPlural> endDone, Output<Boolean> emit)114         StandardPlural startSame(StandardPlural start,
115                 EnumSet<StandardPlural> endDone, Output<Boolean> emit) {
116             emit.value = false;
117             StandardPlural first = null;
118             for (StandardPlural end : StandardPlural.VALUES) {
119                 StandardPlural item = get(start, end);
120                 if (item == null) {
121                     continue;
122                 }
123                 if (first == null) {
124                     first = item;
125                     continue;
126                 }
127                 if (first != item) {
128                     return null;
129                 }
130                 // only emit if we didn't cover with the 'end' values
131                 if (!endDone.contains(end)) {
132                     emit.value = true;
133                 }
134             }
135             return first;
136         }
137 
138         @Override
hashCode()139         public int hashCode() {
140             int result = 0;
141             for (int i = 0; i < data.length; ++i) {
142                 result = result * 37 + data[i];
143             }
144             return result;
145         }
146 
147         @Override
equals(Object other)148         public boolean equals(Object other) {
149             if (!(other instanceof Matrix)) {
150                 return false;
151             }
152             return 0 == compareTo((Matrix) other);
153         }
154 
155         @Override
compareTo(Matrix o)156         public int compareTo(Matrix o) {
157             for (int i = 0; i < data.length; ++i) {
158                 int diff = data[i] - o.data[i];
159                 if (diff != 0) {
160                     return diff;
161                 }
162             }
163             return 0;
164         }
165 
166         @Override
clone()167         public Matrix clone() {
168             Matrix result = new Matrix();
169             result.data = data.clone();
170             return result;
171         }
172 
173         @Override
toString()174         public String toString() {
175             StringBuilder result = new StringBuilder();
176             for (StandardPlural i : StandardPlural.values()) {
177                 for (StandardPlural j : StandardPlural.values()) {
178                     StandardPlural x = get(i, j);
179                     if (x != null) {
180                         result.append(i + " & " + j + " → " + x + ";\n");
181                     }
182                 }
183             }
184             return result.toString();
185         }
186     }
187 
188     /**
189      * Internal method for building. If the start or end are null, it means everything of that type.
190      *
191      * @param rangeStart
192      *            plural category for the start of the range
193      * @param rangeEnd
194      *            plural category for the end of the range
195      * @param result
196      *            the resulting plural category
197      * @internal
198      * @deprecated This API is ICU internal only.
199      */
200     @Deprecated
add(StandardPlural rangeStart, StandardPlural rangeEnd, StandardPlural result)201     public void add(StandardPlural rangeStart, StandardPlural rangeEnd,
202             StandardPlural result) {
203         if (isFrozen) {
204             throw new UnsupportedOperationException();
205         }
206         explicit[result.ordinal()] = true;
207         if (rangeStart == null) {
208             for (StandardPlural rs : StandardPlural.values()) {
209                 if (rangeEnd == null) {
210                     for (StandardPlural re : StandardPlural.values()) {
211                         matrix.setIfNew(rs, re, result);
212                     }
213                 } else {
214                     explicit[rangeEnd.ordinal()] = true;
215                     matrix.setIfNew(rs, rangeEnd, result);
216                 }
217             }
218         } else if (rangeEnd == null) {
219             explicit[rangeStart.ordinal()] = true;
220             for (StandardPlural re : StandardPlural.values()) {
221                 matrix.setIfNew(rangeStart, re, result);
222             }
223         } else {
224             explicit[rangeStart.ordinal()] = true;
225             explicit[rangeEnd.ordinal()] = true;
226             matrix.setIfNew(rangeStart, rangeEnd, result);
227         }
228     }
229 
230     /**
231      * Returns the appropriate plural category for a range from start to end. If there is no available data, then
232      * 'end' is returned as an implicit value. (Such an implicit value can be tested for with {@link #isExplicit}.)
233      *
234      * @param start
235      *            plural category for the start of the range
236      * @param end
237      *            plural category for the end of the range
238      * @return the resulting plural category, or 'end' if there is no data.
239      * @internal
240      * @deprecated This API is ICU internal only.
241      */
242     @Deprecated
get(StandardPlural start, StandardPlural end)243     public StandardPlural get(StandardPlural start, StandardPlural end) {
244         StandardPlural result = matrix.get(start, end);
245         return result == null ? end : result;
246     }
247 
248     /**
249      * Returns whether the appropriate plural category for a range from start to end
250      * is explicitly in the data (vs given an implicit value). See also {@link #get}.
251      *
252      * @param start
253      *            plural category for the start of the range
254      * @param end
255      *            plural category for the end of the range
256      * @return whether the value for (start,end) is explicit or not.
257      * @internal
258      * @deprecated This API is ICU internal only.
259      */
260     @Deprecated
isExplicit(StandardPlural start, StandardPlural end)261     public boolean isExplicit(StandardPlural start, StandardPlural end) {
262         return matrix.get(start, end) != null;
263     }
264 
265     /**
266      * Internal method to determines whether the StandardPluralCategories was explicitly used in any add statement.
267      *
268      * @param count
269      *            plural category to test
270      * @return true if set
271      * @internal
272      * @deprecated This API is ICU internal only.
273      */
274     @Deprecated
isExplicitlySet(StandardPlural count)275     public boolean isExplicitlySet(StandardPlural count) {
276         return explicit[count.ordinal()];
277     }
278 
279     /**
280      * {@inheritDoc}
281      * @internal
282      * @deprecated This API is ICU internal only.
283      */
284     @Deprecated
285     @Override
equals(Object other)286     public boolean equals(Object other) {
287         if (this == other) {
288             return true;
289         }
290         if (!(other instanceof PluralRanges)) {
291             return false;
292         }
293         PluralRanges otherPR = (PluralRanges)other;
294         return matrix.equals(otherPR.matrix) && Arrays.equals(explicit, otherPR.explicit);
295     }
296 
297     /**
298      * {@inheritDoc}
299      * @internal
300      * @deprecated This API is ICU internal only.
301      */
302     @Override
303     @Deprecated
hashCode()304     public int hashCode() {
305         return matrix.hashCode();
306     }
307 
308     /**
309      * {@inheritDoc}
310      * @internal
311      * @deprecated This API is ICU internal only.
312      */
313     @Override
314     @Deprecated
compareTo(PluralRanges that)315     public int compareTo(PluralRanges that) {
316         return matrix.compareTo(that.matrix);
317     }
318 
319     /**
320      * {@inheritDoc}
321      * @internal
322      * @deprecated This API is ICU internal only.
323      */
324     @Override
325     @Deprecated
isFrozen()326     public boolean isFrozen() {
327         return isFrozen;
328     }
329 
330     /**
331      * {@inheritDoc}
332      * @internal
333      * @deprecated This API is ICU internal only.
334      */
335     @Override
336     @Deprecated
freeze()337     public PluralRanges freeze() {
338         isFrozen = true;
339         return this;
340     }
341 
342     /**
343      * {@inheritDoc}
344      * @internal
345      * @deprecated This API is ICU internal only.
346      */
347     @Override
348     @Deprecated
cloneAsThawed()349     public PluralRanges cloneAsThawed() {
350         PluralRanges result = new PluralRanges();
351         result.explicit = explicit.clone();
352         result.matrix = matrix.clone();
353         return result;
354     }
355 
356     /**
357      * {@inheritDoc}
358      * @internal
359      * @deprecated This API is ICU internal only.
360      */
361     @Override
362     @Deprecated
toString()363     public String toString() {
364         return matrix.toString();
365     }
366 }