1. /*
  2. * $Id: SimpleHashtable.java,v 1.1.1.1 2000/11/23 01:53:33 edwingo Exp $
  3. *
  4. * The Apache Software License, Version 1.1
  5. *
  6. *
  7. * Copyright (c) 2000 The Apache Software Foundation. All rights
  8. * reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. *
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in
  19. * the documentation and/or other materials provided with the
  20. * distribution.
  21. *
  22. * 3. The end-user documentation included with the redistribution,
  23. * if any, must include the following acknowledgment:
  24. * "This product includes software developed by the
  25. * Apache Software Foundation (http://www.apache.org/)."
  26. * Alternately, this acknowledgment may appear in the software itself,
  27. * if and wherever such third-party acknowledgments normally appear.
  28. *
  29. * 4. The names "Crimson" and "Apache Software Foundation" must
  30. * not be used to endorse or promote products derived from this
  31. * software without prior written permission. For written
  32. * permission, please contact apache@apache.org.
  33. *
  34. * 5. Products derived from this software may not be called "Apache",
  35. * nor may "Apache" appear in their name, without prior written
  36. * permission of the Apache Software Foundation.
  37. *
  38. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  39. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  40. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  41. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  42. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  43. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  44. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  45. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  46. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  47. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  48. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  49. * SUCH DAMAGE.
  50. * ====================================================================
  51. *
  52. * This software consists of voluntary contributions made by many
  53. * individuals on behalf of the Apache Software Foundation and was
  54. * originally based on software copyright (c) 1999, Sun Microsystems, Inc.,
  55. * http://www.sun.com. For more information on the Apache Software
  56. * Foundation, please see <http://www.apache.org/>.
  57. */
  58. package org.apache.crimson.parser;
  59. import java.util.Enumeration;
  60. // can't be replaced using a Java 2 "Collections" API
  61. // since this package must also run on JDK 1.1
  62. /**
  63. * This class implements a special purpose hashtable. It works like a
  64. * normal <code>java.util.Hashtable</code> except that: <OL>
  65. *
  66. * <LI> Keys to "get" are strings which are known to be interned,
  67. * so that "==" is used instead of "String.equals". (Interning
  68. * could be document-relative instead of global.)
  69. *
  70. * <LI> It's not synchronized, since it's to be used only by
  71. * one thread at a time.
  72. *
  73. * <LI> The keys () enumerator allocates no memory, with live
  74. * updates to the data disallowed.
  75. *
  76. * <LI> It's got fewer bells and whistles: fixed threshold and
  77. * load factor, no JDK 1.2 collection support, only keys can be
  78. * enumerated, things can't be removed, simpler inheritance; more.
  79. *
  80. * </OL>
  81. *
  82. * <P> The overall result is that it's less expensive to use these in
  83. * performance-critical locations, in terms both of CPU and memory,
  84. * than <code>java.util.Hashtable</code> instances. In this package
  85. * it makes a significant difference when normalizing attributes,
  86. * which is done for each start-element construct.
  87. *
  88. * @version $Revision: 1.1.1.1 $
  89. */
  90. final class SimpleHashtable implements Enumeration
  91. {
  92. // entries ...
  93. private Entry table[];
  94. // currently enumerated key
  95. private Entry current = null;
  96. private int currentBucket = 0;
  97. private int count;
  98. private int threshold;
  99. private static final float loadFactor = 0.75f;
  100. /**
  101. * Constructs a new, empty hashtable with the specified initial
  102. * capacity.
  103. *
  104. * @param initialCapacity the initial capacity of the hashtable.
  105. */
  106. public SimpleHashtable(int initialCapacity) {
  107. if (initialCapacity < 0)
  108. throw new IllegalArgumentException("Illegal Capacity: "+
  109. initialCapacity);
  110. if (initialCapacity==0)
  111. initialCapacity = 1;
  112. table = new Entry[initialCapacity];
  113. threshold = (int)(initialCapacity * loadFactor);
  114. }
  115. /**
  116. * Constructs a new, empty hashtable with a default capacity.
  117. */
  118. public SimpleHashtable() {
  119. this(11);
  120. }
  121. /**
  122. */
  123. public void clear ()
  124. {
  125. count = 0;
  126. currentBucket = 0;
  127. current = null;
  128. for (int i = 0; i < table.length; i++)
  129. table [i] = null;
  130. }
  131. /**
  132. * Returns the number of keys in this hashtable.
  133. *
  134. * @return the number of keys in this hashtable.
  135. */
  136. public int size() {
  137. return count;
  138. }
  139. /**
  140. * Returns an enumeration of the keys in this hashtable.
  141. *
  142. * @return an enumeration of the keys in this hashtable.
  143. * @see Enumeration
  144. */
  145. public Enumeration keys() {
  146. currentBucket = 0;
  147. current = null;
  148. return this;
  149. }
  150. /**
  151. * Used to view this as an enumeration; returns true if there
  152. * are more keys to be enumerated.
  153. */
  154. public boolean hasMoreElements ()
  155. {
  156. if (current != null)
  157. return true;
  158. while (currentBucket < table.length) {
  159. current = table [currentBucket++];
  160. if (current != null)
  161. return true;
  162. }
  163. return false;
  164. }
  165. /**
  166. * Used to view this as an enumeration; returns the next key
  167. * in the enumeration.
  168. */
  169. public Object nextElement ()
  170. {
  171. Object retval;
  172. if (current == null)
  173. throw new IllegalStateException ();
  174. retval = current.key;
  175. current = current.next;
  176. return retval;
  177. }
  178. /**
  179. * Returns the value to which the specified key is mapped in this hashtable.
  180. */
  181. public Object get (String key) {
  182. Entry tab[] = table;
  183. int hash = key.hashCode();
  184. int index = (hash & 0x7FFFFFFF) % tab.length;
  185. for (Entry e = tab[index] ; e != null ; e = e.next) {
  186. if ((e.hash == hash) && (e.key == key))
  187. return e.value;
  188. }
  189. return null;
  190. }
  191. /**
  192. * Returns the value to which the specified key is mapped in this
  193. * hashtable ... the key isn't necessarily interned, though.
  194. */
  195. public Object getNonInterned (String key) {
  196. Entry tab[] = table;
  197. int hash = key.hashCode();
  198. int index = (hash & 0x7FFFFFFF) % tab.length;
  199. for (Entry e = tab[index] ; e != null ; e = e.next) {
  200. if ((e.hash == hash) && e.key.equals(key))
  201. return e.value;
  202. }
  203. return null;
  204. }
  205. /**
  206. * Increases the capacity of and internally reorganizes this
  207. * hashtable, in order to accommodate and access its entries more
  208. * efficiently. This method is called automatically when the
  209. * number of keys in the hashtable exceeds this hashtable's capacity
  210. * and load factor.
  211. */
  212. private void rehash() {
  213. int oldCapacity = table.length;
  214. Entry oldMap[] = table;
  215. int newCapacity = oldCapacity * 2 + 1;
  216. Entry newMap[] = new Entry[newCapacity];
  217. threshold = (int)(newCapacity * loadFactor);
  218. table = newMap;
  219. /*
  220. System.out.println("rehash old=" + oldCapacity
  221. + ", new=" + newCapacity
  222. + ", thresh=" + threshold
  223. + ", count=" + count);
  224. */
  225. for (int i = oldCapacity ; i-- > 0 ;) {
  226. for (Entry old = oldMap[i] ; old != null ; ) {
  227. Entry e = old;
  228. old = old.next;
  229. int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  230. e.next = newMap[index];
  231. newMap[index] = e;
  232. }
  233. }
  234. }
  235. /**
  236. * Maps the specified <code>key</code> to the specified
  237. * <code>value</code> in this hashtable. Neither the key nor the
  238. * value can be <code>null</code>.
  239. *
  240. * <P>The value can be retrieved by calling the <code>get</code> method
  241. * with a key that is equal to the original key.
  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. Entry tab[] = table;
  250. int hash = key.hashCode();
  251. int index = (hash & 0x7FFFFFFF) % tab.length;
  252. for (Entry e = tab[index] ; e != null ; e = e.next) {
  253. // if ((e.hash == hash) && e.key.equals(key)) {
  254. if ((e.hash == hash) && (e.key == key)) {
  255. Object old = e.value;
  256. e.value = value;
  257. return old;
  258. }
  259. }
  260. if (count >= threshold) {
  261. // Rehash the table if the threshold is exceeded
  262. rehash();
  263. tab = table;
  264. index = (hash & 0x7FFFFFFF) % tab.length;
  265. }
  266. // Creates the new entry.
  267. Entry e = new Entry(hash, key, value, tab[index]);
  268. tab[index] = e;
  269. count++;
  270. return null;
  271. }
  272. /**
  273. * Hashtable collision list.
  274. */
  275. private static class Entry {
  276. int hash;
  277. Object key;
  278. Object value;
  279. Entry next;
  280. protected Entry(int hash, Object key, Object value, Entry next) {
  281. this.hash = hash;
  282. this.key = key;
  283. this.value = value;
  284. this.next = next;
  285. }
  286. }
  287. }