comparison agent/src/share/classes/sun/jvm/hotspot/debugger/LongHashMap.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2002 Sun Microsystems, Inc. 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 package sun.jvm.hotspot.debugger;
26
27 import java.util.*;
28
29 /**
30 * This is a copy of java.util.HashMap which uses longs as keys
31 * instead of Objects. It turns out that using this in the PageCache
32 * implementation speeds up heap traversals by a factor of three.
33 *
34 * @author Josh Bloch
35 * @author Arthur van Hoff
36 */
37
38 public class LongHashMap
39 {
40 static class Entry {
41 private int hash;
42 private long key;
43 private Object value;
44 private Entry next;
45
46 Entry(int hash, long key, Object value, Entry next) {
47 this.hash = hash;
48 this.key = key;
49 this.value = value;
50 this.next = next;
51 }
52
53 /**
54 * Returns the key corresponding to this entry.
55 *
56 * @return the key corresponding to this entry.
57 */
58 long getKey() { return key; }
59
60 /**
61 * Returns the value corresponding to this entry. If the mapping
62 * has been removed from the backing map (by the iterator's
63 * <tt>remove</tt> operation), the results of this call are undefined.
64 *
65 * @return the value corresponding to this entry.
66 */
67 Object getValue() { return value; }
68
69 /**
70 * Replaces the value corresponding to this entry with the specified
71 * value (optional operation). (Writes through to the map.) The
72 * behavior of this call is undefined if the mapping has already been
73 * removed from the map (by the iterator's <tt>remove</tt> operation).
74 *
75 * @param value new value to be stored in this entry.
76 * @return old value corresponding to the entry.
77 *
78 * @throws UnsupportedOperationException if the <tt>put</tt> operation
79 * is not supported by the backing map.
80 * @throws ClassCastException if the class of the specified value
81 * prevents it from being stored in the backing map.
82 * @throws IllegalArgumentException if some aspect of this value
83 * prevents it from being stored in the backing map.
84 * @throws NullPointerException the backing map does not permit
85 * <tt>null</tt> values, and the specified value is
86 * <tt>null</tt>.
87 */
88 Object setValue(Object value) {
89 Object oldValue = this.value;
90 this.value = value;
91 return oldValue;
92 }
93
94 /**
95 * Compares the specified object with this entry for equality.
96 * Returns <tt>true</tt> if the given object is also a map entry and
97 * the two entries represent the same mapping. More formally, two
98 * entries <tt>e1</tt> and <tt>e2</tt> represent the same mapping
99 * if<pre>
100 * (e1.getKey()==null ?
101 * e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&
102 * (e1.getValue()==null ?
103 * e2.getValue()==null : e1.getValue().equals(e2.getValue()))
104 * </pre>
105 * This ensures that the <tt>equals</tt> method works properly across
106 * different implementations of the <tt>Map.Entry</tt> interface.
107 *
108 * @param o object to be compared for equality with this map entry.
109 * @return <tt>true</tt> if the specified object is equal to this map
110 * entry.
111 */
112 public boolean equals(Object o) {
113 if (!(o instanceof Entry))
114 return false;
115 Entry e = (Entry)o;
116 return (key == e.getKey()) && eq(value, e.getValue());
117 }
118
119 /**
120 * Returns the hash code value for this map entry. The hash code
121 * of a map entry <tt>e</tt> is defined to be: <pre>
122 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^
123 * (e.getValue()==null ? 0 : e.getValue().hashCode())
124 * </pre>
125 * This ensures that <tt>e1.equals(e2)</tt> implies that
126 * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries
127 * <tt>e1</tt> and <tt>e2</tt>, as required by the general
128 * contract of <tt>Object.hashCode</tt>.
129 *
130 * @return the hash code value for this map entry.
131 * @see Object#hashCode()
132 * @see Object#equals(Object)
133 * @see #equals(Object)
134 */
135 public int hashCode() {
136 return hash ^ (value==null ? 0 : value.hashCode());
137 }
138 }
139
140 /**
141 * The hash table data.
142 */
143 transient Entry table[];
144
145 /**
146 * The total number of mappings in the hash table.
147 */
148 transient int size;
149
150 /**
151 * The table is rehashed when its size exceeds this threshold. (The
152 * value of this field is (int)(capacity * loadFactor).)
153 *
154 * @serial
155 */
156 int threshold;
157
158 /**
159 * The load factor for the hash table.
160 *
161 * @serial
162 */
163 final float loadFactor;
164
165 /**
166 * The number of times this HashMap has been structurally modified
167 * Structural modifications are those that change the number of mappings in
168 * the HashMap or otherwise modify its internal structure (e.g.,
169 * rehash). This field is used to make iterators on Collection-views of
170 * the HashMap fail-fast. (See ConcurrentModificationException).
171 */
172 transient int modCount = 0;
173
174 /**
175 * Constructs a new, empty map with the specified initial
176 * capacity and the specified load factor.
177 *
178 * @param initialCapacity the initial capacity of the HashMap.
179 * @param loadFactor the load factor of the HashMap
180 * @throws IllegalArgumentException if the initial capacity is less
181 * than zero, or if the load factor is nonpositive.
182 */
183 public LongHashMap(int initialCapacity, float loadFactor) {
184 if (initialCapacity < 0)
185 throw new IllegalArgumentException("Illegal Initial Capacity: "+
186 initialCapacity);
187 if (loadFactor <= 0 || Float.isNaN(loadFactor))
188 throw new IllegalArgumentException("Illegal Load factor: "+
189 loadFactor);
190 if (initialCapacity==0)
191 initialCapacity = 1;
192 this.loadFactor = loadFactor;
193 table = new Entry[initialCapacity];
194 threshold = (int)(initialCapacity * loadFactor);
195 }
196
197 /**
198 * Constructs a new, empty map with the specified initial capacity
199 * and default load factor, which is <tt>0.75</tt>.
200 *
201 * @param initialCapacity the initial capacity of the HashMap.
202 * @throws IllegalArgumentException if the initial capacity is less
203 * than zero.
204 */
205 public LongHashMap(int initialCapacity) {
206 this(initialCapacity, 0.75f);
207 }
208
209 /**
210 * Constructs a new, empty map with a default capacity and load
211 * factor, which is <tt>0.75</tt>.
212 */
213 public LongHashMap() {
214 this(11, 0.75f);
215 }
216
217 /**
218 * Returns the number of key-value mappings in this map.
219 *
220 * @return the number of key-value mappings in this map.
221 */
222 public int size() {
223 return size;
224 }
225
226 /**
227 * Returns <tt>true</tt> if this map contains no key-value mappings.
228 *
229 * @return <tt>true</tt> if this map contains no key-value mappings.
230 */
231 public boolean isEmpty() {
232 return size == 0;
233 }
234
235 /**
236 * Returns the value to which this map maps the specified key. Returns
237 * <tt>null</tt> if the map contains no mapping for this key. A return
238 * value of <tt>null</tt> does not <i>necessarily</i> indicate that the
239 * map contains no mapping for the key; it's also possible that the map
240 * explicitly maps the key to <tt>null</tt>. The <tt>containsKey</tt>
241 * operation may be used to distinguish these two cases.
242 *
243 * @return the value to which this map maps the specified key.
244 * @param key key whose associated value is to be returned.
245 */
246 public Object get(long key) {
247 Entry e = getEntry(key);
248 return (e == null ? null : e.value);
249 }
250
251 /**
252 * Returns <tt>true</tt> if this map contains a mapping for the specified
253 * key.
254 *
255 * @return <tt>true</tt> if this map contains a mapping for the specified
256 * key.
257 * @param key key whose presence in this Map is to be tested.
258 */
259 public boolean containsKey(long key) {
260 return getEntry(key) != null;
261 }
262
263 /**
264 * Returns the entry associated with the specified key in the
265 * HashMap. Returns null if the HashMap contains no mapping
266 * for this key.
267 */
268 Entry getEntry(long key) {
269 Entry tab[] = table;
270 int hash = (int) key;
271 int index = (hash & 0x7FFFFFFF) % tab.length;
272
273 for (Entry e = tab[index]; e != null; e = e.next)
274 if (e.hash == hash && e.key ==key)
275 return e;
276
277 return null;
278 }
279
280 /**
281 * Returns <tt>true</tt> if this map maps one or more keys to the
282 * specified value.
283 *
284 * @param value value whose presence in this map is to be tested.
285 * @return <tt>true</tt> if this map maps one or more keys to the
286 * specified value.
287 */
288 public boolean containsValue(Object value) {
289 Entry tab[] = table;
290
291 if (value==null) {
292 for (int i = tab.length ; i-- > 0 ;)
293 for (Entry e = tab[i] ; e != null ; e = e.next)
294 if (e.value==null)
295 return true;
296 } else {
297 for (int i = tab.length ; i-- > 0 ;)
298 for (Entry e = tab[i] ; e != null ; e = e.next)
299 if (value.equals(e.value))
300 return true;
301 }
302
303 return false;
304 }
305
306 /**
307 * Associates the specified value with the specified key in this map.
308 * If the map previously contained a mapping for this key, the old
309 * value is replaced.
310 *
311 * @param key key with which the specified value is to be associated.
312 * @param value value to be associated with the specified key.
313 * @return previous value associated with specified key, or <tt>null</tt>
314 * if there was no mapping for key. A <tt>null</tt> return can
315 * also indicate that the HashMap previously associated
316 * <tt>null</tt> with the specified key.
317 */
318 public Object put(long key, Object value) {
319 Entry tab[] = table;
320 int hash = (int) key;
321 int index = (hash & 0x7FFFFFFF) % tab.length;
322
323 // Look for entry in hash table
324 for (Entry e = tab[index] ; e != null ; e = e.next) {
325 if (e.hash == hash && e.key == key) {
326 Object oldValue = e.value;
327 e.value = value;
328 return oldValue;
329 }
330 }
331
332 // It's not there; grow the hash table if necessary...
333 modCount++;
334 if (size >= threshold) {
335 rehash();
336 tab = table;
337 index = (hash & 0x7FFFFFFF) % tab.length;
338 }
339
340 // ...and add the entry
341 size++;
342 tab[index] = newEntry(hash, key, value, tab[index]);
343 return null;
344 }
345
346 /**
347 * Removes the mapping for this key from this map if present.
348 *
349 * @param key key whose mapping is to be removed from the map.
350 * @return previous value associated with specified key, or <tt>null</tt>
351 * if there was no mapping for key. A <tt>null</tt> return can
352 * also indicate that the map previously associated <tt>null</tt>
353 * with the specified key.
354 */
355 public Object remove(long key) {
356 Entry e = removeEntryForKey(key);
357 return (e == null ? null : e.value);
358 }
359
360 /**
361 * Removes and returns the entry associated with the specified key
362 * in the HashMap. Returns null if the HashMap contains no mapping
363 * for this key.
364 */
365 Entry removeEntryForKey(long key) {
366 Entry tab[] = table;
367 int hash = (int) key;
368 int index = (hash & 0x7FFFFFFF) % tab.length;
369
370 for (Entry e = tab[index], prev = null; e != null;
371 prev = e, e = e.next) {
372 if (e.hash == hash && e.key == key) {
373 modCount++;
374 if (prev != null)
375 prev.next = e.next;
376 else
377 tab[index] = e.next;
378
379 size--;
380 return e;
381 }
382 }
383
384 return null;
385 }
386
387 /**
388 * Removes the specified entry from this HashMap (and increments modCount).
389 *
390 * @throws ConcurrentModificationException if the entry is not in the Map
391 */
392 void removeEntry(Entry doomed) {
393 Entry[] tab = table;
394 int index = (doomed.hash & 0x7FFFFFFF) % tab.length;
395
396 for (Entry e = tab[index], prev = null; e != null;
397 prev = e, e = e.next) {
398 if (e == doomed) {
399 modCount++;
400 if (prev == null)
401 tab[index] = e.next;
402 else
403 prev.next = e.next;
404 size--;
405 return;
406 }
407 }
408 throw new ConcurrentModificationException();
409 }
410
411 /**
412 * Removes all mappings from this map.
413 */
414 public void clear() {
415 Entry tab[] = table;
416 modCount++;
417 for (int index = tab.length; --index >= 0; )
418 tab[index] = null;
419 size = 0;
420 }
421
422 /**
423 * Rehashes the contents of this map into a new <tt>HashMap</tt> instance
424 * with a larger capacity. This method is called automatically when the
425 * number of keys in this map exceeds its capacity and load factor.
426 */
427 void rehash() {
428 Entry oldTable[] = table;
429 int oldCapacity = oldTable.length;
430 int newCapacity = oldCapacity * 2 + 1;
431 Entry newTable[] = new Entry[newCapacity];
432
433 modCount++;
434 threshold = (int)(newCapacity * loadFactor);
435 table = newTable;
436
437 for (int i = oldCapacity ; i-- > 0 ;) {
438 for (Entry old = oldTable[i] ; old != null ; ) {
439 Entry e = old;
440 old = old.next;
441
442 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
443 e.next = newTable[index];
444 newTable[index] = e;
445 }
446 }
447 }
448
449 static boolean eq(Object o1, Object o2) {
450 return (o1==null ? o2==null : o1.equals(o2));
451 }
452
453 Entry newEntry(int hash, long key, Object value, Entry next) {
454 return new Entry(hash, key, value, next);
455 }
456
457 int capacity() {
458 return table.length;
459 }
460
461 float loadFactor() {
462 return loadFactor;
463 }
464 }