1 12 13 package org.eclipse.jface.viewers; 14 15 import java.util.Enumeration ; 16 import java.util.NoSuchElementException ; 17 18 28 final class CustomHashtable { 29 30 33 private static class HashMapEntry { 34 Object key, value; 35 36 HashMapEntry next; 37 38 HashMapEntry(Object theKey, Object theValue) { 39 key = theKey; 40 value = theValue; 41 } 42 } 43 44 private static final class EmptyEnumerator implements Enumeration { 45 public boolean hasMoreElements() { 46 return false; 47 } 48 49 public Object nextElement() { 50 throw new NoSuchElementException (); 51 } 52 } 53 54 private class HashEnumerator implements Enumeration { 55 boolean key; 56 57 int start; 58 59 HashMapEntry entry; 60 61 HashEnumerator(boolean isKey) { 62 key = isKey; 63 start = firstSlot; 64 } 65 66 public boolean hasMoreElements() { 67 if (entry != null) { 68 return true; 69 } 70 while (start <= lastSlot) { 71 if (elementData[start++] != null) { 72 entry = elementData[start - 1]; 73 return true; 74 } 75 } 76 return false; 77 } 78 79 public Object nextElement() { 80 if (hasMoreElements()) { 81 Object result = key ? entry.key : entry.value; 82 entry = entry.next; 83 return result; 84 } else { 85 throw new NoSuchElementException (); 86 } 87 } 88 } 89 90 transient int elementCount; 91 92 transient HashMapEntry[] elementData; 93 94 private float loadFactor; 95 96 private int threshold; 97 98 transient int firstSlot = 0; 99 100 transient int lastSlot = -1; 101 102 transient private IElementComparer comparer; 103 104 private static final EmptyEnumerator emptyEnumerator = new EmptyEnumerator(); 105 106 109 public static final int DEFAULT_CAPACITY = 13; 110 111 115 public CustomHashtable() { 116 this(13); 117 } 118 119 125 public CustomHashtable(int capacity) { 126 this(capacity, null); 127 } 128 129 137 public CustomHashtable(IElementComparer comparer) { 138 this(DEFAULT_CAPACITY, comparer); 139 } 140 141 151 public CustomHashtable(int capacity, IElementComparer comparer) { 152 if (capacity >= 0) { 153 elementCount = 0; 154 elementData = new HashMapEntry[capacity == 0 ? 1 : capacity]; 155 firstSlot = elementData.length; 156 loadFactor = 0.75f; 157 computeMaxSize(); 158 } else { 159 throw new IllegalArgumentException (); 160 } 161 this.comparer = comparer; 162 } 163 164 174 public CustomHashtable(CustomHashtable table, IElementComparer comparer) { 175 this(table.size() * 2, comparer); 176 for (int i = table.elementData.length; --i >= 0;) { 177 HashMapEntry entry = table.elementData[i]; 178 while (entry != null) { 179 put(entry.key, entry.value); 180 entry = entry.next; 181 } 182 } 183 } 184 185 194 public IElementComparer getComparer() { 195 return comparer; 196 } 197 198 private void computeMaxSize() { 199 threshold = (int) (elementData.length * loadFactor); 200 } 201 202 209 public boolean containsKey(Object key) { 210 return getEntry(key) != null; 211 } 212 213 220 public Enumeration elements() { 221 if (elementCount == 0) { 222 return emptyEnumerator; 223 } 224 return new HashEnumerator(false); 225 } 226 227 235 public Object get(Object key) { 236 int index = (hashCode(key) & 0x7FFFFFFF) % elementData.length; 237 HashMapEntry entry = elementData[index]; 238 while (entry != null) { 239 if (keyEquals(key, entry.key)) { 240 return entry.value; 241 } 242 entry = entry.next; 243 } 244 return null; 245 } 246 247 private HashMapEntry getEntry(Object key) { 248 int index = (hashCode(key) & 0x7FFFFFFF) % elementData.length; 249 HashMapEntry entry = elementData[index]; 250 while (entry != null) { 251 if (keyEquals(key, entry.key)) { 252 return entry; 253 } 254 entry = entry.next; 255 } 256 return null; 257 } 258 259 262 private int hashCode(Object key) { 263 if (comparer == null) { 264 return key.hashCode(); 265 } else { 266 return comparer.hashCode(key); 267 } 268 } 269 270 273 private boolean keyEquals(Object a, Object b) { 274 if (comparer == null) { 275 return a.equals(b); 276 } else { 277 return comparer.equals(a, b); 278 } 279 } 280 281 288 public Enumeration keys() { 289 if (elementCount == 0) { 290 return emptyEnumerator; 291 } 292 return new HashEnumerator(true); 293 } 294 295 305 public Object put(Object key, Object value) { 306 if (key != null && value != null) { 307 int index = (hashCode(key) & 0x7FFFFFFF) % elementData.length; 308 HashMapEntry entry = elementData[index]; 309 while (entry != null && !keyEquals(key, entry.key)) { 310 entry = entry.next; 311 } 312 if (entry == null) { 313 if (++elementCount > threshold) { 314 rehash(); 315 index = (hashCode(key) & 0x7FFFFFFF) % elementData.length; 316 } 317 if (index < firstSlot) { 318 firstSlot = index; 319 } 320 if (index > lastSlot) { 321 lastSlot = index; 322 } 323 entry = new HashMapEntry(key, value); 324 entry.next = elementData[index]; 325 elementData[index] = entry; 326 return null; 327 } 328 Object result = entry.value; 329 entry.key = key; entry.value = value; 331 return result; 332 } else { 333 throw new NullPointerException (); 334 } 335 } 336 337 341 private void rehash() { 342 int length = elementData.length << 1; 343 if (length == 0) { 344 length = 1; 345 } 346 firstSlot = length; 347 lastSlot = -1; 348 HashMapEntry[] newData = new HashMapEntry[length]; 349 for (int i = elementData.length; --i >= 0;) { 350 HashMapEntry entry = elementData[i]; 351 while (entry != null) { 352 int index = (hashCode(entry.key) & 0x7FFFFFFF) % length; 353 if (index < firstSlot) { 354 firstSlot = index; 355 } 356 if (index > lastSlot) { 357 lastSlot = index; 358 } 359 HashMapEntry next = entry.next; 360 entry.next = newData[index]; 361 newData[index] = entry; 362 entry = next; 363 } 364 } 365 elementData = newData; 366 computeMaxSize(); 367 } 368 369 376 public Object remove(Object key) { 377 HashMapEntry last = null; 378 int index = (hashCode(key) & 0x7FFFFFFF) % elementData.length; 379 HashMapEntry entry = elementData[index]; 380 while (entry != null && !keyEquals(key, entry.key)) { 381 last = entry; 382 entry = entry.next; 383 } 384 if (entry != null) { 385 if (last == null) { 386 elementData[index] = entry.next; 387 } else { 388 last.next = entry.next; 389 } 390 elementCount--; 391 return entry.value; 392 } 393 return null; 394 } 395 396 401 public int size() { 402 return elementCount; 403 } 404 405 410 public String toString() { 411 if (size() == 0) { 412 return "{}"; } 414 415 StringBuffer buffer = new StringBuffer (); 416 buffer.append('{'); 417 for (int i = elementData.length; --i >= 0;) { 418 HashMapEntry entry = elementData[i]; 419 while (entry != null) { 420 buffer.append(entry.key); 421 buffer.append('='); 422 buffer.append(entry.value); 423 buffer.append(", "); entry = entry.next; 425 } 426 } 427 if (elementCount > 0) { 429 buffer.setLength(buffer.length() - 2); 430 } 431 buffer.append('}'); 432 return buffer.toString(); 433 } 434 } 435 | Popular Tags |