1 7 8 package com.ibm.icu.util; 9 10 import com.ibm.icu.impl.Utility; 11 12 33 public final class CompactCharArray implements Cloneable { 34 35 40 public static final int UNICODECOUNT = 65536; 41 42 48 public CompactCharArray() 49 { 50 this((char)0); 51 } 52 53 59 public CompactCharArray(char defaultValue) 60 { 61 int i; 62 values = new char[UNICODECOUNT]; 63 indices = new char[INDEXCOUNT]; 64 hashes = new int[INDEXCOUNT]; 65 for (i = 0; i < UNICODECOUNT; ++i) { 66 values[i] = defaultValue; 67 } 68 for (i = 0; i < INDEXCOUNT; ++i) { 69 indices[i] = (char)(i<<BLOCKSHIFT); 70 hashes[i] = 0; 71 } 72 isCompact = false; 73 74 this.defaultValue = defaultValue; 75 } 76 77 85 public CompactCharArray(char indexArray[], 86 char newValues[]) 87 { 88 int i; 89 if (indexArray.length != INDEXCOUNT) 90 throw new IllegalArgumentException ("Index out of bounds."); 91 for (i = 0; i < INDEXCOUNT; ++i) { 92 char index = indexArray[i]; 93 if ((index < 0) || (index >= newValues.length+BLOCKCOUNT)) 94 throw new IllegalArgumentException ("Index out of bounds."); 95 } 96 indices = indexArray; 97 values = newValues; 98 isCompact = true; 99 } 100 101 112 public CompactCharArray(String indexArray, 113 String valueArray) 114 { 115 this( Utility.RLEStringToCharArray(indexArray), 116 Utility.RLEStringToCharArray(valueArray)); 117 } 118 119 126 public char elementAt(char index) 127 { 128 int ix = (indices[index >> BLOCKSHIFT] & 0xFFFF) 129 + (index & BLOCKMASK); 130 return ix >= values.length ? defaultValue : values[ix]; 131 } 132 133 141 public void setElementAt(char index, char value) 142 { 143 if (isCompact) 144 expand(); 145 values[(int)index] = value; 146 touchBlock(index >> BLOCKSHIFT, value); 147 } 148 149 158 public void setElementAt(char start, char end, char value) 159 { 160 int i; 161 if (isCompact) { 162 expand(); 163 } 164 for (i = start; i <= end; ++i) { 165 values[i] = value; 166 touchBlock(i >> BLOCKSHIFT, value); 167 } 168 } 169 174 public void compact() { 175 compact(true); 176 } 177 178 183 public void compact(boolean exhaustive) 184 { 185 if (!isCompact) { 186 int iBlockStart = 0; 187 char iUntouched = 0xFFFF; 188 int newSize = 0; 189 190 char[] target = exhaustive ? new char[UNICODECOUNT] : values; 191 192 for (int i = 0; i < indices.length; ++i, iBlockStart += BLOCKCOUNT) { 193 indices[i] = 0xFFFF; 194 boolean touched = blockTouched(i); 195 if (!touched && iUntouched != 0xFFFF) { 196 indices[i] = iUntouched; 200 } else { 201 int jBlockStart = 0; 202 for (int j = 0; j < i; ++j, jBlockStart += BLOCKCOUNT) { 204 if (hashes[i] == hashes[j] && 205 arrayRegionMatches(values, iBlockStart, 206 values, jBlockStart, BLOCKCOUNT)) { 207 indices[i] = indices[j]; 208 } 209 } 210 if (indices[i] == 0xFFFF) { 211 int dest; if (exhaustive) { 213 dest = FindOverlappingPosition(iBlockStart, target, 215 newSize); 216 } else { 217 dest = newSize; 219 } 220 int limit = dest + BLOCKCOUNT; 221 if (limit > newSize) { 222 for (int j = newSize; j < limit; ++j) { 223 target[j] = values[iBlockStart + j - dest]; 224 } 225 newSize = limit; 226 } 227 indices[i] = (char)dest; 228 if (!touched) { 229 iUntouched = (char)jBlockStart; 232 } 233 } 234 } 235 } 236 char[] result = new char[newSize]; 238 System.arraycopy(target, 0, result, 0, newSize); 239 values = result; 240 isCompact = true; 241 hashes = null; 242 } 243 } 244 245 private int FindOverlappingPosition(int start, char[] tempValues, int tempCount) 246 { 247 for (int i = 0; i < tempCount; i += 1) { 248 int currentCount = BLOCKCOUNT; 249 if (i + BLOCKCOUNT > tempCount) { 250 currentCount = tempCount - i; 251 } 252 if (arrayRegionMatches(values, start, tempValues, i, currentCount)) 253 return i; 254 } 255 return tempCount; 256 } 257 258 263 final static boolean arrayRegionMatches(char[] source, int sourceStart, 264 char[] target, int targetStart, 265 int len) 266 { 267 int sourceEnd = sourceStart + len; 268 int delta = targetStart - sourceStart; 269 for (int i = sourceStart; i < sourceEnd; i++) { 270 if (source[i] != target[i + delta]) 271 return false; 272 } 273 return true; 274 } 275 276 280 private final void touchBlock(int i, int value) { 281 hashes[i] = (hashes[i] + (value<<1)) | 1; 282 } 283 284 288 private final boolean blockTouched(int i) { 289 return hashes[i] != 0; 290 } 291 292 298 public char[] getIndexArray() 299 { 300 return indices; 301 } 302 303 309 public char[] getValueArray() 310 { 311 return values; 312 } 313 314 319 public Object clone() 320 { 321 try { 322 CompactCharArray other = (CompactCharArray) super.clone(); 323 other.values = (char[])values.clone(); 324 other.indices = (char[])indices.clone(); 325 if (hashes != null) other.hashes = (int[])hashes.clone(); 326 return other; 327 } catch (CloneNotSupportedException e) { 328 throw new IllegalStateException (); 329 } 330 } 331 332 340 public boolean equals(Object obj) { 341 if (obj == null) return false; 342 if (this == obj) return true; 344 if (getClass() != obj.getClass()) return false; 346 CompactCharArray other = (CompactCharArray) obj; 347 for (int i = 0; i < UNICODECOUNT; i++) { 348 if (elementAt((char)i) != other.elementAt((char)i)) 350 return false; 351 } 352 return true; } 354 355 360 public int hashCode() { 361 int result = 0; 362 int increment = Math.min(3, values.length/16); 363 for (int i = 0; i < values.length; i+= increment) { 364 result = result * 37 + values[i]; 365 } 366 return result; 367 } 368 369 370 374 377 private void expand() 378 { 379 int i; 380 if (isCompact) { 381 char[] tempArray; 382 hashes = new int[INDEXCOUNT]; 383 tempArray = new char[UNICODECOUNT]; 384 for (i = 0; i < UNICODECOUNT; ++i) { 385 tempArray[i] = elementAt((char)i); 386 } 387 for (i = 0; i < INDEXCOUNT; ++i) { 388 indices[i] = (char)(i<<BLOCKSHIFT); 389 } 390 values = null; 391 values = tempArray; 392 isCompact = false; 393 } 394 } 395 399 public static final int BLOCKSHIFT = 5; static final int BLOCKCOUNT =(1<<BLOCKSHIFT); 401 static final int INDEXSHIFT =(16-BLOCKSHIFT); 402 static final int INDEXCOUNT =(1<<INDEXSHIFT); 403 static final int BLOCKMASK = BLOCKCOUNT - 1; 404 405 private char values[]; 406 private char indices[]; 407 private int[] hashes; 408 private boolean isCompact; 409 char defaultValue; 410 }; 411 | Popular Tags |