Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/LongHashMap.java
41161 views
/*1* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package sun.jvm.hotspot.debugger;2526import java.util.*;2728/**29* This is a copy of java.util.HashMap which uses longs as keys30* instead of Objects. It turns out that using this in the PageCache31* implementation speeds up heap traversals by a factor of three.32*33* @author Josh Bloch34* @author Arthur van Hoff35*/3637public class LongHashMap38{39static class Entry {40private int hash;41private long key;42private Object value;43private Entry next;4445Entry(int hash, long key, Object value, Entry next) {46this.hash = hash;47this.key = key;48this.value = value;49this.next = next;50}5152/**53* Returns the key corresponding to this entry.54*55* @return the key corresponding to this entry.56*/57long getKey() { return key; }5859/**60* Returns the value corresponding to this entry. If the mapping61* has been removed from the backing map (by the iterator's62* <tt>remove</tt> operation), the results of this call are undefined.63*64* @return the value corresponding to this entry.65*/66Object getValue() { return value; }6768/**69* Replaces the value corresponding to this entry with the specified70* value (optional operation). (Writes through to the map.) The71* behavior of this call is undefined if the mapping has already been72* removed from the map (by the iterator's <tt>remove</tt> operation).73*74* @param value new value to be stored in this entry.75* @return old value corresponding to the entry.76*77* @throws UnsupportedOperationException if the <tt>put</tt> operation78* is not supported by the backing map.79* @throws ClassCastException if the class of the specified value80* prevents it from being stored in the backing map.81* @throws IllegalArgumentException if some aspect of this value82* prevents it from being stored in the backing map.83* @throws NullPointerException the backing map does not permit84* <tt>null</tt> values, and the specified value is85* <tt>null</tt>.86*/87Object setValue(Object value) {88Object oldValue = this.value;89this.value = value;90return oldValue;91}9293/**94* Compares the specified object with this entry for equality.95* Returns <tt>true</tt> if the given object is also a map entry and96* the two entries represent the same mapping. More formally, two97* entries <tt>e1</tt> and <tt>e2</tt> represent the same mapping98* if<pre>99* (e1.getKey()==null ?100* e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&101* (e1.getValue()==null ?102* e2.getValue()==null : e1.getValue().equals(e2.getValue()))103* </pre>104* This ensures that the <tt>equals</tt> method works properly across105* different implementations of the <tt>Map.Entry</tt> interface.106*107* @param o object to be compared for equality with this map entry.108* @return <tt>true</tt> if the specified object is equal to this map109* entry.110*/111public boolean equals(Object o) {112if (!(o instanceof Entry))113return false;114Entry e = (Entry)o;115return (key == e.getKey()) && eq(value, e.getValue());116}117118/**119* Returns the hash code value for this map entry. The hash code120* of a map entry <tt>e</tt> is defined to be: <pre>121* (e.getKey()==null ? 0 : e.getKey().hashCode()) ^122* (e.getValue()==null ? 0 : e.getValue().hashCode())123* </pre>124* This ensures that <tt>e1.equals(e2)</tt> implies that125* <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries126* <tt>e1</tt> and <tt>e2</tt>, as required by the general127* contract of <tt>Object.hashCode</tt>.128*129* @return the hash code value for this map entry.130* @see Object#hashCode()131* @see Object#equals(Object)132* @see #equals(Object)133*/134public int hashCode() {135return hash ^ (value==null ? 0 : value.hashCode());136}137}138139/**140* The hash table data.141*/142transient Entry table[];143144/**145* The total number of mappings in the hash table.146*/147transient int size;148149/**150* The table is rehashed when its size exceeds this threshold. (The151* value of this field is (int)(capacity * loadFactor).)152*153* @serial154*/155int threshold;156157/**158* The load factor for the hash table.159*160* @serial161*/162final float loadFactor;163164/**165* The number of times this HashMap has been structurally modified166* Structural modifications are those that change the number of mappings in167* the HashMap or otherwise modify its internal structure (e.g.,168* rehash). This field is used to make iterators on Collection-views of169* the HashMap fail-fast. (See ConcurrentModificationException).170*/171transient int modCount = 0;172173/**174* Constructs a new, empty map with the specified initial175* capacity and the specified load factor.176*177* @param initialCapacity the initial capacity of the HashMap.178* @param loadFactor the load factor of the HashMap179* @throws IllegalArgumentException if the initial capacity is less180* than zero, or if the load factor is nonpositive.181*/182public LongHashMap(int initialCapacity, float loadFactor) {183if (initialCapacity < 0)184throw new IllegalArgumentException("Illegal Initial Capacity: "+185initialCapacity);186if (loadFactor <= 0 || Float.isNaN(loadFactor))187throw new IllegalArgumentException("Illegal Load factor: "+188loadFactor);189if (initialCapacity==0)190initialCapacity = 1;191this.loadFactor = loadFactor;192table = new Entry[initialCapacity];193threshold = (int)(initialCapacity * loadFactor);194}195196/**197* Constructs a new, empty map with the specified initial capacity198* and default load factor, which is <tt>0.75</tt>.199*200* @param initialCapacity the initial capacity of the HashMap.201* @throws IllegalArgumentException if the initial capacity is less202* than zero.203*/204public LongHashMap(int initialCapacity) {205this(initialCapacity, 0.75f);206}207208/**209* Constructs a new, empty map with a default capacity and load210* factor, which is <tt>0.75</tt>.211*/212public LongHashMap() {213this(11, 0.75f);214}215216/**217* Returns the number of key-value mappings in this map.218*219* @return the number of key-value mappings in this map.220*/221public int size() {222return size;223}224225/**226* Returns <tt>true</tt> if this map contains no key-value mappings.227*228* @return <tt>true</tt> if this map contains no key-value mappings.229*/230public boolean isEmpty() {231return size == 0;232}233234/**235* Returns the value to which this map maps the specified key. Returns236* <tt>null</tt> if the map contains no mapping for this key. A return237* value of <tt>null</tt> does not <i>necessarily</i> indicate that the238* map contains no mapping for the key; it's also possible that the map239* explicitly maps the key to <tt>null</tt>. The <tt>containsKey</tt>240* operation may be used to distinguish these two cases.241*242* @return the value to which this map maps the specified key.243* @param key key whose associated value is to be returned.244*/245public Object get(long key) {246Entry e = getEntry(key);247return (e == null ? null : e.value);248}249250/**251* Returns <tt>true</tt> if this map contains a mapping for the specified252* key.253*254* @return <tt>true</tt> if this map contains a mapping for the specified255* key.256* @param key key whose presence in this Map is to be tested.257*/258public boolean containsKey(long key) {259return getEntry(key) != null;260}261262/**263* Returns the entry associated with the specified key in the264* HashMap. Returns null if the HashMap contains no mapping265* for this key.266*/267Entry getEntry(long key) {268Entry tab[] = table;269int hash = (int) key;270int index = (hash & 0x7FFFFFFF) % tab.length;271272for (Entry e = tab[index]; e != null; e = e.next)273if (e.hash == hash && e.key ==key)274return e;275276return null;277}278279/**280* Returns <tt>true</tt> if this map maps one or more keys to the281* specified value.282*283* @param value value whose presence in this map is to be tested.284* @return <tt>true</tt> if this map maps one or more keys to the285* specified value.286*/287public boolean containsValue(Object value) {288Entry tab[] = table;289290if (value==null) {291for (int i = tab.length ; i-- > 0 ;)292for (Entry e = tab[i] ; e != null ; e = e.next)293if (e.value==null)294return true;295} else {296for (int i = tab.length ; i-- > 0 ;)297for (Entry e = tab[i] ; e != null ; e = e.next)298if (value.equals(e.value))299return true;300}301302return false;303}304305/**306* Associates the specified value with the specified key in this map.307* If the map previously contained a mapping for this key, the old308* value is replaced.309*310* @param key key with which the specified value is to be associated.311* @param value value to be associated with the specified key.312* @return previous value associated with specified key, or <tt>null</tt>313* if there was no mapping for key. A <tt>null</tt> return can314* also indicate that the HashMap previously associated315* <tt>null</tt> with the specified key.316*/317public Object put(long key, Object value) {318Entry tab[] = table;319int hash = (int) key;320int index = (hash & 0x7FFFFFFF) % tab.length;321322// Look for entry in hash table323for (Entry e = tab[index] ; e != null ; e = e.next) {324if (e.hash == hash && e.key == key) {325Object oldValue = e.value;326e.value = value;327return oldValue;328}329}330331// It's not there; grow the hash table if necessary...332modCount++;333if (size >= threshold) {334rehash();335tab = table;336index = (hash & 0x7FFFFFFF) % tab.length;337}338339// ...and add the entry340size++;341tab[index] = newEntry(hash, key, value, tab[index]);342return null;343}344345/**346* Removes the mapping for this key from this map if present.347*348* @param key key whose mapping is to be removed from the map.349* @return previous value associated with specified key, or <tt>null</tt>350* if there was no mapping for key. A <tt>null</tt> return can351* also indicate that the map previously associated <tt>null</tt>352* with the specified key.353*/354public Object remove(long key) {355Entry e = removeEntryForKey(key);356return (e == null ? null : e.value);357}358359/**360* Removes and returns the entry associated with the specified key361* in the HashMap. Returns null if the HashMap contains no mapping362* for this key.363*/364Entry removeEntryForKey(long key) {365Entry tab[] = table;366int hash = (int) key;367int index = (hash & 0x7FFFFFFF) % tab.length;368369for (Entry e = tab[index], prev = null; e != null;370prev = e, e = e.next) {371if (e.hash == hash && e.key == key) {372modCount++;373if (prev != null)374prev.next = e.next;375else376tab[index] = e.next;377378size--;379return e;380}381}382383return null;384}385386/**387* Removes the specified entry from this HashMap (and increments modCount).388*389* @throws ConcurrentModificationException if the entry is not in the Map390*/391void removeEntry(Entry doomed) {392Entry[] tab = table;393int index = (doomed.hash & 0x7FFFFFFF) % tab.length;394395for (Entry e = tab[index], prev = null; e != null;396prev = e, e = e.next) {397if (e == doomed) {398modCount++;399if (prev == null)400tab[index] = e.next;401else402prev.next = e.next;403size--;404return;405}406}407throw new ConcurrentModificationException();408}409410/**411* Removes all mappings from this map.412*/413public void clear() {414Entry tab[] = table;415modCount++;416for (int index = tab.length; --index >= 0; )417tab[index] = null;418size = 0;419}420421/**422* Rehashes the contents of this map into a new <tt>HashMap</tt> instance423* with a larger capacity. This method is called automatically when the424* number of keys in this map exceeds its capacity and load factor.425*/426void rehash() {427Entry oldTable[] = table;428int oldCapacity = oldTable.length;429int newCapacity = oldCapacity * 2 + 1;430Entry newTable[] = new Entry[newCapacity];431432modCount++;433threshold = (int)(newCapacity * loadFactor);434table = newTable;435436for (int i = oldCapacity ; i-- > 0 ;) {437for (Entry old = oldTable[i] ; old != null ; ) {438Entry e = old;439old = old.next;440441int index = (e.hash & 0x7FFFFFFF) % newCapacity;442e.next = newTable[index];443newTable[index] = e;444}445}446}447448static boolean eq(Object o1, Object o2) {449return (o1==null ? o2==null : o1.equals(o2));450}451452Entry newEntry(int hash, long key, Object value, Entry next) {453return new Entry(hash, key, value, next);454}455456int capacity() {457return table.length;458}459460float loadFactor() {461return loadFactor;462}463}464465466