1. /*
  2. * @(#)IdentityHashtable.java 1.9 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * Licensed Materials - Property of IBM
  9. * RMI-IIOP v1.0
  10. * Copyright IBM Corp. 1998 1999 All Rights Reserved
  11. *
  12. * US Government Users Restricted Rights - Use, duplication or
  13. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  14. */
  15. package com.sun.corba.se.internal.util;
  16. import java.util.Dictionary;
  17. import java.util.Enumeration;
  18. import java.util.NoSuchElementException;
  19. /**
  20. * IdentityHashtable collision list.
  21. */
  22. class IdentityHashtableEntry {
  23. int hash;
  24. Object key;
  25. Object value;
  26. IdentityHashtableEntry next;
  27. }
  28. /**
  29. * IdentityHashtable is a modified copy of the 1.1.6 Hashtable class which
  30. * does not rely on the hashCode() and equals() methods of the key or value;
  31. * instead, it uses the System.identityHashcode() method and pointer comparison.
  32. * In addition, all synchronization has been removed.
  33. */
  34. public final class IdentityHashtable extends Dictionary {
  35. /**
  36. * The hash table data.
  37. */
  38. private transient IdentityHashtableEntry table[];
  39. /**
  40. * The total number of entries in the hash table.
  41. */
  42. private transient int count;
  43. /**
  44. * Rehashes the table when count exceeds this threshold.
  45. */
  46. private int threshold;
  47. /**
  48. * The load factor for the hashtable.
  49. */
  50. private float loadFactor;
  51. /**
  52. * Constructs a new, empty hashtable with the specified initial
  53. * capacity and the specified load factor.
  54. *
  55. * @param initialCapacity the initial capacity of the hashtable.
  56. * @param loadFactor a number between 0.0 and 1.0.
  57. * @exception IllegalArgumentException if the initial capacity is less
  58. * than or equal to zero, or if the load factor is less than
  59. * or equal to zero.
  60. * @since JDK1.0
  61. */
  62. public IdentityHashtable(int initialCapacity, float loadFactor) {
  63. if ((initialCapacity <= 0) || (loadFactor <= 0.0)) {
  64. throw new IllegalArgumentException();
  65. }
  66. this.loadFactor = loadFactor;
  67. table = new IdentityHashtableEntry[initialCapacity];
  68. threshold = (int)(initialCapacity * loadFactor);
  69. }
  70. /**
  71. * Constructs a new, empty hashtable with the specified initial capacity
  72. * and default load factor.
  73. *
  74. * @param initialCapacity the initial capacity of the hashtable.
  75. * @since JDK1.0
  76. */
  77. public IdentityHashtable(int initialCapacity) {
  78. this(initialCapacity, 0.75f);
  79. }
  80. /**
  81. * Constructs a new, empty hashtable with a default capacity and load
  82. * factor.
  83. *
  84. * @since JDK1.0
  85. */
  86. public IdentityHashtable() {
  87. this(101, 0.75f);
  88. }
  89. /**
  90. * Returns the number of keys in this hashtable.
  91. *
  92. * @return the number of keys in this hashtable.
  93. * @since JDK1.0
  94. */
  95. public int size() {
  96. return count;
  97. }
  98. /**
  99. * Tests if this hashtable maps no keys to values.
  100. *
  101. * @return <code>true</code> if this hashtable maps no keys to values;
  102. * <code>false</code> otherwise.
  103. * @since JDK1.0
  104. */
  105. public boolean isEmpty() {
  106. return count == 0;
  107. }
  108. /**
  109. * Returns an enumeration of the keys in this hashtable.
  110. *
  111. * @return an enumeration of the keys in this hashtable.
  112. * @see java.util.Enumeration
  113. * @see java.util.Hashtable#elements()
  114. * @since JDK1.0
  115. */
  116. public Enumeration keys() {
  117. return new IdentityHashtableEnumerator(table, true);
  118. }
  119. /**
  120. * Returns an enumeration of the values in this hashtable.
  121. * Use the Enumeration methods on the returned object to fetch the elements
  122. * sequentially.
  123. *
  124. * @return an enumeration of the values in this hashtable.
  125. * @see java.util.Enumeration
  126. * @see java.util.Hashtable#keys()
  127. * @since JDK1.0
  128. */
  129. public Enumeration elements() {
  130. return new IdentityHashtableEnumerator(table, false);
  131. }
  132. /**
  133. * Tests if some key maps into the specified value in this hashtable.
  134. * This operation is more expensive than the <code>containsKey</code>
  135. * method.
  136. *
  137. * @param value a value to search for.
  138. * @return <code>true</code> if some key maps to the
  139. * <code>value</code> argument in this hashtable;
  140. * <code>false</code> otherwise.
  141. * @exception NullPointerException if the value is <code>null</code>.
  142. * @see java.util.Hashtable#containsKey(java.lang.Object)
  143. * @since JDK1.0
  144. */
  145. public boolean contains(Object value) {
  146. if (value == null) {
  147. throw new NullPointerException();
  148. }
  149. IdentityHashtableEntry tab[] = table;
  150. for (int i = tab.length ; i-- > 0 ;) {
  151. for (IdentityHashtableEntry e = tab[i] ; e != null ; e = e.next) {
  152. if (e.value == value) {
  153. return true;
  154. }
  155. }
  156. }
  157. return false;
  158. }
  159. /**
  160. * Tests if the specified object is a key in this hashtable.
  161. *
  162. * @param key possible key.
  163. * @return <code>true</code> if the specified object is a key in this
  164. * hashtable; <code>false</code> otherwise.
  165. * @see java.util.Hashtable#contains(java.lang.Object)
  166. * @since JDK1.0
  167. */
  168. public boolean containsKey(Object key) {
  169. IdentityHashtableEntry tab[] = table;
  170. int hash = System.identityHashCode(key);
  171. int index = (hash & 0x7FFFFFFF) % tab.length;
  172. for (IdentityHashtableEntry e = tab[index] ; e != null ; e = e.next) {
  173. if ((e.hash == hash) && e.key == key) {
  174. return true;
  175. }
  176. }
  177. return false;
  178. }
  179. /**
  180. * Returns the value to which the specified key is mapped in this hashtable.
  181. *
  182. * @param key a key in the hashtable.
  183. * @return the value to which the key is mapped in this hashtable;
  184. * <code>null</code> if the key is not mapped to any value in
  185. * this hashtable.
  186. * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object)
  187. * @since JDK1.0
  188. */
  189. public Object get(Object key) {
  190. IdentityHashtableEntry tab[] = table;
  191. int hash = System.identityHashCode(key);
  192. int index = (hash & 0x7FFFFFFF) % tab.length;
  193. for (IdentityHashtableEntry e = tab[index] ; e != null ; e = e.next) {
  194. if ((e.hash == hash) && e.key == key) {
  195. return e.value;
  196. }
  197. }
  198. return null;
  199. }
  200. /**
  201. * Rehashes the contents of the hashtable into a hashtable with a
  202. * larger capacity. This method is called automatically when the
  203. * number of keys in the hashtable exceeds this hashtable's capacity
  204. * and load factor.
  205. *
  206. * @since JDK1.0
  207. */
  208. protected void rehash() {
  209. int oldCapacity = table.length;
  210. IdentityHashtableEntry oldTable[] = table;
  211. int newCapacity = oldCapacity * 2 + 1;
  212. IdentityHashtableEntry newTable[] = new IdentityHashtableEntry[newCapacity];
  213. threshold = (int)(newCapacity * loadFactor);
  214. table = newTable;
  215. //System.out.println("rehash old=" + oldCapacity + ", new=" + newCapacity + ", thresh=" + threshold + ", count=" + count);
  216. for (int i = oldCapacity ; i-- > 0 ;) {
  217. for (IdentityHashtableEntry old = oldTable[i] ; old != null ; ) {
  218. IdentityHashtableEntry e = old;
  219. old = old.next;
  220. int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  221. e.next = newTable[index];
  222. newTable[index] = e;
  223. }
  224. }
  225. }
  226. /**
  227. * Maps the specified <code>key</code> to the specified
  228. * <code>value</code> in this hashtable. Neither the key nor the
  229. * value can be <code>null</code>.
  230. * <p>
  231. * The value can be retrieved by calling the <code>get</code> method
  232. * with a key that is equal to the original key.
  233. *
  234. * @param key the hashtable key.
  235. * @param value the value.
  236. * @return the previous value of the specified key in this hashtable,
  237. * or <code>null</code> if it did not have one.
  238. * @exception NullPointerException if the key or value is
  239. * <code>null</code>.
  240. * @see java.util.Hashtable#get(java.lang.Object)
  241. * @since JDK1.0
  242. */
  243. public Object put(Object key, Object value) {
  244. // Make sure the value is not null
  245. if (value == null) {
  246. throw new NullPointerException();
  247. }
  248. // Makes sure the key is not already in the hashtable.
  249. IdentityHashtableEntry tab[] = table;
  250. int hash = System.identityHashCode(key);
  251. int index = (hash & 0x7FFFFFFF) % tab.length;
  252. for (IdentityHashtableEntry e = tab[index] ; e != null ; e = e.next) {
  253. if ((e.hash == hash) && e.key == key) {
  254. Object old = e.value;
  255. e.value = value;
  256. return old;
  257. }
  258. }
  259. if (count >= threshold) {
  260. // Rehash the table if the threshold is exceeded
  261. rehash();
  262. return put(key, value);
  263. }
  264. // Creates the new entry.
  265. IdentityHashtableEntry e = new IdentityHashtableEntry();
  266. e.hash = hash;
  267. e.key = key;
  268. e.value = value;
  269. e.next = tab[index];
  270. tab[index] = e;
  271. count++;
  272. return null;
  273. }
  274. /**
  275. * Removes the key (and its corresponding value) from this
  276. * hashtable. This method does nothing if the key is not in the hashtable.
  277. *
  278. * @param key the key that needs to be removed.
  279. * @return the value to which the key had been mapped in this hashtable,
  280. * or <code>null</code> if the key did not have a mapping.
  281. * @since JDK1.0
  282. */
  283. public Object remove(Object key) {
  284. IdentityHashtableEntry tab[] = table;
  285. int hash = System.identityHashCode(key);
  286. int index = (hash & 0x7FFFFFFF) % tab.length;
  287. for (IdentityHashtableEntry e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
  288. if ((e.hash == hash) && e.key == key) {
  289. if (prev != null) {
  290. prev.next = e.next;
  291. } else {
  292. tab[index] = e.next;
  293. }
  294. count--;
  295. return e.value;
  296. }
  297. }
  298. return null;
  299. }
  300. /**
  301. * Clears this hashtable so that it contains no keys.
  302. *
  303. * @since JDK1.0
  304. */
  305. public void clear() {
  306. IdentityHashtableEntry tab[] = table;
  307. for (int index = tab.length; --index >= 0; )
  308. tab[index] = null;
  309. count = 0;
  310. }
  311. /**
  312. * Returns a rather long string representation of this hashtable.
  313. *
  314. * @return a string representation of this hashtable.
  315. * @since JDK1.0
  316. */
  317. public String toString() {
  318. int max = size() - 1;
  319. StringBuffer buf = new StringBuffer();
  320. Enumeration k = keys();
  321. Enumeration e = elements();
  322. buf.append("{");
  323. for (int i = 0; i <= max; i++) {
  324. String s1 = k.nextElement().toString();
  325. String s2 = e.nextElement().toString();
  326. buf.append(s1 + "=" + s2);
  327. if (i < max) {
  328. buf.append(", ");
  329. }
  330. }
  331. buf.append("}");
  332. return buf.toString();
  333. }
  334. }
  335. /**
  336. * A hashtable enumerator class. This class should remain opaque
  337. * to the client. It will use the Enumeration interface.
  338. */
  339. class IdentityHashtableEnumerator implements Enumeration {
  340. boolean keys;
  341. int index;
  342. IdentityHashtableEntry table[];
  343. IdentityHashtableEntry entry;
  344. IdentityHashtableEnumerator(IdentityHashtableEntry table[], boolean keys) {
  345. this.table = table;
  346. this.keys = keys;
  347. this.index = table.length;
  348. }
  349. public boolean hasMoreElements() {
  350. if (entry != null) {
  351. return true;
  352. }
  353. while (index-- > 0) {
  354. if ((entry = table[index]) != null) {
  355. return true;
  356. }
  357. }
  358. return false;
  359. }
  360. public Object nextElement() {
  361. if (entry == null) {
  362. while ((index-- > 0) && ((entry = table[index]) == null));
  363. }
  364. if (entry != null) {
  365. IdentityHashtableEntry e = entry;
  366. entry = e.next;
  367. return keys ? e.key : e.value;
  368. }
  369. throw new NoSuchElementException("IdentityHashtableEnumerator");
  370. }
  371. }