1 package gnu.mapping; 2 /* #ifdef JAVA2 */ 3 import java.lang.ref.WeakReference; 4 /* #endif */ 5 6 /** Maps 2 objects to another. 7 * Uses a weak references to each key, unless it is null or a Symbol. 8 * This should at some point be merged with SimpleEnvironment. FIXME. 9 */ 10 11 public class Table2D 12 { 13 private static Table2D instance = new Table2D(); getInstance()14 public static final Table2D getInstance () { return instance; } 15 16 Entry[] table; 17 int log2Size; 18 int mask; 19 int num_bindings; 20 Table2D()21 public Table2D () 22 { 23 this(64); 24 } 25 Table2D(int capacity)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 get(Object key1, Object key2, Object defaultValue)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 isBound(Object key1, Object key2)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 put(Object key1, Object key2, Object newValue)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 remove(Object key1, Object key2)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 remove(Object key1, Object key2, int hash)70 public Object remove (Object key1, Object key2, int hash) 71 { 72 return remove (key1, key2, hash); 73 } 74 remove(Object key1, Object key2, int hash1, int hash2)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 /* #ifdef JAVA2 */ 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 /* #endif */ 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 /* 119 // FIXME: clear reference queue 120 121 Entry first = table[index]; 122 Entry prev = null; 123 Entry e = first; 124 for (;;) 125 { 126 if (e == null) 127 return null; 128 if (e.hash == hash && e.matches(key1, key2)) 129 break; 130 prev = e; 131 e = e.chain; 132 } 133 134 Object oldValue = e.value; 135 e.value = e; 136 137 // If this the head of a non-empty list, we can't unlink it. 138 if ((key2 == null && e.next1 != e) 139 || (key1 == null && e.next2 != e)) 140 return oldValue; 141 142 Entry head1 = lookup(key1, null, hash1, 0, false); 143 144 if (prev == null) 145 table[index] = null; 146 else 147 prev.chain = e.chain; 148 149 Entry head2 = lookup(key2, null, hash2, 0, false); 150 for (Entry p = head1; ; p = p.next1) 151 { 152 Entry next = p.next; 153 if (next1 == e) 154 { 155 p.next1 = e.next1; 156 if (head1.next1 == head1 && head1.entry == head1) 157 { 158 } 159 break; 160 } 161 } 162 for (Entry e = table[index]; e != null; e = e.chain) 163 { 164 //if (e.hash != hash) 165 } 166 return entry == null ? defaultValue : entry.getValue(); 167 */ 168 } 169 rehash()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 /* #ifdef JAVA2 */ 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 /* #endif */ 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 lookup(Object key1, Object key2, int hash1, int hash2, boolean create)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 /* #ifdef JAVA2 */ 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 /* #endif */ 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 /* 264 Entry head1; 265 if (key2 != null) 266 { 267 head1 = lookup(key1, null, hash1, 0, true); 268 e.ref1 = head1.ref1; 269 e,next1 = head1; 270 head1.next1 = e; 271 e1.ref1 = head1.ref1; 272 } 273 else 274 { 275 head1 = e; 276 e.ref1 = key1 == null ? null : new WeakReference(key1); 277 e.next1 = e; 278 } 279 if (key1 != null) 280 { 281 head2 = lookup(key2, null, hash2, 0, true); 282 e.ref2 = head2.ref2; 283 e,next2 = head2; 284 head2.next2 = e; 285 e1.ref2 = head1.ref2; 286 } 287 else 288 { 289 head2 = e; 290 e.ref2 = key2 == null ? null : new WeakReference(key2); 291 e.next2 = e; 292 } 293 e.hash = hash; 294 */ 295 key1 = wrapReference(key1); 296 key2 = wrapReference(key2); 297 e.key1 = key1; 298 e.key2 = key2; 299 num_bindings++; 300 // FIXME maybe rehash. 301 e.chain = first; 302 table[index] = e; 303 e.value = e; 304 return e; 305 } 306 else 307 return null; 308 } 309 wrapReference(Object key)310 protected Object wrapReference (Object key) 311 { 312 /* #ifdef JAVA2 */ 313 return key == null || key instanceof Symbol ? key : new WeakReference(key); 314 /* #else */ 315 // return key; 316 /* #endif */ 317 } 318 319 /* 320 Head getHead (Object key, boolean isDim2, int hash) 321 { 322 int index = hash & mask; 323 // FIXME: clear reference queue 324 Entry first = table[index]; 325 for (Entry e = first; e != null; e = e.chain) 326 { 327 if (e.hash != hash || ! (e instanceof Head)) 328 continue; 329 Head h = (Head) e; 330 if (h.ref.ref() == key) 331 return h; 332 } 333 Head h = new Head(); 334 h.hash = hash; 335 if (isDim2) 336 h.next2 = h; 337 else 338 h.next1 = h; 339 h.chain = first; 340 table[index] = h; 341 h.ref = new WeakReference(key); 342 return h; 343 } 344 */ 345 } 346 347 class Entry 348 { 349 //int hash; 350 ///** Next in circular list with same key1. */ 351 //Entry next1; 352 ///** Next in circular list with same key2. */ 353 //Entry next2; 354 /** Next in list in same hash bucket. */ 355 Entry chain; 356 357 /** Value, if nound. Point to self if unbound. */ 358 Object value; 359 360 Object key1, key2; 361 getKey1()362 public Object getKey1 () 363 { 364 /* #ifdef JAVA2 */ 365 if (key1 instanceof WeakReference) 366 return ((WeakReference) key1).get(); 367 /* #endif */ 368 return key1; 369 } 370 getKey2()371 public Object getKey2 () 372 { 373 /* #ifdef JAVA2 */ 374 if (key2 instanceof WeakReference) 375 return ((WeakReference) key2).get(); 376 /* #endif */ 377 return key2; 378 } 379 matches(Object key1, Object key2)380 public boolean matches (Object key1, Object key2) 381 { 382 return key1 == getKey1() && key2 == getKey2(); 383 } 384 getValue()385 public Object getValue() { return value == this ? null : value; } 386 } 387 388 /* 389 class Head extends Entry 390 { 391 WeakRefeference ref; 392 393 public LList make List () 394 { 395 LList list = LList.Empty; 396 for (Entry e = next1;// FIXME or next2 397 e != null; 398 e = e.next1 // FIXME or next2 399 ) 400 { 401 list = new Car (e.getKey1(),//FIXME 402 new Car (e.value, list)); 403 } 404 return list; 405 } 406 } 407 */ 408