1 22 package org.eclipse.core.internal.registry; 23 24 import java.lang.ref.*; 25 26 51 public class ReferenceMap { 52 53 58 private static class HardRef implements IEntry { 59 60 private int key; 61 private IEntry next; 62 65 private Object value; 66 67 public HardRef(int key, Object value, IEntry next) { 68 this.key = key; 69 this.value = value; 70 this.next = next; 71 } 72 73 public int getKey() { 74 return key; 75 } 76 77 public IEntry getNext() { 78 return next; 79 } 80 81 public Object getValue() { 82 return value; 83 } 84 85 public void setNext(IEntry next) { 86 this.next = next; 87 } 88 89 public String toString() { 90 return "HardRef(" + key + ',' + value + ')'; } 92 } 93 94 98 private static interface IEntry { 99 103 public int getKey(); 104 105 111 public IEntry getNext(); 112 113 117 public Object getValue(); 118 119 125 public void setNext(IEntry next); 126 } 127 128 132 private static class SoftRef extends SoftReference implements IEntry { 133 private int key; 134 137 private IEntry next; 138 139 public SoftRef(int key, Object value, IEntry next, ReferenceQueue q) { 140 super(value, q); 141 this.key = key; 142 this.next = next; 143 } 144 145 public int getKey() { 146 return key; 147 } 148 149 public IEntry getNext() { 150 return next; 151 } 152 153 public Object getValue() { 154 return super.get(); 155 } 156 157 public void setNext(IEntry next) { 158 this.next = next; 159 } 160 } 161 162 165 final public static int HARD = 0; 166 167 170 final public static int SOFT = 1; 171 172 private int entryCount; 173 174 181 private float loadFactor; 182 183 186 private transient ReferenceQueue queue = new ReferenceQueue(); 187 188 191 private transient int size; 192 193 196 private transient IEntry[] table; 197 198 202 private transient int threshold; 203 204 210 int valueType; 211 212 222 public ReferenceMap(int referenceType, int capacity, float loadFactor) { 223 super(); 224 if (referenceType != HARD && referenceType != SOFT) 225 throw new IllegalArgumentException (" must be HARD or SOFT."); if (capacity <= 0) 227 throw new IllegalArgumentException ("capacity must be positive"); if ((loadFactor <= 0.0f) || (loadFactor >= 1.0f)) 229 throw new IllegalArgumentException ("Load factor must be greater than 0 and less than 1."); 231 this.valueType = referenceType; 232 233 int initialSize = 1; 234 while (initialSize < capacity) 235 initialSize *= 2; 236 237 this.table = new IEntry[initialSize]; 238 this.loadFactor = loadFactor; 239 this.threshold = (int) (initialSize * loadFactor); 240 } 241 242 246 private Object doRemove(int key) { 247 int index = indexFor(key); 248 IEntry previous = null; 249 IEntry entry = table[index]; 250 while (entry != null) { 251 if (key == entry.getKey()) { 252 if (previous == null) 253 table[index] = entry.getNext(); 254 else 255 previous.setNext(entry.getNext()); 256 this.size--; 257 return entry.getValue(); 258 } 259 previous = entry; 260 entry = entry.getNext(); 261 } 262 return null; 263 } 264 265 271 public Object get(int key) { 272 purge(); 273 for (IEntry entry = table[indexFor(key)]; entry != null; entry = entry.getNext()) 274 if (entry.getKey() == key) 275 return entry.getValue(); 276 return null; 277 } 278 279 283 private int indexFor(int hash) { 284 hash += ~(hash << 15); 286 hash ^= (hash >>> 10); 287 hash += (hash << 3); 288 hash ^= (hash >>> 6); 289 hash += ~(hash << 11); 290 hash ^= (hash >>> 16); 291 return hash & (table.length - 1); 292 } 293 294 302 private IEntry newEntry(int key, Object value, IEntry next) { 303 entryCount++; 304 switch (valueType) { 305 case HARD : 306 return new HardRef(key, value, next); 307 case SOFT : 308 return new SoftRef(key, value, next, queue); 309 default : 310 throw new Error (); 311 } 312 } 313 314 327 private void purge() { 328 Reference ref = queue.poll(); 329 while (ref != null) { 330 doRemove(((IEntry) ref).getKey()); 331 ref.clear(); 332 ref = queue.poll(); 333 } 334 } 335 336 345 public void put(int key, Object value) { 346 if (value == null) 347 throw new NullPointerException ("null values not allowed"); 349 purge(); 350 351 if (size + 1 > threshold) 352 resize(); 353 354 int index = indexFor(key); 355 IEntry previous = null; 356 IEntry entry = table[index]; 357 while (entry != null) { 358 if (key == entry.getKey()) { 359 if (previous == null) 360 table[index] = newEntry(key, value, entry.getNext()); 361 else 362 previous.setNext(newEntry(key, value, entry.getNext())); 363 return; 364 } 365 previous = entry; 366 entry = entry.getNext(); 367 } 368 this.size++; 369 table[index] = newEntry(key, value, table[index]); 370 } 371 372 379 public Object remove(int key) { 380 purge(); 381 return doRemove(key); 382 } 383 384 390 private void resize() { 391 IEntry[] old = table; 392 table = new IEntry[old.length * 2]; 393 394 for (int i = 0; i < old.length; i++) { 395 IEntry next = old[i]; 396 while (next != null) { 397 IEntry entry = next; 398 next = next.getNext(); 399 int index = indexFor(entry.getKey()); 400 entry.setNext(table[index]); 401 table[index] = entry; 402 } 403 old[i] = null; 404 } 405 threshold = (int) (table.length * loadFactor); 406 } 407 } | Popular Tags |