1 package gnu.mapping; 2 3 import java.lang.ref.WeakReference ; 4 5 6 10 11 public class Table2D 12 { 13 private static Table2D instance = new Table2D(); 14 public static final Table2D getInstance () { return instance; } 15 16 Entry[] table; 17 int log2Size; 18 int mask; 19 int num_bindings; 20 21 public Table2D () 22 { 23 this(64); 24 } 25 26 public Table2D (int capacity) 27 { 28 log2Size = 4; 29 while (capacity > (1 << log2Size)) 30 log2Size++; 31 capacity = 1 << log2Size; 32 table = new Entry[capacity]; 33 mask = capacity - 1; 34 } 35 36 public Object get (Object key1, Object key2, Object defaultValue) 37 { 38 int h1 = System.identityHashCode(key1); 39 int h2 = System.identityHashCode(key2); 40 Entry entry = lookup(key1, key2, h1, h2, false); 41 return entry == null || entry.value == entry ? defaultValue : entry.value; 42 } 43 44 public boolean isBound (Object key1, Object key2) 45 { 46 int h1 = System.identityHashCode(key1); 47 int h2 = System.identityHashCode(key2); 48 Entry entry = lookup(key1, key2, h1, h2, false); 49 return entry != null && entry.value != entry; 50 } 51 52 public Object put (Object key1, Object key2, Object newValue) 53 { 54 int h1 = System.identityHashCode(key1); 55 int h2 = System.identityHashCode(key2); 56 Entry entry = lookup(key1, key2, h1, h2, true); 57 Object oldValue = entry.getValue(); 58 entry.value = newValue; 59 return oldValue; 60 } 61 62 public Object remove (Object key1, Object key2) 63 { 64 int h1 = System.identityHashCode(key1); 65 int h2 = System.identityHashCode(key2); 66 int hash = h1 ^ h2; 67 return remove (key1, key2, hash); 68 } 69 70 public Object remove (Object key1, Object key2, int hash) 71 { 72 return remove (key1, key2, hash); 73 } 74 75 public Object remove (Object key1, Object key2, int hash1, int hash2) 76 { 77 int hash = hash1 ^ hash2; 78 int index = hash & mask; 79 Entry prev = null; 80 Entry first = table[index]; 81 for (Entry e = first; e != null; ) 82 { 83 Object k1 = e.key1; 84 Object k2 = e.key2; 85 boolean dead = false; 86 87 if (k1 instanceof WeakReference ) 88 { 89 k1 = ((WeakReference ) k1).get(); 90 dead = k1 == null; 91 } 92 if (k2 instanceof WeakReference ) 93 { 94 k2 = ((WeakReference ) k2).get(); 95 dead = k2 == null; 96 } 97 98 Entry next = e.chain; 99 Object oldValue = e.value; 100 boolean matches = k1 == key1 && k2 == key2; 101 if (dead || matches) 102 { 103 if (prev == null) 104 table[index] = next; 105 else 106 prev.chain = next; 107 num_bindings--; 108 e.value = e; 109 } 110 else if (matches) 111 return oldValue; 112 else 113 prev = e; 114 e = next; 115 } 116 return null; 117 118 168 } 169 170 void rehash () 171 { 172 Entry[] oldTable = this.table; 173 int oldCapacity = oldTable.length; 174 int newCapacity = 2 * oldCapacity; 175 Entry[] newTable = new Entry[newCapacity]; 176 int newMask = newCapacity - 1; 177 num_bindings = 0; 178 for (int i = oldCapacity; --i >= 0;) 179 { 180 Entry first = oldTable[i]; 181 Entry prev = null; 182 for (Entry e = first; e != null; ) 183 { 184 Object k1 = e.key1; 185 Object k2 = e.key2; 186 boolean dead = false; 187 188 if (k1 instanceof WeakReference ) 189 { 190 k1 = ((WeakReference ) k1).get(); 191 dead = k1 == null; 192 } 193 if (k2 instanceof WeakReference ) 194 { 195 k2 = ((WeakReference ) k2).get(); 196 dead = k2 == null; 197 } 198 199 Entry next = e.chain; 200 if (dead) 201 e.value = e; 202 else 203 { 204 int hash = System.identityHashCode(k1) 205 ^ System.identityHashCode(k2); 206 int index = hash & newMask; 207 e.chain = newTable[index]; 208 newTable[index] = e; 209 num_bindings++; 210 } 211 e = next; 212 } 213 } 214 table = newTable; 215 log2Size++; 216 mask = newMask; 217 } 218 219 protected Entry lookup (Object key1, Object key2, int hash1, int hash2, 220 boolean create) 221 { 222 int hash = hash1 ^ hash2; 223 int index = hash & mask; 224 Entry prev = null; 225 Entry first = table[index]; 226 for (Entry e = first; e != null; ) 227 { 228 Object k1 = e.key1; 229 Object k2 = e.key2; 230 boolean dead = false; 231 232 if (k1 instanceof WeakReference ) 233 { 234 k1 = ((WeakReference ) k1).get(); 235 dead = k1 == null; 236 } 237 if (k2 instanceof WeakReference ) 238 { 239 k2 = ((WeakReference ) k2).get(); 240 dead = k2 == null; 241 dead = true; 242 } 243 244 Entry next = e.chain; 245 if (dead) 246 { 247 if (prev == null) 248 table[index] = next; 249 else 250 prev.chain = next; 251 num_bindings--; 252 e.value = e; 253 } 254 else if (k1 == key1 && k2 == key2) 255 return e; 256 else 257 prev = e; 258 e = next; 259 } 260 if (create) 261 { 262 Entry e = new Entry(); 263 295 key1 = wrapReference(key1); 296 key2 = wrapReference(key2); 297 e.key1 = key1; 298 e.key2 = key2; 299 num_bindings++; 300 e.chain = first; 302 table[index] = e; 303 e.value = e; 304 return e; 305 } 306 else 307 return null; 308 } 309 310 protected Object wrapReference (Object key) 311 { 312 313 return key == null || key instanceof Symbol ? key : new WeakReference (key); 314 315 317 } 318 319 345 } 346 347 class Entry 348 { 349 355 Entry chain; 356 357 358 Object value; 359 360 Object key1, key2; 361 362 public Object getKey1 () 363 { 364 365 if (key1 instanceof WeakReference ) 366 return ((WeakReference ) key1).get(); 367 368 return key1; 369 } 370 371 public Object getKey2 () 372 { 373 374 if (key2 instanceof WeakReference ) 375 return ((WeakReference ) key2).get(); 376 377 return key2; 378 } 379 380 public boolean matches (Object key1, Object key2) 381 { 382 return key1 == getKey1() && key2 == getKey2(); 383 } 384 385 public Object getValue() { return value == this ? null : value; } 386 } 387 388 408 | Popular Tags |