1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ******************************************************************************* 6 * Copyright (C) 1996-2014, International Business Machines Corporation and * 7 * others. All Rights Reserved. * 8 ******************************************************************************* 9 */ 10 11 package android.icu.util; 12 13 import android.icu.impl.Utility; 14 15 /** 16 * class CompactATypeArray : use only on primitive data types 17 * Provides a compact way to store information that is indexed by Unicode 18 * values, such as character properties, types, keyboard values, etc.This 19 * is very useful when you have a block of Unicode data that contains 20 * significant values while the rest of the Unicode data is unused in the 21 * application or when you have a lot of redundance, such as where all 21,000 22 * Han ideographs have the same value. However, lookup is much faster than a 23 * hash table. 24 * A compact array of any primitive data type serves two purposes: 25 * <UL type = round> 26 * <LI>Fast access of the indexed values. 27 * <LI>Smaller memory footprint. 28 * </UL> 29 * A compact array is composed of a index array and value array. The index 30 * array contains the indicies of Unicode characters to the value array. 31 * @see CompactByteArray 32 * @author Helena Shih 33 * @deprecated This API is ICU internal only. 34 * @hide Only a subset of ICU is exposed in Android 35 * @hide draft / provisional / internal are hidden on Android 36 */ 37 @Deprecated 38 public final class CompactCharArray implements Cloneable { 39 40 /** 41 * The total number of Unicode characters. 42 * @deprecated This API is ICU internal only. 43 * @hide draft / provisional / internal are hidden on Android 44 */ 45 @Deprecated 46 public static final int UNICODECOUNT = 65536; 47 48 /** 49 * Default constructor for CompactCharArray, the default value of the 50 * compact array is 0. 51 * @deprecated This API is ICU internal only. 52 * @hide draft / provisional / internal are hidden on Android 53 */ 54 @Deprecated CompactCharArray()55 public CompactCharArray() 56 { 57 this((char)0); 58 } 59 60 /** 61 * Constructor for CompactCharArray. 62 * @param defaultValue the default value of the compact array. 63 * @deprecated This API is ICU internal only. 64 * @hide draft / provisional / internal are hidden on Android 65 */ 66 @Deprecated CompactCharArray(char defaultValue)67 public CompactCharArray(char defaultValue) 68 { 69 int i; 70 values = new char[UNICODECOUNT]; 71 indices = new char[INDEXCOUNT]; 72 hashes = new int[INDEXCOUNT]; 73 for (i = 0; i < UNICODECOUNT; ++i) { 74 values[i] = defaultValue; 75 } 76 for (i = 0; i < INDEXCOUNT; ++i) { 77 indices[i] = (char)(i<<BLOCKSHIFT); 78 hashes[i] = 0; 79 } 80 isCompact = false; 81 82 this.defaultValue = defaultValue; 83 } 84 85 /** 86 * Constructor for CompactCharArray. 87 * @param indexArray the indicies of the compact array. 88 * @param newValues the values of the compact array. 89 * @exception IllegalArgumentException If the index is out of range. 90 * @deprecated This API is ICU internal only. 91 * @hide draft / provisional / internal are hidden on Android 92 */ 93 @Deprecated CompactCharArray(char indexArray[], char newValues[])94 public CompactCharArray(char indexArray[], 95 char newValues[]) 96 { 97 int i; 98 if (indexArray.length != INDEXCOUNT) 99 throw new IllegalArgumentException("Index out of bounds."); 100 for (i = 0; i < INDEXCOUNT; ++i) { 101 char index = indexArray[i]; 102 if (index >= newValues.length+BLOCKCOUNT) 103 throw new IllegalArgumentException("Index out of bounds."); 104 } 105 indices = indexArray; 106 values = newValues; 107 isCompact = true; 108 } 109 110 /** 111 * Constructor for CompactCharArray. 112 * 113 * @param indexArray the RLE-encoded indicies of the compact array. 114 * @param valueArray the RLE-encoded values of the compact array. 115 * 116 * @throws IllegalArgumentException if the index or value array is 117 * the wrong size. 118 * @deprecated This API is ICU internal only. 119 * @hide draft / provisional / internal are hidden on Android 120 */ 121 @Deprecated CompactCharArray(String indexArray, String valueArray)122 public CompactCharArray(String indexArray, 123 String valueArray) 124 { 125 this( Utility.RLEStringToCharArray(indexArray), 126 Utility.RLEStringToCharArray(valueArray)); 127 } 128 129 /** 130 * Get the mapped value of a Unicode character. 131 * @param index the character to get the mapped value with 132 * @return the mapped value of the given character 133 * @deprecated This API is ICU internal only. 134 * @hide draft / provisional / internal are hidden on Android 135 */ 136 @Deprecated elementAt(char index)137 public char elementAt(char index) 138 { 139 int ix = (indices[index >> BLOCKSHIFT] & 0xFFFF) 140 + (index & BLOCKMASK); 141 return ix >= values.length ? defaultValue : values[ix]; 142 } 143 144 /** 145 * Set a new value for a Unicode character. 146 * Set automatically expands the array if it is compacted. 147 * @param index the character to set the mapped value with 148 * @param value the new mapped value 149 * @deprecated This API is ICU internal only. 150 * @hide draft / provisional / internal are hidden on Android 151 */ 152 @Deprecated setElementAt(char index, char value)153 public void setElementAt(char index, char value) 154 { 155 if (isCompact) 156 expand(); 157 values[index] = value; 158 touchBlock(index >> BLOCKSHIFT, value); 159 } 160 161 /** 162 * Set new values for a range of Unicode character. 163 * 164 * @param start the starting offset of the range 165 * @param end the ending offset of the range 166 * @param value the new mapped value 167 * @deprecated This API is ICU internal only. 168 * @hide draft / provisional / internal are hidden on Android 169 */ 170 @Deprecated setElementAt(char start, char end, char value)171 public void setElementAt(char start, char end, char value) 172 { 173 int i; 174 if (isCompact) { 175 expand(); 176 } 177 for (i = start; i <= end; ++i) { 178 values[i] = value; 179 touchBlock(i >> BLOCKSHIFT, value); 180 } 181 } 182 /** 183 * Compact the array 184 * @deprecated This API is ICU internal only. 185 * @hide draft / provisional / internal are hidden on Android 186 */ 187 @Deprecated compact()188 public void compact() { 189 compact(true); 190 } 191 192 /** 193 * Compact the array. 194 * @deprecated This API is ICU internal only. 195 * @hide draft / provisional / internal are hidden on Android 196 */ 197 @Deprecated compact(boolean exhaustive)198 public void compact(boolean exhaustive) 199 { 200 if (!isCompact) { 201 int iBlockStart = 0; 202 char iUntouched = 0xFFFF; 203 int newSize = 0; 204 205 char[] target = exhaustive ? new char[UNICODECOUNT] : values; 206 207 for (int i = 0; i < indices.length; ++i, iBlockStart += BLOCKCOUNT) { 208 indices[i] = 0xFFFF; 209 boolean touched = blockTouched(i); 210 if (!touched && iUntouched != 0xFFFF) { 211 // If no values in this block were set, we can just set its 212 // index to be the same as some other block with no values 213 // set, assuming we've seen one yet. 214 indices[i] = iUntouched; 215 } else { 216 int jBlockStart = 0; 217 // See if we can find a previously compacted block that's identical 218 for (int j = 0; j < i; ++j, jBlockStart += BLOCKCOUNT) { 219 if (hashes[i] == hashes[j] && 220 arrayRegionMatches(values, iBlockStart, 221 values, jBlockStart, BLOCKCOUNT)) { 222 indices[i] = indices[j]; 223 } 224 } 225 if (indices[i] == 0xFFFF) { 226 int dest; // Where to copy 227 if (exhaustive) { 228 // See if we can find some overlap with another block 229 dest = FindOverlappingPosition(iBlockStart, target, 230 newSize); 231 } else { 232 // Just copy to the end; it's quicker 233 dest = newSize; 234 } 235 int limit = dest + BLOCKCOUNT; 236 if (limit > newSize) { 237 for (int j = newSize; j < limit; ++j) { 238 target[j] = values[iBlockStart + j - dest]; 239 } 240 newSize = limit; 241 } 242 indices[i] = (char)dest; 243 if (!touched) { 244 // If this is the first untouched block we've seen, 245 // remember its index. 246 iUntouched = (char)jBlockStart; 247 } 248 } 249 } 250 } 251 // we are done compacting, so now make the array shorter 252 char[] result = new char[newSize]; 253 System.arraycopy(target, 0, result, 0, newSize); 254 values = result; 255 isCompact = true; 256 hashes = null; 257 } 258 } 259 FindOverlappingPosition(int start, char[] tempValues, int tempCount)260 private int FindOverlappingPosition(int start, char[] tempValues, int tempCount) 261 { 262 for (int i = 0; i < tempCount; i += 1) { 263 int currentCount = BLOCKCOUNT; 264 if (i + BLOCKCOUNT > tempCount) { 265 currentCount = tempCount - i; 266 } 267 if (arrayRegionMatches(values, start, tempValues, i, currentCount)) 268 return i; 269 } 270 return tempCount; 271 } 272 273 /** 274 * Convenience utility to compare two arrays of doubles. 275 * @param len the length to compare. 276 * The start indices and start+len must be valid. 277 */ arrayRegionMatches(char[] source, int sourceStart, char[] target, int targetStart, int len)278 final static boolean arrayRegionMatches(char[] source, int sourceStart, 279 char[] target, int targetStart, 280 int len) 281 { 282 int sourceEnd = sourceStart + len; 283 int delta = targetStart - sourceStart; 284 for (int i = sourceStart; i < sourceEnd; i++) { 285 if (source[i] != target[i + delta]) 286 return false; 287 } 288 return true; 289 } 290 291 /** 292 * Remember that a specified block was "touched", i.e. had a value set. 293 * Untouched blocks can be skipped when compacting the array 294 */ touchBlock(int i, int value)295 private final void touchBlock(int i, int value) { 296 hashes[i] = (hashes[i] + (value<<1)) | 1; 297 } 298 299 /** 300 * Query whether a specified block was "touched", i.e. had a value set. 301 * Untouched blocks can be skipped when compacting the array 302 */ blockTouched(int i)303 private final boolean blockTouched(int i) { 304 return hashes[i] != 0; 305 } 306 307 /** 308 * For internal use only. Do not modify the result, the behavior of 309 * modified results are undefined. 310 * @deprecated This API is ICU internal only. 311 * @hide draft / provisional / internal are hidden on Android 312 */ 313 @Deprecated getIndexArray()314 public char[] getIndexArray() 315 { 316 return indices; 317 } 318 319 /** 320 * For internal use only. Do not modify the result, the behavior of 321 * modified results are undefined. 322 * @deprecated This API is ICU internal only. 323 * @hide draft / provisional / internal are hidden on Android 324 */ 325 @Deprecated getValueArray()326 public char[] getValueArray() 327 { 328 return values; 329 } 330 331 /** 332 * Overrides Cloneable 333 * @deprecated This API is ICU internal only. 334 * @hide draft / provisional / internal are hidden on Android 335 */ 336 @Override 337 @Deprecated clone()338 public Object clone() 339 { 340 try { 341 CompactCharArray other = (CompactCharArray) super.clone(); 342 other.values = values.clone(); 343 other.indices = indices.clone(); 344 if (hashes != null) other.hashes = hashes.clone(); 345 return other; 346 } catch (CloneNotSupportedException e) { 347 throw new ICUCloneNotSupportedException(e); 348 } 349 } 350 351 /** 352 * Compares the equality of two compact array objects. 353 * @param obj the compact array object to be compared with this. 354 * @return true if the current compact array object is the same 355 * as the compact array object obj; false otherwise. 356 * @deprecated This API is ICU internal only. 357 * @hide draft / provisional / internal are hidden on Android 358 */ 359 @Override 360 @Deprecated equals(Object obj)361 public boolean equals(Object obj) { 362 if (obj == null) return false; 363 if (this == obj) // quick check 364 return true; 365 if (getClass() != obj.getClass()) // same class? 366 return false; 367 CompactCharArray other = (CompactCharArray) obj; 368 for (int i = 0; i < UNICODECOUNT; i++) { 369 // could be sped up later 370 if (elementAt((char)i) != other.elementAt((char)i)) 371 return false; 372 } 373 return true; // we made it through the guantlet. 374 } 375 376 /** 377 * Generates the hash code for the compact array object 378 * @deprecated This API is ICU internal only. 379 * @hide draft / provisional / internal are hidden on Android 380 */ 381 @Override 382 @Deprecated hashCode()383 public int hashCode() { 384 int result = 0; 385 int increment = Math.min(3, values.length/16); 386 for (int i = 0; i < values.length; i+= increment) { 387 result = result * 37 + values[i]; 388 } 389 return result; 390 } 391 392 393 // -------------------------------------------------------------- 394 // private 395 // -------------------------------------------------------------- 396 397 /** 398 * Expanding takes the array back to a 65536 element array. 399 */ expand()400 private void expand() 401 { 402 int i; 403 if (isCompact) { 404 char[] tempArray; 405 hashes = new int[INDEXCOUNT]; 406 tempArray = new char[UNICODECOUNT]; 407 for (i = 0; i < UNICODECOUNT; ++i) { 408 tempArray[i] = elementAt((char)i); 409 } 410 for (i = 0; i < INDEXCOUNT; ++i) { 411 indices[i] = (char)(i<<BLOCKSHIFT); 412 } 413 values = null; 414 values = tempArray; 415 isCompact = false; 416 } 417 } 418 /** 419 * @deprecated This API is ICU internal only. 420 * @hide draft / provisional / internal are hidden on Android 421 */ 422 @Deprecated 423 public static final int BLOCKSHIFT = 5; // NormalizerBuilder needs - liu 424 static final int BLOCKCOUNT =(1<<BLOCKSHIFT); 425 static final int INDEXSHIFT =(16-BLOCKSHIFT); 426 static final int INDEXCOUNT =(1<<INDEXSHIFT); 427 static final int BLOCKMASK = BLOCKCOUNT - 1; 428 429 private char values[]; 430 private char indices[]; 431 private int[] hashes; 432 private boolean isCompact; 433 char defaultValue; 434 } 435