package runtime; /* * @(#)HashMap.java 1.51 02/01/24 * * Copyright 2002 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ import java.io.*; import java.util.HashMap; import java.util.Iterator; import java.util.Map; final class NameCodeMap { /** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The maximum capacity, used if a higher value is implicitly specified * by either of the constructors with arguments. * MUST be a power of two <= 1<<30. */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * The load fast used when none specified in constructor. **/ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * The table, resized as necessary. Length MUST Always be a power of two. */ transient Entry[] table; /** * The number of key-value mappings contained in this identity hash map. */ transient int size; /** * The next size value at which to resize (capacity * load factor). * @serial */ int threshold; /** * The load factor for the hash table. * * @serial */ final float loadFactor; /** * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and load factor. * * @param initialCapacity The initial capacity. * @param loadFactor The load factor. * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive. */ public NameCodeMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); table = new Entry[capacity]; } /** * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and the default load factor (0.75). * * @param initialCapacity the initial capacity. * @throws IllegalArgumentException if the initial capacity is negative. */ public NameCodeMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } /** * Constructs an empty <tt>HashMap</tt> with the default initial capacity * (16) and the default load factor (0.75). */ public NameCodeMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; threshold = (int)(DEFAULT_INITIAL_CAPACITY); table = new Entry[DEFAULT_INITIAL_CAPACITY]; } public Entry get(String uri, String localName) { int hash = uri.hashCode()^localName.hashCode(); hash = hash - (hash << 7); // i.e., -127 * h int h = hash; int i = h & (table.length-1); Entry e = table[i]; while (true) { if (e == null) return e; // not found if (e.hash == hash && uri.equals(e.uri) && localName.equals(e.localName)) return e; // found e = e.next; } } public Object put(String uri, String localName, int nameCode) { int hash = uri.hashCode()^localName.hashCode(); hash = hash - (hash << 7); // i.e., -127 * h int h = hash; int i = h & (table.length-1); for (Entry e = table[i]; e != null; e = e.next) { if (e.hash == hash && uri.equals(e.uri) && localName.equals(e.localName)) throw new InternalError("duplicate entry"); } addEntry(hash, uri, localName, nameCode, i); return null; } /** * Rehashes the contents of this map into a new <tt>HashMap</tt> instance * with a larger capacity. This method is called automatically when the * number of keys in this map exceeds its capacity and load factor. * * @param newCapacity the new capacity, MUST be a power of two. */ void resize(int newCapacity) { // assert (newCapacity & -newCapacity) == newCapacity; // power of 2 Entry[] oldTable = table; int oldCapacity = oldTable.length; // check if needed if (size < threshold || oldCapacity > newCapacity) return; Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); } /** * Transfer all entries from current table to newTable. */ void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { Entry e = src[j]; if (e != null) { src[j] = null; do { Entry next = e.next; int length = newCapacity; int i = e.hash & (length-1); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } } } static final class Entry { final String uri; final String localName; final int nameCode; final HashMap startTagCache = new HashMap(); // internal variables for this map implementation final int hash; Entry next; /** * Create new entry. */ Entry(int h, String k1, String k2, int nameCode, Entry n) { this.nameCode = nameCode; next = n; uri = k1; localName = k2; hash = h; } } /** * Add a new entry with the specified key, value and hash code to * the specified bucket. It is the responsibility of this * method to resize the table if appropriate. * * Subclass overrides this to alter the behavior of put method. */ void addEntry(int hash, String uri, String localName, int nameCode, int bucketIndex) { table[bucketIndex] = new Entry(hash, uri, localName, nameCode, table[bucketIndex]); if (size++ >= threshold) resize(2 * table.length); } }