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