1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: Hashtable.java,v 1.4 2004/02/16 22:55:54 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.runtime;
  20. import java.util.Enumeration;
  21. /**
  22. * IMPORTANT NOTE:
  23. * This code was taken from Sun's Java1.1 JDK java.util.HashTable.java
  24. * All "synchronized" keywords and some methods we do not need have been
  25. * all been removed.
  26. */
  27. /**
  28. * Object that wraps entries in the hash-table
  29. * @author Morten Jorgensen
  30. */
  31. class HashtableEntry {
  32. int hash;
  33. Object key;
  34. Object value;
  35. HashtableEntry next;
  36. protected Object clone() {
  37. HashtableEntry entry = new HashtableEntry();
  38. entry.hash = hash;
  39. entry.key = key;
  40. entry.value = value;
  41. entry.next = (next != null) ? (HashtableEntry)next.clone() : null;
  42. return entry;
  43. }
  44. }
  45. /**
  46. * The main hash-table implementation
  47. */
  48. public class Hashtable {
  49. private transient HashtableEntry table[]; // hash-table entries
  50. private transient int count; // number of entries
  51. private int threshold; // current size of hash-tabke
  52. private float loadFactor; // load factor
  53. /**
  54. * Constructs a new, empty hashtable with the specified initial
  55. * capacity and the specified load factor.
  56. */
  57. public Hashtable(int initialCapacity, float loadFactor) {
  58. if (initialCapacity <= 0) initialCapacity = 11;
  59. if (loadFactor <= 0.0) loadFactor = 0.75f;
  60. this.loadFactor = loadFactor;
  61. table = new HashtableEntry[initialCapacity];
  62. threshold = (int)(initialCapacity * loadFactor);
  63. }
  64. /**
  65. * Constructs a new, empty hashtable with the specified initial capacity
  66. * and default load factor.
  67. */
  68. public Hashtable(int initialCapacity) {
  69. this(initialCapacity, 0.75f);
  70. }
  71. /**
  72. * Constructs a new, empty hashtable with a default capacity and load
  73. * factor.
  74. */
  75. public Hashtable() {
  76. this(101, 0.75f);
  77. }
  78. /**
  79. * Returns the number of keys in this hashtable.
  80. */
  81. public int size() {
  82. return count;
  83. }
  84. /**
  85. * Tests if this hashtable maps no keys to values.
  86. */
  87. public boolean isEmpty() {
  88. return count == 0;
  89. }
  90. /**
  91. * Returns an enumeration of the keys in this hashtable.
  92. */
  93. public Enumeration keys() {
  94. return new HashtableEnumerator(table, true);
  95. }
  96. /**
  97. * Returns an enumeration of the values in this hashtable.
  98. * Use the Enumeration methods on the returned object to fetch the elements
  99. * sequentially.
  100. */
  101. public Enumeration elements() {
  102. return new HashtableEnumerator(table, false);
  103. }
  104. /**
  105. * Tests if some key maps into the specified value in this hashtable.
  106. * This operation is more expensive than the <code>containsKey</code>
  107. * method.
  108. */
  109. public boolean contains(Object value) {
  110. if (value == null) throw new NullPointerException();
  111. int i;
  112. HashtableEntry e;
  113. HashtableEntry tab[] = table;
  114. for (i = tab.length ; i-- > 0 ;) {
  115. for (e = tab[i] ; e != null ; e = e.next) {
  116. if (e.value.equals(value)) {
  117. return true;
  118. }
  119. }
  120. }
  121. return false;
  122. }
  123. /**
  124. * Tests if the specified object is a key in this hashtable.
  125. */
  126. public boolean containsKey(Object key) {
  127. HashtableEntry e;
  128. HashtableEntry tab[] = table;
  129. int hash = key.hashCode();
  130. int index = (hash & 0x7FFFFFFF) % tab.length;
  131. for (e = tab[index] ; e != null ; e = e.next)
  132. if ((e.hash == hash) && e.key.equals(key))
  133. return true;
  134. return false;
  135. }
  136. /**
  137. * Returns the value to which the specified key is mapped in this hashtable.
  138. */
  139. public Object get(Object key) {
  140. HashtableEntry e;
  141. HashtableEntry tab[] = table;
  142. int hash = key.hashCode();
  143. int index = (hash & 0x7FFFFFFF) % tab.length;
  144. for (e = tab[index] ; e != null ; e = e.next)
  145. if ((e.hash == hash) && e.key.equals(key))
  146. return e.value;
  147. return null;
  148. }
  149. /**
  150. * Rehashes the contents of the hashtable into a hashtable with a
  151. * larger capacity. This method is called automatically when the
  152. * number of keys in the hashtable exceeds this hashtable's capacity
  153. * and load factor.
  154. */
  155. protected void rehash() {
  156. HashtableEntry e, old;
  157. int i, index;
  158. int oldCapacity = table.length;
  159. HashtableEntry oldTable[] = table;
  160. int newCapacity = oldCapacity * 2 + 1;
  161. HashtableEntry newTable[] = new HashtableEntry[newCapacity];
  162. threshold = (int)(newCapacity * loadFactor);
  163. table = newTable;
  164. for (i = oldCapacity ; i-- > 0 ;) {
  165. for (old = oldTable[i] ; old != null ; ) {
  166. e = old;
  167. old = old.next;
  168. index = (e.hash & 0x7FFFFFFF) % newCapacity;
  169. e.next = newTable[index];
  170. newTable[index] = e;
  171. }
  172. }
  173. }
  174. /**
  175. * Maps the specified <code>key</code> to the specified
  176. * <code>value</code> in this hashtable. Neither the key nor the
  177. * value can be <code>null</code>.
  178. * <p>
  179. * The value can be retrieved by calling the <code>get</code> method
  180. * with a key that is equal to the original key.
  181. */
  182. public Object put(Object key, Object value) {
  183. // Make sure the value is not null
  184. if (value == null) throw new NullPointerException();
  185. // Makes sure the key is not already in the hashtable.
  186. HashtableEntry e;
  187. HashtableEntry tab[] = table;
  188. int hash = key.hashCode();
  189. int index = (hash & 0x7FFFFFFF) % tab.length;
  190. for (e = tab[index] ; e != null ; e = e.next) {
  191. if ((e.hash == hash) && e.key.equals(key)) {
  192. Object old = e.value;
  193. e.value = value;
  194. return old;
  195. }
  196. }
  197. // Rehash the table if the threshold is exceeded
  198. if (count >= threshold) {
  199. rehash();
  200. return put(key, value);
  201. }
  202. // Creates the new entry.
  203. e = new HashtableEntry();
  204. e.hash = hash;
  205. e.key = key;
  206. e.value = value;
  207. e.next = tab[index];
  208. tab[index] = e;
  209. count++;
  210. return null;
  211. }
  212. /**
  213. * Removes the key (and its corresponding value) from this
  214. * hashtable. This method does nothing if the key is not in the hashtable.
  215. */
  216. public Object remove(Object key) {
  217. HashtableEntry e, prev;
  218. HashtableEntry tab[] = table;
  219. int hash = key.hashCode();
  220. int index = (hash & 0x7FFFFFFF) % tab.length;
  221. for (e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
  222. if ((e.hash == hash) && e.key.equals(key)) {
  223. if (prev != null)
  224. prev.next = e.next;
  225. else
  226. tab[index] = e.next;
  227. count--;
  228. return e.value;
  229. }
  230. }
  231. return null;
  232. }
  233. /**
  234. * Clears this hashtable so that it contains no keys.
  235. */
  236. public void clear() {
  237. HashtableEntry tab[] = table;
  238. for (int index = tab.length; --index >= 0; )
  239. tab[index] = null;
  240. count = 0;
  241. }
  242. /**
  243. * Returns a rather long string representation of this hashtable.
  244. * Handy for debugging - leave it here!!!
  245. */
  246. public String toString() {
  247. int i;
  248. int max = size() - 1;
  249. StringBuffer buf = new StringBuffer();
  250. Enumeration k = keys();
  251. Enumeration e = elements();
  252. buf.append("{");
  253. for (i = 0; i <= max; i++) {
  254. String s1 = k.nextElement().toString();
  255. String s2 = e.nextElement().toString();
  256. buf.append(s1 + "=" + s2);
  257. if (i < max) buf.append(", ");
  258. }
  259. buf.append("}");
  260. return buf.toString();
  261. }
  262. /**
  263. * A hashtable enumerator class. This class should remain opaque
  264. * to the client. It will use the Enumeration interface.
  265. */
  266. class HashtableEnumerator implements Enumeration {
  267. boolean keys;
  268. int index;
  269. HashtableEntry table[];
  270. HashtableEntry entry;
  271. HashtableEnumerator(HashtableEntry table[], boolean keys) {
  272. this.table = table;
  273. this.keys = keys;
  274. this.index = table.length;
  275. }
  276. public boolean hasMoreElements() {
  277. if (entry != null) {
  278. return true;
  279. }
  280. while (index-- > 0) {
  281. if ((entry = table[index]) != null) {
  282. return true;
  283. }
  284. }
  285. return false;
  286. }
  287. public Object nextElement() {
  288. if (entry == null) {
  289. while ((index-- > 0) && ((entry = table[index]) == null));
  290. }
  291. if (entry != null) {
  292. HashtableEntry e = entry;
  293. entry = e.next;
  294. return keys ? e.key : e.value;
  295. }
  296. return null;
  297. }
  298. }
  299. }