1 7 package com.ibm.icu.util; 8 import com.ibm.icu.impl.Utility; 9 10 32 public final class CompactByteArray implements Cloneable { 33 34 39 public static final int UNICODECOUNT =65536; 40 41 47 public CompactByteArray() 48 { 49 this((byte)0); 50 } 51 52 58 public CompactByteArray(byte defaultValue) 59 { 60 int i; 61 values = new byte[UNICODECOUNT]; 62 indices = new char[INDEXCOUNT]; 63 hashes = new int[INDEXCOUNT]; 64 for (i = 0; i < UNICODECOUNT; ++i) { 65 values[i] = defaultValue; 66 } 67 for (i = 0; i < INDEXCOUNT; ++i) { 68 indices[i] = (char)(i<<BLOCKSHIFT); 69 hashes[i] = 0; 70 } 71 isCompact = false; 72 73 this.defaultValue = defaultValue; 74 } 75 76 84 public CompactByteArray(char indexArray[], 85 byte newValues[]) 86 { 87 int i; 88 if (indexArray.length != INDEXCOUNT) 89 throw new IllegalArgumentException ("Index out of bounds."); 90 for (i = 0; i < INDEXCOUNT; ++i) { 91 char index = indexArray[i]; 92 if ((index < 0) || (index >= newValues.length+BLOCKCOUNT)) 93 throw new IllegalArgumentException ("Index out of bounds."); 94 } 95 indices = indexArray; 96 values = newValues; 97 isCompact = true; 98 } 99 100 111 public CompactByteArray(String indexArray, 112 String valueArray) 113 { 114 this( Utility.RLEStringToCharArray(indexArray), 115 Utility.RLEStringToByteArray(valueArray)); 116 } 117 118 125 public byte elementAt(char index) 126 { 127 return (values[(indices[index >> BLOCKSHIFT] & 0xFFFF) 128 + (index & BLOCKMASK)]); 129 } 130 131 139 public void setElementAt(char index, byte value) 140 { 141 if (isCompact) 142 expand(); 143 values[(int)index] = value; 144 touchBlock(index >> BLOCKSHIFT, value); 145 } 146 147 156 public void setElementAt(char start, char end, byte value) 157 { 158 int i; 159 if (isCompact) { 160 expand(); 161 } 162 for (i = start; i <= end; ++i) { 163 values[i] = value; 164 touchBlock(i >> BLOCKSHIFT, value); 165 } 166 } 167 172 public void compact() { 173 compact(false); 174 } 175 176 181 public void compact(boolean exhaustive) 182 { 183 if (!isCompact) { 184 int limitCompacted = 0; 185 int iBlockStart = 0; 186 char iUntouched = 0xFFFF; 187 188 for (int i = 0; i < indices.length; ++i, iBlockStart += BLOCKCOUNT) { 189 indices[i] = 0xFFFF; 190 boolean touched = blockTouched(i); 191 if (!touched && iUntouched != 0xFFFF) { 192 indices[i] = iUntouched; 196 } else { 197 int jBlockStart = 0; 198 int j = 0; 199 for (j = 0; j < limitCompacted; 200 ++j, jBlockStart += BLOCKCOUNT) { 201 if (hashes[i] == hashes[j] && 202 arrayRegionMatches(values, iBlockStart, 203 values, jBlockStart, BLOCKCOUNT)) { 204 indices[i] = (char)jBlockStart; 205 break; 206 } 207 } 208 if (indices[i] == 0xFFFF) { 209 System.arraycopy(values, iBlockStart, 211 values, jBlockStart, BLOCKCOUNT); 212 indices[i] = (char)jBlockStart; 213 hashes[j] = hashes[i]; 214 ++limitCompacted; 215 216 if (!touched) { 217 iUntouched = (char)jBlockStart; 220 } 221 } 222 } 223 } 224 int newSize = limitCompacted*BLOCKCOUNT; 226 byte[] result = new byte[newSize]; 227 System.arraycopy(values, 0, result, 0, newSize); 228 values = result; 229 isCompact = true; 230 hashes = null; 231 } 232 } 233 234 239 final static boolean arrayRegionMatches(byte[] source, int sourceStart, 240 byte[] target, int targetStart, 241 int len) 242 { 243 int sourceEnd = sourceStart + len; 244 int delta = targetStart - sourceStart; 245 for (int i = sourceStart; i < sourceEnd; i++) { 246 if (source[i] != target[i + delta]) 247 return false; 248 } 249 return true; 250 } 251 252 256 private final void touchBlock(int i, int value) { 257 hashes[i] = (hashes[i] + (value<<1)) | 1; 258 } 259 260 264 private final boolean blockTouched(int i) { 265 return hashes[i] != 0; 266 } 267 268 274 public char[] getIndexArray() 275 { 276 return indices; 277 } 278 279 285 public byte[] getValueArray() 286 { 287 return values; 288 } 289 290 295 public Object clone() 296 { 297 try { 298 CompactByteArray other = (CompactByteArray) super.clone(); 299 other.values = (byte[])values.clone(); 300 other.indices = (char[])indices.clone(); 301 if (hashes != null) other.hashes = (int[])hashes.clone(); 302 return other; 303 } catch (CloneNotSupportedException e) { 304 throw new IllegalStateException (); 305 } 306 } 307 308 316 public boolean equals(Object obj) { 317 if (obj == null) return false; 318 if (this == obj) return true; 320 if (getClass() != obj.getClass()) return false; 322 CompactByteArray other = (CompactByteArray) obj; 323 for (int i = 0; i < UNICODECOUNT; i++) { 324 if (elementAt((char)i) != other.elementAt((char)i)) 326 return false; 327 } 328 return true; } 330 331 336 public int hashCode() { 337 int result = 0; 338 int increment = Math.min(3, values.length/16); 339 for (int i = 0; i < values.length; i+= increment) { 340 result = result * 37 + values[i]; 341 } 342 return result; 343 } 344 345 349 352 private void expand() 353 { 354 int i; 355 if (isCompact) { 356 byte[] tempArray; 357 hashes = new int[INDEXCOUNT]; 358 tempArray = new byte[UNICODECOUNT]; 359 for (i = 0; i < UNICODECOUNT; ++i) { 360 byte value = elementAt((char)i); 361 tempArray[i] = value; 362 touchBlock(i >> BLOCKSHIFT, value); 363 } 364 for (i = 0; i < INDEXCOUNT; ++i) { 365 indices[i] = (char)(i<<BLOCKSHIFT); 366 } 367 values = null; 368 values = tempArray; 369 isCompact = false; 370 } 371 } 372 373 private static final int BLOCKSHIFT =7; 374 private static final int BLOCKCOUNT =(1<<BLOCKSHIFT); 375 private static final int INDEXSHIFT =(16-BLOCKSHIFT); 376 private static final int INDEXCOUNT =(1<<INDEXSHIFT); 377 private static final int BLOCKMASK = BLOCKCOUNT - 1; 378 379 private byte[] values; 380 private char indices[]; 381 private int[] hashes; 382 private boolean isCompact; 383 byte defaultValue; 384 }; 385 | Popular Tags |