src/share/jaxws_classes/com/sun/xml/internal/dtdparser/SimpleHashtable.java

changeset 286
f50545b5e2f1
child 397
b99d7e355d4b
equal deleted inserted replaced
284:88b85470e72c 286:f50545b5e2f1
1 /*
2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.xml.internal.dtdparser;
27
28 import java.util.Enumeration;
29
30
31 // This could be replaced by Collections class unless we want
32 // to be able to run on JDK 1.1
33
34
35 /**
36 * This class implements a special purpose hashtable. It works like a
37 * normal <code>java.util.Hashtable</code> except that: <OL>
38 * <p/>
39 * <LI> Keys to "get" are strings which are known to be interned,
40 * so that "==" is used instead of "String.equals". (Interning
41 * could be document-relative instead of global.)
42 * <p/>
43 * <LI> It's not synchronized, since it's to be used only by
44 * one thread at a time.
45 * <p/>
46 * <LI> The keys () enumerator allocates no memory, with live
47 * updates to the data disallowed.
48 * <p/>
49 * <LI> It's got fewer bells and whistles: fixed threshold and
50 * load factor, no JDK 1.2 collection support, only keys can be
51 * enumerated, things can't be removed, simpler inheritance; more.
52 * <p/>
53 * </OL>
54 * <p/>
55 * <P> The overall result is that it's less expensive to use these in
56 * performance-critical locations, in terms both of CPU and memory,
57 * than <code>java.util.Hashtable</code> instances. In this package
58 * it makes a significant difference when normalizing attributes,
59 * which is done for each start-element construct.
60 *
61 * @version $Revision: 1.2 $
62 */
63 final class SimpleHashtable implements Enumeration {
64 // entries ...
65 private Entry table[];
66
67 // currently enumerated key
68 private Entry current = null;
69 private int currentBucket = 0;
70
71 private int count;
72 private int threshold;
73
74 private static final float loadFactor = 0.75f;
75
76
77 /**
78 * Constructs a new, empty hashtable with the specified initial
79 * capacity.
80 *
81 * @param initialCapacity the initial capacity of the hashtable.
82 */
83 public SimpleHashtable(int initialCapacity) {
84 if (initialCapacity < 0)
85 throw new IllegalArgumentException("Illegal Capacity: " +
86 initialCapacity);
87 if (initialCapacity == 0)
88 initialCapacity = 1;
89 table = new Entry[initialCapacity];
90 threshold = (int) (initialCapacity * loadFactor);
91 }
92
93 /**
94 * Constructs a new, empty hashtable with a default capacity.
95 */
96 public SimpleHashtable() {
97 this(11);
98 }
99
100 /**
101 */
102 public void clear() {
103 count = 0;
104 currentBucket = 0;
105 current = null;
106 for (int i = 0; i < table.length; i++)
107 table[i] = null;
108 }
109
110 /**
111 * Returns the number of keys in this hashtable.
112 *
113 * @return the number of keys in this hashtable.
114 */
115 public int size() {
116 return count;
117 }
118
119 /**
120 * Returns an enumeration of the keys in this hashtable.
121 *
122 * @return an enumeration of the keys in this hashtable.
123 * @see Enumeration
124 */
125 public Enumeration keys() {
126 currentBucket = 0;
127 current = null;
128 return this;
129 }
130
131 /**
132 * Used to view this as an enumeration; returns true if there
133 * are more keys to be enumerated.
134 */
135 public boolean hasMoreElements() {
136 if (current != null)
137 return true;
138 while (currentBucket < table.length) {
139 current = table[currentBucket++];
140 if (current != null)
141 return true;
142 }
143 return false;
144 }
145
146 /**
147 * Used to view this as an enumeration; returns the next key
148 * in the enumeration.
149 */
150 public Object nextElement() {
151 Object retval;
152
153 if (current == null)
154 throw new IllegalStateException();
155 retval = current.key;
156 current = current.next;
157 return retval;
158 }
159
160
161 /**
162 * Returns the value to which the specified key is mapped in this hashtable.
163 */
164 public Object get(String key) {
165 Entry tab[] = table;
166 int hash = key.hashCode();
167 int index = (hash & 0x7FFFFFFF) % tab.length;
168 for (Entry e = tab[index]; e != null; e = e.next) {
169 if ((e.hash == hash) && (e.key == key))
170 return e.value;
171 }
172 return null;
173 }
174
175 /**
176 * Returns the value to which the specified key is mapped in this
177 * hashtable ... the key isn't necessarily interned, though.
178 */
179 public Object getNonInterned(String key) {
180 Entry tab[] = table;
181 int hash = key.hashCode();
182 int index = (hash & 0x7FFFFFFF) % tab.length;
183 for (Entry e = tab[index]; e != null; e = e.next) {
184 if ((e.hash == hash) && e.key.equals(key))
185 return e.value;
186 }
187 return null;
188 }
189
190 /**
191 * Increases the capacity of and internally reorganizes this
192 * hashtable, in order to accommodate and access its entries more
193 * efficiently. This method is called automatically when the
194 * number of keys in the hashtable exceeds this hashtable's capacity
195 * and load factor.
196 */
197 private void rehash() {
198 int oldCapacity = table.length;
199 Entry oldMap[] = table;
200
201 int newCapacity = oldCapacity * 2 + 1;
202 Entry newMap[] = new Entry[newCapacity];
203
204 threshold = (int) (newCapacity * loadFactor);
205 table = newMap;
206
207 /*
208 System.out.println("rehash old=" + oldCapacity
209 + ", new=" + newCapacity
210 + ", thresh=" + threshold
211 + ", count=" + count);
212 */
213
214 for (int i = oldCapacity; i-- > 0;) {
215 for (Entry old = oldMap[i]; old != null;) {
216 Entry e = old;
217 old = old.next;
218
219 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
220 e.next = newMap[index];
221 newMap[index] = e;
222 }
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 * <P>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 public Object put(Object key, Object value) {
235 // Make sure the value is not null
236 if (value == null) {
237 throw new NullPointerException();
238 }
239
240 // Makes sure the key is not already in the hashtable.
241 Entry tab[] = table;
242 int hash = key.hashCode();
243 int index = (hash & 0x7FFFFFFF) % tab.length;
244 for (Entry e = tab[index]; e != null; e = e.next) {
245 // if ((e.hash == hash) && e.key.equals(key)) {
246 if ((e.hash == hash) && (e.key == key)) {
247 Object old = e.value;
248 e.value = value;
249 return old;
250 }
251 }
252
253 if (count >= threshold) {
254 // Rehash the table if the threshold is exceeded
255 rehash();
256
257 tab = table;
258 index = (hash & 0x7FFFFFFF) % tab.length;
259 }
260
261 // Creates the new entry.
262 Entry e = new Entry(hash, key, value, tab[index]);
263 tab[index] = e;
264 count++;
265 return null;
266 }
267
268
269 /**
270 * Hashtable collision list.
271 */
272 private static class Entry {
273 int hash;
274 Object key;
275 Object value;
276 Entry next;
277
278 protected Entry(int hash, Object key, Object value, Entry next) {
279 this.hash = hash;
280 this.key = key;
281 this.value = value;
282 this.next = next;
283 }
284 }
285 }

mercurial