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 }