/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*- * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is the Grendel mail/news client. * * The Initial Developer of the Original Code is Netscape Communications * Corporation. Portions created by Netscape are Copyright (C) 1997 * Netscape Communications Corporation. All Rights Reserved. */ package calypso.util; import java.util.*; /** * Special hashtable that uses Atoms as keys. This extends HashtableBase to * expose a public Atom based api * This hastable uses identity comparisons on keys * * @author psl 10-15-97 1:22pm * @version $Revision: 1.1 $ * @see */ public class AtomHashtable extends HashtableBase { /** Constructs an empty Hashtable. The Hashtable will grow on demand * as more elements are added. */ public AtomHashtable () { super (); } /** Constructs a Hashtable capable of holding at least * initialCapacity elements before needing to grow. */ public AtomHashtable (int aInitialCapacity) { super (aInitialCapacity); } /** Returns an Object array containing the Hashtable's keys. */ public Atom[] keysArray () { Atom[] result = new Atom[count]; getKeysArray (result); return result; } /** Returns an Object array containing the Hashtable's elements. */ public Object[] elementsArray () { Object[] result = new Object[count]; getElementsArray (result); return result; } /** Returns true if the Hashtable contains the element. This method * is slow -- O(n) -- because it must scan the table searching for the * element. */ public boolean contains (Object aElement) { return containsElement (aElement); } /** Returns true if the Hashtable contains the key key. */ public boolean containsKey (Atom aKey) { return (get (aKey) != null); } /** Returns the element associated with the key. This method returns * null if the Hashtable does not contain key. Hashtable * hashes and compares key using hashCode() and * equals(). */ public Object get (Atom aKey) { // We need to short-circuit here since the data arrays may not have // been allocated yet. if (count == 0) return null; return elements[tableIndexFor (aKey, hash (aKey))]; } /** Removes key and the element associated with it from the * Hashtable. Returns the element associated with key, or * null if key was not present. */ public Object remove (Atom aKey) { return removeKey (aKey); } /** Places the key/element pair in the Hashtable. Neither * key nor element may be null. Returns the old * element associated with key, or null if the key * was not present. */ public Object put (Atom aKey, Object aElement) { return super.put (aKey, aElement); } int hash (Object aKey) { return ((Atom)aKey).fHashCode; } int hash (Atom aKey) { return aKey.fHashCode; } /** Primitive method used internally to find slots in the * table. If the key is present in the table, this method will return the * index * under which it is stored. If the key is not present, then this * method will return the index under which it can be put. The caller * must look at the hashCode at that index to differentiate between * the two possibilities. */ int tableIndexFor (Object aKey, int aHash) { int product, testHash, index, step, removedIndex, probeCount; product = aHash * A; index = product >>> shift; // Probe the first slot in the table. We keep track of the first // index where we found a REMOVED marker so we can return that index // as the first available slot if the key is not already in the table. testHash = hashCodes[index]; if (testHash == aHash) { if (aKey == keys[index]) return index; removedIndex = -1; } else if (testHash == EMPTY) return index; else if (testHash == REMOVED) removedIndex = index; else removedIndex = -1; // Our first probe has failed, so now we need to start looking // elsewhere in the table. step = ((product >>> (2 * shift - 32)) & indexMask) | 1; probeCount = 1; do { probeCount++; index = (index + step) & indexMask; testHash = hashCodes[index]; if (testHash == aHash) { if (aKey == keys[index]) return index; } else if (testHash == EMPTY) { if (removedIndex < 0) return index; else return removedIndex; } else if (testHash == REMOVED && removedIndex == -1) removedIndex = index; } while (probeCount <= totalCount); // Something very bad has happened. throw new Error("Hashtable overflow"); } }