Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

RefHashTable.java

00001 package edu.ksu.cis.bandera.abstraction.util;
00002 
00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00004  * Bandera, a Java(TM) analysis and transformation toolkit           *
00005  * Copyright (C) 1998, 1999, 2000   Shawn Laubach (laubach@acm.org)  *
00006  * All rights reserved.                                              *
00007  *                                                                   *
00008  * This work was done as a project in the SAnToS Laboratory,         *
00009  * Department of Computing and Information Sciences, Kansas State    *
00010  * University, USA (http://www.cis.ksu.edu/santos).                  *
00011  * It is understood that any modification not identified as such is  *
00012  * not covered by the preceding statement.                           *
00013  *                                                                   *
00014  * This work is free software; you can redistribute it and/or        *
00015  * modify it under the terms of the GNU Library General Public       *
00016  * License as published by the Free Software Foundation; either      *
00017  * version 2 of the License, or (at your option) any later version.  *
00018  *                                                                   *
00019  * This work is distributed in the hope that it will be useful,      *
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
00022  * Library General Public License for more details.                  *
00023  *                                                                   *
00024  * You should have received a copy of the GNU Library General Public *
00025  * License along with this toolkit; if not, write to the             *
00026  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,      *
00027  * Boston, MA  02111-1307, USA.                                      *
00028  *                                                                   *
00029  * Java is a trademark of Sun Microsystems, Inc.                     *
00030  *                                                                   *
00031  * To submit a bug report, send a comment, or get the latest news on *
00032  * this project and other SAnToS projects, please visit the web-site *
00033  *                http://www.cis.ksu.edu/santos                      *
00034  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00035 import java.util.*;
00036 import java.io.*;
00037 public class RefHashTable extends Dictionary implements Map, Cloneable, java.io.Serializable {
00038     /**
00039      * The hash table data.
00040      */
00041     private transient Entry table[];
00042 
00043     /**
00044      * The total number of entries in the hash table.
00045      */
00046     private transient int count;
00047 
00048     /**
00049      * The table is rehashed when its size exceeds this threshold.  (The
00050      * value of this field is (int)(capacity * loadFactor).)
00051      *
00052      * @serial
00053      */
00054     private int threshold;
00055 
00056     /**
00057      * The load factor for the RefHashTable.
00058      *
00059      * @serial
00060      */
00061     private float loadFactor;
00062 
00063     /**
00064      * The number of times this RefHashTable has been structurally modified
00065      * Structural modifications are those that change the number of entries in
00066      * the RefHashTable or otherwise modify its internal structure (e.g.,
00067      * rehash).  This field is used to make iterators on Collection-views of
00068      * the RefHashTable fail-fast.  (See ConcurrentModificationException).
00069      */
00070     private transient int modCount = 0;
00071 
00072     // Views
00073 
00074     private transient Set keySet = null;
00075     private transient Set entrySet = null;
00076     private transient Collection values = null;
00077     private class KeySet extends AbstractSet {
00078         public Iterator iterator() {
00079             return new Enumerator(KEYS, true);
00080         }
00081         public int size() {
00082             return count;
00083         }
00084         public boolean contains(Object o) {
00085             return containsKey(o);
00086         }
00087         public boolean remove(Object o) {
00088             return RefHashTable.this.remove(o) != null;
00089         }
00090         public void clear() {
00091             RefHashTable.this.clear();
00092         }
00093     }
00094     private class EntrySet extends AbstractSet {
00095         public Iterator iterator() {
00096             return new Enumerator(ENTRIES, true);
00097         }
00098         public boolean contains(Object o) {
00099             if (!(o instanceof Map.Entry))
00100                 return false;
00101             Map.Entry entry = (Map.Entry) o;
00102             Object key = entry.getKey();
00103             Entry tab[] = table;
00104             int hash = key.hashCode();
00105             int index = (hash & 0x7FFFFFFF) % tab.length;
00106             for (Entry e = tab[index]; e != null; e = e.next)
00107                 if (e.hash == hash && e.equals(entry))
00108                     return true;
00109             return false;
00110         }
00111         public boolean remove(Object o) {
00112             if (!(o instanceof Map.Entry))
00113                 return false;
00114             Map.Entry entry = (Map.Entry) o;
00115             Object key = entry.getKey();
00116             Entry tab[] = table;
00117             int hash = key.hashCode();
00118             int index = (hash & 0x7FFFFFFF) % tab.length;
00119             for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
00120                 if (e.hash == hash && e.equals(entry)) {
00121                     modCount++;
00122                     if (prev != null)
00123                         prev.next = e.next;
00124                     else
00125                         tab[index] = e.next;
00126                     count--;
00127                     e.value = null;
00128                     return true;
00129                 }
00130             }
00131             return false;
00132         }
00133         public int size() {
00134             return count;
00135         }
00136         public void clear() {
00137             RefHashTable.this.clear();
00138         }
00139     }
00140     private class ValueCollection extends AbstractCollection {
00141         public Iterator iterator() {
00142             return new Enumerator(VALUES, true);
00143         }
00144         public int size() {
00145             return count;
00146         }
00147         public boolean contains(Object o) {
00148             return containsValue(o);
00149         }
00150         public void clear() {
00151             RefHashTable.this.clear();
00152         }
00153     }
00154 
00155     /**
00156      * RefHashTable collision list.
00157      */
00158     private static class Entry implements Map.Entry {
00159         int hash;
00160         Object key;
00161         Object value;
00162         Entry next;
00163         protected Entry(int hash, Object key, Object value, Entry next) {
00164             this.hash = hash;
00165             this.key = key;
00166             this.value = value;
00167             this.next = next;
00168         }
00169         protected Object clone() {
00170             return new Entry(hash, key, value, (next == null ? null : (Entry) next.clone()));
00171         }
00172 
00173         // Map.Entry Ops 
00174 
00175         public Object getKey() {
00176             return key;
00177         }
00178         public Object getValue() {
00179             return value;
00180         }
00181         public Object setValue(Object value) {
00182             if (value == null)
00183                 throw new NullPointerException();
00184             Object oldValue = this.value;
00185             this.value = value;
00186             return oldValue;
00187         }
00188         public boolean equals(Object o) {
00189             if (!(o instanceof Map.Entry))
00190                 return false;
00191             Map.Entry e = (Map.Entry) o;
00192             return (key == null ? e.getKey() == null : key == e.getKey()) && (value == null ? e.getValue() == null : value.equals(e.getValue()));
00193         }
00194         public int hashCode() {
00195             return hash ^ (value == null ? 0 : value.hashCode());
00196         }
00197         public String toString() {
00198             return key.toString() + "=" + value.toString();
00199         }
00200     }
00201 
00202     // Types of Enumerations/Iterations
00203     private static final int KEYS = 0;
00204     private static final int VALUES = 1;
00205     private static final int ENTRIES = 2;
00206 
00207     /**
00208      * A hashtable enumerator class.  This class implements both the
00209      * Enumeration and Iterator interfaces, but individual instances
00210      * can be created with the Iterator methods disabled.  This is necessary
00211      * to avoid unintentionally increasing the capabilities granted a user
00212      * by passing an Enumeration.
00213      */
00214     private class Enumerator implements Enumeration, Iterator {
00215         Entry[] table = RefHashTable.this.table;
00216         int index = table.length;
00217         Entry entry = null;
00218         Entry lastReturned = null;
00219         int type;
00220 
00221         /**
00222          * Indicates whether this Enumerator is serving as an Iterator
00223          * or an Enumeration.  (true -> Iterator).
00224          */
00225         boolean iterator;
00226 
00227         /**
00228          * The modCount value that the iterator believes that the backing
00229          * List should have.  If this expectation is violated, the iterator
00230          * has detected concurrent modification.
00231          */
00232         private int expectedModCount = modCount;
00233         Enumerator(int type, boolean iterator) {
00234             this.type = type;
00235             this.iterator = iterator;
00236         }
00237         public boolean hasMoreElements() {
00238             while (entry == null && index > 0)
00239                 entry = table[--index];
00240             return entry != null;
00241         }
00242         public Object nextElement() {
00243             while (entry == null && index > 0)
00244                 entry = table[--index];
00245             if (entry != null) {
00246                 Entry e = lastReturned = entry;
00247                 entry = e.next;
00248                 return type == KEYS ? e.key : (type == VALUES ? e.value : e);
00249             }
00250             throw new NoSuchElementException("RefHashTable Enumerator");
00251         }
00252 
00253         // Iterator methods
00254         public boolean hasNext() {
00255             return hasMoreElements();
00256         }
00257         public Object next() {
00258             if (modCount != expectedModCount)
00259                 throw new ConcurrentModificationException();
00260             return nextElement();
00261         }
00262         public void remove() {
00263             if (!iterator)
00264                 throw new UnsupportedOperationException();
00265             if (lastReturned == null)
00266                 throw new IllegalStateException("RefHashTable Enumerator");
00267             if (modCount != expectedModCount)
00268                 throw new ConcurrentModificationException();
00269             synchronized (RefHashTable.this) {
00270                 Entry[] tab = RefHashTable.this.table;
00271                 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
00272                 for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
00273                     if (e == lastReturned) {
00274                         modCount++;
00275                         expectedModCount++;
00276                         if (prev == null)
00277                             tab[index] = e.next;
00278                         else
00279                             prev.next = e.next;
00280                         count--;
00281                         lastReturned = null;
00282                         return;
00283                     }
00284                 }
00285                 throw new ConcurrentModificationException();
00286             }
00287         }
00288     }
00289     /**
00290      * Constructs a new, empty HashPointerTable with a default capacity and load
00291      * factor, which is <tt>0.75</tt>. 
00292      */
00293     public RefHashTable() {
00294         this(101, 0.75f);
00295     }
00296     /**
00297      * Constructs a new, empty HashPointerTable with the specified initial capacity
00298      * and default load factor, which is <tt>0.75</tt>.
00299      *
00300      * @param     initialCapacity   the initial capacity of the hashtable.
00301      * @exception IllegalArgumentException if the initial capacity is less
00302      *              than zero.
00303      */
00304     public RefHashTable(int initialCapacity) {
00305         this(initialCapacity, 0.75f);
00306     }
00307     /**
00308      * Constructs a new, empty HashPointerTable with the specified initial 
00309      * capacity and the specified load factor.
00310      *
00311      * @param      initialCapacity   the initial capacity of the hashtable.
00312      * @param      loadFactor        the load factor of the hashtable.
00313      * @exception  IllegalArgumentException  if the initial capacity is less
00314      *             than zero, or if the load factor is nonpositive.
00315      */
00316     public RefHashTable(int initialCapacity, float loadFactor) {
00317         if (initialCapacity < 0)
00318             throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
00319         if (loadFactor <= 0)
00320             throw new IllegalArgumentException("Illegal Load: " + loadFactor);
00321         if (initialCapacity == 0)
00322             initialCapacity = 1;
00323         this.loadFactor = loadFactor;
00324         table = new Entry[initialCapacity];
00325         threshold = (int) (initialCapacity * loadFactor);
00326     }
00327     /**
00328      * Constructs a new HashPointerTable with the same mappings as the given 
00329      * Map.  The hashtable is created with a capacity of twice the number
00330      * of entries in the given Map or 11 (whichever is greater), and a
00331      * default load factor, which is <tt>0.75</tt>.
00332      *
00333      * @since   JDK1.2
00334      */
00335     public RefHashTable(Map t) {
00336         this(Math.max(2 * t.size(), 11), 0.75f);
00337         putAll(t);
00338     }
00339     /**
00340      * Clears this HashPointerTable so that it contains no keys. 
00341      */
00342     public synchronized void clear() {
00343         Entry tab[] = table;
00344         modCount++;
00345         for (int index = tab.length; --index >= 0;)
00346             tab[index] = null;
00347         count = 0;
00348     }
00349 /**
00350  * Creates a shallow copy of this HashPointerTable. All the structure of the 
00351  * hashtable itself is copied, but the keys and values are not cloned. 
00352  * This is a relatively expensive operation.
00353  *
00354  * @return  a clone of the hashtable.
00355  */
00356 public synchronized Object clone() {
00357     try {
00358         RefHashTable t = (RefHashTable) super.clone();
00359         t.table = new Entry[table.length];
00360         for (int i = table.length; i-- > 0;) {
00361             t.table[i] = (table[i] != null) ? (Entry) table[i].clone() : null;
00362         }
00363         t.keySet = null;
00364         t.entrySet = null;
00365         t.values = null;
00366         t.modCount = 0;
00367         return t;
00368     } catch (CloneNotSupportedException e) {
00369         // this shouldn't happen, since we are Cloneable
00370         throw new InternalError();
00371     }
00372 }
00373     /**
00374      * Tests if some key maps into the specified value in this HashPointerTable.
00375      * This operation is more expensive than the <code>containsKey</code>
00376      * method.<p>
00377      *
00378      * Note that this method is identical in functionality to containsValue,
00379      * (which is part of the Map interface in the collections framework).
00380      * 
00381      * @param      value   a value to search for.
00382      * @return     <code>true</code> if and only if some key maps to the
00383      *             <code>value</code> argument in this hashtable as 
00384      *             determined by the <tt>equals</tt> method;
00385      *             <code>false</code> otherwise.
00386      * @exception  NullPointerException  if the value is <code>null</code>.
00387      * @see        #containsKey(Object)
00388      * @see        #containsValue(Object)
00389      * @see    Map
00390      */
00391     public synchronized boolean contains(Object value) {
00392         if (value == null) {
00393             throw new NullPointerException();
00394         }
00395         Entry tab[] = table;
00396         for (int i = tab.length; i-- > 0;) {
00397             for (Entry e = tab[i]; e != null; e = e.next) {
00398                 if (e.value.equals(value)) {
00399                     return true;
00400                 }
00401             }
00402         }
00403         return false;
00404     }
00405     /**
00406      * Tests if the specified object is a key in this HashPointerTable.
00407      * 
00408      * @param   key   possible key.
00409      * @return  <code>true</code> if and only if the specified object 
00410      *          is a key in this hashtable, as determined by the 
00411      *          <tt>equals</tt> method; <code>false</code> otherwise.
00412      * @see     #contains(Object)
00413      */
00414     public synchronized boolean containsKey(Object key) {
00415         Entry tab[] = table;
00416         int hash = key.hashCode();
00417         int index = (hash & 0x7FFFFFFF) % tab.length;
00418         for (Entry e = tab[index]; e != null; e = e.next) {
00419             if ((e.hash == hash) && e.key == key) {
00420                 return true;
00421             }
00422         }
00423         return false;
00424     }
00425     /**
00426      * Returns true if this HashPointerTable maps one or more keys to this value.<p>
00427      *
00428      * Note that this method is identical in functionality to contains
00429      * (which predates the Map interface).
00430      *
00431      * @param value value whose presence in this HashPointerTable is to be tested.
00432      * @see    Map
00433      * @since JDK1.2
00434      */
00435     public boolean containsValue(Object value) {
00436         return contains(value);
00437     }
00438     /**
00439      * Returns an enumeration of the values in this HashPointerTable.
00440      * Use the Enumeration methods on the returned object to fetch the elements
00441      * sequentially.
00442      *
00443      * @return  an enumeration of the values in this hashtable.
00444      * @see     java.util.Enumeration
00445      * @see     #keys()
00446      * @see #values()
00447      * @see Map
00448      */
00449     public synchronized Enumeration elements() {
00450         return new Enumerator(VALUES, false);
00451     }
00452     /**
00453      * Returns a Set view of the entries contained in this HashPointerTable.
00454      * Each element in this collection is a Map.Entry.  The Set is
00455      * backed by the HashPointerTable, so changes to the HashPointerTable are reflected in
00456      * the Set, and vice-versa.  The Set supports element removal
00457      * (which removes the corresponding entry from the HashPointerTable),
00458      * but not element addition.
00459      *
00460      * @see   Map.Entry
00461      * @since JDK1.2
00462      */
00463     public Set entrySet() {
00464         if (entrySet == null)
00465             entrySet = Collections.synchronizedSet(new EntrySet());
00466         return entrySet;
00467     }
00468     // Comparison and hashing
00469 
00470     /**
00471      * Compares the specified Object with this Map for equality,
00472      * as per the definition in the Map interface.
00473      *
00474      * @return true if the specified Object is equal to this Map.
00475      * @see Map#equals(Object)
00476      * @since JDK1.2
00477      */
00478     public synchronized boolean equals(Object o) {
00479         if (o == this)
00480             return true;
00481         if (!(o instanceof Map))
00482             return false;
00483         Map t = (Map) o;
00484         if (t.size() != size())
00485             return false;
00486         Iterator i = entrySet().iterator();
00487         while (i.hasNext()) {
00488             Entry e = (Entry) i.next();
00489             Object key = e.getKey();
00490             Object value = e.getValue();
00491             if (value == null) {
00492                 if (!(t.get(key) == null && t.containsKey(key)))
00493                     return false;
00494             } else {
00495                 if (!value.equals(t.get(key)))
00496                     return false;
00497             }
00498         }
00499         return true;
00500     }
00501     /**
00502      * Returns the value to which the specified key is mapped in this HashPointerTable.
00503      *
00504      * @param   key   a key in the hashtable.
00505      * @return  the value to which the key is mapped in this hashtable;
00506      *          <code>null</code> if the key is not mapped to any value in
00507      *          this hashtable.
00508      * @see     #put(Object, Object)
00509      */
00510     public synchronized Object get(Object key) {
00511         Entry tab[] = table;
00512         int hash = key.hashCode();
00513         int index = (hash & 0x7FFFFFFF) % tab.length;
00514         for (Entry e = tab[index]; e != null; e = e.next) {
00515             if ((e.hash == hash) && e.key == key) {
00516                 return e.value;
00517             }
00518         }
00519         return null;
00520     }
00521     /**
00522      * Returns the hash code value for this Map as per the definition in the
00523      * Map interface.
00524      *
00525      * @see Map#hashCode()
00526      * @since JDK1.2
00527      */
00528     public synchronized int hashCode() {
00529         int h = 0;
00530         Iterator i = entrySet().iterator();
00531         while (i.hasNext())
00532             h += i.next().hashCode();
00533         return h;
00534     }
00535     /**
00536      * Tests if this HashPointerTable maps no keys to values.
00537      *
00538      * @return  <code>true</code> if this hashtable maps no keys to values;
00539      *          <code>false</code> otherwise.
00540      */
00541     public boolean isEmpty() {
00542         return count == 0;
00543     }
00544     /**
00545      * Returns an enumeration of the keys in this HashPointerTable.
00546      *
00547      * @return  an enumeration of the keys in this hashtable.
00548      * @see     Enumeration
00549      * @see     #elements()
00550      * @see #keySet()
00551      * @see Map
00552      */
00553     public synchronized Enumeration keys() {
00554         return new Enumerator(KEYS, false);
00555     }
00556     /**
00557      * Returns a Set view of the keys contained in this HashPointerTable.  The Set
00558      * is backed by the HashPointerTable, so changes to the HashPointerTable are reflected
00559      * in the Set, and vice-versa.  The Set supports element removal
00560      * (which removes the corresponding entry from the HashPointerTable), but not
00561      * element addition.
00562      *
00563      * @since JDK1.2
00564      */
00565     public Set keySet() {
00566         if (keySet == null)
00567             keySet = Collections.synchronizedSet(new KeySet());
00568         return keySet;
00569     }
00570     /**
00571      * Maps the specified <code>key</code> to the specified 
00572      * <code>value</code> in this HashPointerTable. Neither the key nor the 
00573      * value can be <code>null</code>. <p>
00574      *
00575      * The value can be retrieved by calling the <code>get</code> method 
00576      * with a key that is equal to the original key. 
00577      *
00578      * @param      key     the hashtable key.
00579      * @param      value   the value.
00580      * @return     the previous value of the specified key in this hashtable,
00581      *             or <code>null</code> if it did not have one.
00582      * @exception  NullPointerException  if the key or value is
00583      *               <code>null</code>.
00584      * @see     Object#equals(Object)
00585      * @see     #get(Object)
00586      */
00587     public synchronized Object put(Object key, Object value) {
00588         // Make sure the value is not null
00589         if (value == null) {
00590             throw new NullPointerException();
00591         }
00592 
00593         // Makes sure the key is not already in the hashtable.
00594         Entry tab[] = table;
00595         int hash = key.hashCode();
00596         int index = (hash & 0x7FFFFFFF) % tab.length;
00597         for (Entry e = tab[index]; e != null; e = e.next) {
00598             if ((e.hash == hash) && e.key == key) {
00599                 Object old = e.value;
00600                 e.value = value;
00601                 return old;
00602             }
00603         }
00604         modCount++;
00605         if (count >= threshold) {
00606             // Rehash the table if the threshold is exceeded
00607             rehash();
00608             tab = table;
00609             index = (hash & 0x7FFFFFFF) % tab.length;
00610         }
00611 
00612         // Creates the new entry.
00613         Entry e = new Entry(hash, key, value, tab[index]);
00614         tab[index] = e;
00615         count++;
00616         return null;
00617     }
00618     /**
00619      * Copies all of the mappings from the specified Map to this HashPointerTable
00620      * These mappings will replace any mappings that this HashPointerTable had for any
00621      * of the keys currently in the specified Map. 
00622      *
00623      * @since JDK1.2
00624      */
00625     public synchronized void putAll(Map t) {
00626         Iterator i = t.entrySet().iterator();
00627         while (i.hasNext()) {
00628             Map.Entry e = (Map.Entry) i.next();
00629             put(e.getKey(), e.getValue());
00630         }
00631     }
00632     /**
00633      * Reconstitute the HashPointerTable from a stream (i.e., deserialize it).
00634      */
00635     private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
00636         // Read in the length, threshold, and loadfactor
00637         s.defaultReadObject();
00638 
00639         // Read the original length of the array and number of elements
00640         int origlength = s.readInt();
00641         int elements = s.readInt();
00642 
00643         // Compute new size with a bit of room 5% to grow but
00644         // No larger than the original size.  Make the length
00645         // odd if it's large enough, this helps distribute the entries.
00646         // Guard against the length ending up zero, that's not valid.
00647         int length = (int) (elements * loadFactor) + (elements / 20) + 3;
00648         if (length > elements && (length & 1) == 0)
00649             length--;
00650         if (origlength > 0 && length > origlength)
00651             length = origlength;
00652         table = new Entry[length];
00653         count = 0;
00654 
00655         // Read the number of elements and then all the key/value objects
00656         for (; elements > 0; elements--) {
00657             Object key = s.readObject();
00658             Object value = s.readObject();
00659             put(key, value);
00660         }
00661     }
00662     /**
00663      * Increases the capacity of and internally reorganizes this 
00664      * HashPointerTable, in order to accommodate and access its entries more 
00665      * efficiently.  This method is called automatically when the 
00666      * number of keys in the hashtable exceeds this hashtable's capacity 
00667      * and load factor. 
00668      */
00669     protected void rehash() {
00670         int oldCapacity = table.length;
00671         Entry oldMap[] = table;
00672         int newCapacity = oldCapacity * 2 + 1;
00673         Entry newMap[] = new Entry[newCapacity];
00674         modCount++;
00675         threshold = (int) (newCapacity * loadFactor);
00676         table = newMap;
00677         for (int i = oldCapacity; i-- > 0;) {
00678             for (Entry old = oldMap[i]; old != null;) {
00679                 Entry e = old;
00680                 old = old.next;
00681                 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
00682                 e.next = newMap[index];
00683                 newMap[index] = e;
00684             }
00685         }
00686     }
00687     /**
00688      * Removes the key (and its corresponding value) from this 
00689      * HashPointerTable. This method does nothing if the key is not in the hashtable.
00690      *
00691      * @param   key   the key that needs to be removed.
00692      * @return  the value to which the key had been mapped in this hashtable,
00693      *          or <code>null</code> if the key did not have a mapping.
00694      */
00695     public synchronized Object remove(Object key) {
00696         Entry tab[] = table;
00697         int hash = key.hashCode();
00698         int index = (hash & 0x7FFFFFFF) % tab.length;
00699         for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
00700             if ((e.hash == hash) && e.key == key) {
00701                 modCount++;
00702                 if (prev != null) {
00703                     prev.next = e.next;
00704                 } else {
00705                     tab[index] = e.next;
00706                 }
00707                 count--;
00708                 Object oldValue = e.value;
00709                 e.value = null;
00710                 return oldValue;
00711             }
00712         }
00713         return null;
00714     }
00715     /**
00716      * Returns the number of keys in this HashPointerTable.
00717      *
00718      * @return  the number of keys in this hashtable.
00719      */
00720     public int size() {
00721         return count;
00722     }
00723     /**
00724      * Returns a string representation of this <tt>HashPointerTable</tt> object 
00725      * in the form of a set of entries, enclosed in braces and separated 
00726      * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each 
00727      * entry is rendered as the key, an equals sign <tt>=</tt>, and the 
00728      * associated element, where the <tt>toString</tt> method is used to 
00729      * convert the key and element to strings. <p>Overrides to 
00730      * <tt>toString</tt> method of <tt>Object</tt>.
00731      *
00732      * @return  a string representation of this hashtable.
00733      */
00734     public synchronized String toString() {
00735         int max = size() - 1;
00736         StringBuffer buf = new StringBuffer();
00737         Iterator it = entrySet().iterator();
00738         buf.append("{");
00739         for (int i = 0; i <= max; i++) {
00740             Entry e = (Entry) (it.next());
00741             buf.append(e.key + "=" + e.value);
00742             if (i < max)
00743                 buf.append(", ");
00744         }
00745         buf.append("}");
00746         return buf.toString();
00747     }
00748     /**
00749      * Returns a Collection view of the values contained in this HashPointerTable.
00750      * The Collection is backed by the HashPointerTable, so changes to the HashPointerTable
00751      * are reflected in the Collection, and vice-versa.  The Collection
00752      * supports element removal (which removes the corresponding entry from
00753      * the HashPointerTable), but not element addition.
00754      *
00755      * @since JDK1.2
00756      */
00757     public Collection values() {
00758         if (values == null)
00759             values = Collections.synchronizedCollection(new ValueCollection());
00760         return values;
00761     }
00762     /**
00763      * Save the state of the HashPointerTable to a stream (i.e., serialize it).
00764      *
00765      * @serialData The <i>capacity</i> of the HashPointerTable (the length of the
00766      *         bucket array) is emitted (int), followed  by the
00767      *         <i>size</i> of the HashPointerTable (the number of key-value
00768      *         mappings), followed by the key (Object) and value (Object)
00769      *         for each key-value mapping represented by the HashPointerTable
00770      *         The key-value mappings are emitted in no particular order.
00771      */
00772     private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException {
00773         // Write out the length, threshold, loadfactor
00774         s.defaultWriteObject();
00775 
00776         // Write out length, count of elements and then the key/value objects
00777         s.writeInt(table.length);
00778         s.writeInt(count);
00779         for (int index = table.length - 1; index >= 0; index--) {
00780             Entry entry = table[index];
00781             while (entry != null) {
00782                 s.writeObject(entry.key);
00783                 s.writeObject(entry.value);
00784                 entry = entry.next;
00785             }
00786         }
00787     }
00788 }

Generated at Thu Feb 7 06:53:47 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001