Table2D.java 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. package gnu.mapping;
  2. /* #ifdef JAVA2 */
  3. import java.lang.ref.WeakReference;
  4. /* #endif */
  5. /** Maps 2 objects to another.
  6. * Uses a weak references to each key, unless it is null or a Symbol.
  7. * This should at some point be merged with SimpleEnvironment. FIXME.
  8. */
  9. public class Table2D
  10. {
  11. private static Table2D instance = new Table2D();
  12. public static final Table2D getInstance () { return instance; }
  13. Entry[] table;
  14. int log2Size;
  15. int mask;
  16. int num_bindings;
  17. public Table2D ()
  18. {
  19. this(64);
  20. }
  21. public Table2D (int capacity)
  22. {
  23. log2Size = 4;
  24. while (capacity > (1 << log2Size))
  25. log2Size++;
  26. capacity = 1 << log2Size;
  27. table = new Entry[capacity];
  28. mask = capacity - 1;
  29. }
  30. public Object get (Object key1, Object key2, Object defaultValue)
  31. {
  32. int h1 = System.identityHashCode(key1);
  33. int h2 = System.identityHashCode(key2);
  34. Entry entry = lookup(key1, key2, h1, h2, false);
  35. return entry == null || entry.value == entry ? defaultValue : entry.value;
  36. }
  37. public boolean isBound (Object key1, Object key2)
  38. {
  39. int h1 = System.identityHashCode(key1);
  40. int h2 = System.identityHashCode(key2);
  41. Entry entry = lookup(key1, key2, h1, h2, false);
  42. return entry != null && entry.value != entry;
  43. }
  44. public Object put (Object key1, Object key2, Object newValue)
  45. {
  46. int h1 = System.identityHashCode(key1);
  47. int h2 = System.identityHashCode(key2);
  48. Entry entry = lookup(key1, key2, h1, h2, true);
  49. Object oldValue = entry.getValue();
  50. entry.value = newValue;
  51. return oldValue;
  52. }
  53. public Object remove (Object key1, Object key2)
  54. {
  55. int h1 = System.identityHashCode(key1);
  56. int h2 = System.identityHashCode(key2);
  57. int hash = h1 ^ h2;
  58. return remove (key1, key2, hash);
  59. }
  60. public Object remove (Object key1, Object key2, int hash)
  61. {
  62. return remove (key1, key2, hash);
  63. }
  64. public Object remove (Object key1, Object key2, int hash1, int hash2)
  65. {
  66. int hash = hash1 ^ hash2;
  67. int index = hash & mask;
  68. Entry prev = null;
  69. Entry first = table[index];
  70. for (Entry e = first; e != null; )
  71. {
  72. Object k1 = e.key1;
  73. Object k2 = e.key2;
  74. boolean dead = false;
  75. /* #ifdef JAVA2 */
  76. if (k1 instanceof WeakReference)
  77. {
  78. k1 = ((WeakReference) k1).get();
  79. dead = k1 == null;
  80. }
  81. if (k2 instanceof WeakReference)
  82. {
  83. k2 = ((WeakReference) k2).get();
  84. dead = k2 == null;
  85. }
  86. /* #endif */
  87. Entry next = e.chain;
  88. Object oldValue = e.value;
  89. boolean matches = k1 == key1 && k2 == key2;
  90. if (dead || matches)
  91. {
  92. if (prev == null)
  93. table[index] = next;
  94. else
  95. prev.chain = next;
  96. num_bindings--;
  97. e.value = e;
  98. }
  99. else if (matches)
  100. return oldValue;
  101. else
  102. prev = e;
  103. e = next;
  104. }
  105. return null;
  106. /*
  107. // FIXME: clear reference queue
  108. Entry first = table[index];
  109. Entry prev = null;
  110. Entry e = first;
  111. for (;;)
  112. {
  113. if (e == null)
  114. return null;
  115. if (e.hash == hash && e.matches(key1, key2))
  116. break;
  117. prev = e;
  118. e = e.chain;
  119. }
  120. Object oldValue = e.value;
  121. e.value = e;
  122. // If this the head of a non-empty list, we can't unlink it.
  123. if ((key2 == null && e.next1 != e)
  124. || (key1 == null && e.next2 != e))
  125. return oldValue;
  126. Entry head1 = lookup(key1, null, hash1, 0, false);
  127. if (prev == null)
  128. table[index] = null;
  129. else
  130. prev.chain = e.chain;
  131. Entry head2 = lookup(key2, null, hash2, 0, false);
  132. for (Entry p = head1; ; p = p.next1)
  133. {
  134. Entry next = p.next;
  135. if (next1 == e)
  136. {
  137. p.next1 = e.next1;
  138. if (head1.next1 == head1 && head1.entry == head1)
  139. {
  140. }
  141. break;
  142. }
  143. }
  144. for (Entry e = table[index]; e != null; e = e.chain)
  145. {
  146. //if (e.hash != hash)
  147. }
  148. return entry == null ? defaultValue : entry.getValue();
  149. */
  150. }
  151. void rehash ()
  152. {
  153. Entry[] oldTable = this.table;
  154. int oldCapacity = oldTable.length;
  155. int newCapacity = 2 * oldCapacity;
  156. Entry[] newTable = new Entry[newCapacity];
  157. int newMask = newCapacity - 1;
  158. num_bindings = 0;
  159. for (int i = oldCapacity; --i >= 0;)
  160. {
  161. Entry first = oldTable[i];
  162. Entry prev = null;
  163. for (Entry e = first; e != null; )
  164. {
  165. Object k1 = e.key1;
  166. Object k2 = e.key2;
  167. boolean dead = false;
  168. /* #ifdef JAVA2 */
  169. if (k1 instanceof WeakReference)
  170. {
  171. k1 = ((WeakReference) k1).get();
  172. dead = k1 == null;
  173. }
  174. if (k2 instanceof WeakReference)
  175. {
  176. k2 = ((WeakReference) k2).get();
  177. dead = k2 == null;
  178. }
  179. /* #endif */
  180. Entry next = e.chain;
  181. if (dead)
  182. e.value = e;
  183. else
  184. {
  185. int hash = System.identityHashCode(k1)
  186. ^ System.identityHashCode(k2);
  187. int index = hash & newMask;
  188. e.chain = newTable[index];
  189. newTable[index] = e;
  190. num_bindings++;
  191. }
  192. e = next;
  193. }
  194. }
  195. table = newTable;
  196. log2Size++;
  197. mask = newMask;
  198. }
  199. protected Entry lookup (Object key1, Object key2, int hash1, int hash2,
  200. boolean create)
  201. {
  202. int hash = hash1 ^ hash2;
  203. int index = hash & mask;
  204. Entry prev = null;
  205. Entry first = table[index];
  206. for (Entry e = first; e != null; )
  207. {
  208. Object k1 = e.key1;
  209. Object k2 = e.key2;
  210. boolean dead = false;
  211. /* #ifdef JAVA2 */
  212. if (k1 instanceof WeakReference)
  213. {
  214. k1 = ((WeakReference) k1).get();
  215. dead = k1 == null;
  216. }
  217. if (k2 instanceof WeakReference)
  218. {
  219. k2 = ((WeakReference) k2).get();
  220. dead = k2 == null;
  221. dead = true;
  222. }
  223. /* #endif */
  224. Entry next = e.chain;
  225. if (dead)
  226. {
  227. if (prev == null)
  228. table[index] = next;
  229. else
  230. prev.chain = next;
  231. num_bindings--;
  232. e.value = e;
  233. }
  234. else if (k1 == key1 && k2 == key2)
  235. return e;
  236. else
  237. prev = e;
  238. e = next;
  239. }
  240. if (create)
  241. {
  242. Entry e = new Entry();
  243. /*
  244. Entry head1;
  245. if (key2 != null)
  246. {
  247. head1 = lookup(key1, null, hash1, 0, true);
  248. e.ref1 = head1.ref1;
  249. e,next1 = head1;
  250. head1.next1 = e;
  251. e1.ref1 = head1.ref1;
  252. }
  253. else
  254. {
  255. head1 = e;
  256. e.ref1 = key1 == null ? null : new WeakReference(key1);
  257. e.next1 = e;
  258. }
  259. if (key1 != null)
  260. {
  261. head2 = lookup(key2, null, hash2, 0, true);
  262. e.ref2 = head2.ref2;
  263. e,next2 = head2;
  264. head2.next2 = e;
  265. e1.ref2 = head1.ref2;
  266. }
  267. else
  268. {
  269. head2 = e;
  270. e.ref2 = key2 == null ? null : new WeakReference(key2);
  271. e.next2 = e;
  272. }
  273. e.hash = hash;
  274. */
  275. key1 = wrapReference(key1);
  276. key2 = wrapReference(key2);
  277. e.key1 = key1;
  278. e.key2 = key2;
  279. num_bindings++;
  280. // FIXME maybe rehash.
  281. e.chain = first;
  282. table[index] = e;
  283. e.value = e;
  284. return e;
  285. }
  286. else
  287. return null;
  288. }
  289. protected Object wrapReference (Object key)
  290. {
  291. /* #ifdef JAVA2 */
  292. return key == null || key instanceof Symbol ? key : new WeakReference(key);
  293. /* #else */
  294. // return key;
  295. /* #endif */
  296. }
  297. /*
  298. Head getHead (Object key, boolean isDim2, int hash)
  299. {
  300. int index = hash & mask;
  301. // FIXME: clear reference queue
  302. Entry first = table[index];
  303. for (Entry e = first; e != null; e = e.chain)
  304. {
  305. if (e.hash != hash || ! (e instanceof Head))
  306. continue;
  307. Head h = (Head) e;
  308. if (h.ref.ref() == key)
  309. return h;
  310. }
  311. Head h = new Head();
  312. h.hash = hash;
  313. if (isDim2)
  314. h.next2 = h;
  315. else
  316. h.next1 = h;
  317. h.chain = first;
  318. table[index] = h;
  319. h.ref = new WeakReference(key);
  320. return h;
  321. }
  322. */
  323. }
  324. class Entry
  325. {
  326. //int hash;
  327. ///** Next in circular list with same key1. */
  328. //Entry next1;
  329. ///** Next in circular list with same key2. */
  330. //Entry next2;
  331. /** Next in list in same hash bucket. */
  332. Entry chain;
  333. /** Value, if nound. Point to self if unbound. */
  334. Object value;
  335. Object key1, key2;
  336. public Object getKey1 ()
  337. {
  338. /* #ifdef JAVA2 */
  339. if (key1 instanceof WeakReference)
  340. return ((WeakReference) key1).get();
  341. /* #endif */
  342. return key1;
  343. }
  344. public Object getKey2 ()
  345. {
  346. /* #ifdef JAVA2 */
  347. if (key2 instanceof WeakReference)
  348. return ((WeakReference) key2).get();
  349. /* #endif */
  350. return key2;
  351. }
  352. public boolean matches (Object key1, Object key2)
  353. {
  354. return key1 == getKey1() && key2 == getKey2();
  355. }
  356. public Object getValue() { return value == this ? null : value; }
  357. }
  358. /*
  359. class Head extends Entry
  360. {
  361. WeakRefeference ref;
  362. public LList make List ()
  363. {
  364. LList list = LList.Empty;
  365. for (Entry e = next1;// FIXME or next2
  366. e != null;
  367. e = e.next1 // FIXME or next2
  368. )
  369. {
  370. list = new Car (e.getKey1(),//FIXME
  371. new Car (e.value, list));
  372. }
  373. return list;
  374. }
  375. }
  376. */