This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch: FYI: Updated Classpath comparison page


I'm checking this in.
This updates the libgcj/Classpath comparison page.

Tom

? scripts/sum.pl
Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>
	* libgcj-classpath-compare.html: Rebuilt.

Index: libgcj-classpath-compare.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/java/libgcj-classpath-compare.html,v
retrieving revision 1.15
diff -u -r1.15 libgcj-classpath-compare.html
--- libgcj-classpath-compare.html 2001/10/19 21:12:02 1.15
+++ libgcj-classpath-compare.html 2001/11/07 01:21:23
@@ -9,7 +9,7 @@
 cvs Classpath.  It was generated using the <a
 href="scripts/gen-classpath-compare"><code>gen-classpath-compare</code></a>
 script on
-2001-10-19.
+2001-11-06.
 This table intentionally omits certain classes which are not of
 interest.  If the third column shows a "Diff" link, then that means
 the script believes that the class has been merged, but a difference
@@ -19,6 +19,8 @@
 
 <table border=1 width="100%">
 <tr><th>Class</th> <th>libgcj</th> <th>Classpath</th> <th>Merge Status</th> </tr>
+<tr> <td>java.io.ByteArrayOutputStream</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.io.ByteArrayOutputStream.diff">Diff</a></td> </tr>
+<tr> <td>java.io.CharConversionException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.io.CharConversionException.diff">Diff</a></td> </tr>
 <tr> <td>java.io.DataOutputStream</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.io.File</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.io.FileDescriptor</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
@@ -31,19 +33,28 @@
 <tr> <td>java.io.ObjectOutputStream</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.io.ObjectOutputStream.diff">Diff</a></td> </tr>
 <tr> <td>java.io.ObjectStreamClass</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.io.ObjectStreamClass.diff">Diff</a></td> </tr>
 <tr> <td>java.io.OutputStreamWriter</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.io.PipedInputStream</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.io.PipedInputStream.diff">Diff</a></td> </tr>
+<tr> <td>java.io.PipedReader</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.io.PipedReader.diff">Diff</a></td> </tr>
 <tr> <td>java.io.PrintStream</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.io.PrintWriter</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.io.PrintWriter.diff">Diff</a></td> </tr>
 <tr> <td>java.io.RandomAccessFile</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.io.WriteAbortedException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.io.WriteAbortedException.diff">Diff</a></td> </tr>
+<tr> <td>java.lang.Boolean</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Boolean.diff">Diff</a></td> </tr>
+<tr> <td>java.lang.Byte</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Byte.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.Character</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.Class</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.ClassLoader</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.Double</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Double.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.EcosProcess</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.Float</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Float.diff">Diff</a></td> </tr>
+<tr> <td>java.lang.Integer</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Integer.diff">Diff</a></td> </tr>
+<tr> <td>java.lang.Long</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Long.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.Math</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.Object</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.Package</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Package.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.PosixProcess</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.Runtime</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.lang.Short</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Short.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.String</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.StringBuffer</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.StringBuffer.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.System</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.System.diff">Diff</a></td> </tr>
@@ -51,12 +62,23 @@
 <tr> <td>java.lang.Throwable</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.VMClassLoader</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.VMSecurityManager</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.lang.Void</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.Void.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.ref.Reference</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.ref.Reference.diff">Diff</a></td> </tr>
+<tr> <td>java.lang.reflect.AccessibleObject</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.reflect.AccessibleObject.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.reflect.Array</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.reflect.Constructor</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.lang.reflect.Field</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.lang.reflect.InvocationHandler</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.lang.reflect.InvocationTargetException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.reflect.InvocationTargetException.diff">Diff</a></td> </tr>
+<tr> <td>java.lang.reflect.Member</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.reflect.Member.diff">Diff</a></td> </tr>
 <tr> <td>java.lang.reflect.Method</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.lang.reflect.Modifier</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.reflect.Modifier.diff">Diff</a></td> </tr>
+<tr> <td>java.lang.reflect.Proxy</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.lang.reflect.ReflectPermission</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.lang.reflect.ReflectPermission.diff">Diff</a></td> </tr>
+<tr> <td>java.lang.reflect.UndeclaredThrowableException</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.math.BigInteger</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.net.BindException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.net.BindException.diff">Diff</a></td> </tr>
+<tr> <td>java.net.ConnectException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.net.ConnectException.diff">Diff</a></td> </tr>
 <tr> <td>java.net.DatagramSocket</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.HttpURLConnection</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.InetAddress</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
@@ -65,19 +87,64 @@
 <tr> <td>java.net.MulticastSocket</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.net.MulticastSocket.diff">Diff</a></td> </tr>
 <tr> <td>java.net.PlainDatagramSocketImpl</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.PlainSocketImpl</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.net.ProtocolException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.net.ProtocolException.diff">Diff</a></td> </tr>
 <tr> <td>java.net.ServerSocket</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.Socket</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.net.SocketException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.net.SocketException.diff">Diff</a></td> </tr>
 <tr> <td>java.net.SocketInputStream</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.SocketOutputStream</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.URL</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.URLClassLoader</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.URLConnection</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.net.URLStreamHandler</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.net.UnknownServiceException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.net.UnknownServiceException.diff">Diff</a></td> </tr>
+<tr> <td>java.security.SecureRandom</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.security.SecureRandom.diff">Diff</a></td> </tr>
+<tr> <td>java.security.SignedObject</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.security.SignedObject.diff">Diff</a></td> </tr>
+<tr> <td>java.security.cert.X509Certificate</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.security.cert.X509Certificate.diff">Diff</a></td> </tr>
+<tr> <td>java.security.interfaces.DSAKey</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.security.interfaces.DSAKey.diff">Diff</a></td> </tr>
+<tr> <td>java.sql.DatabaseMetaData</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.sql.DatabaseMetaData.diff">Diff</a></td> </tr>
 <tr> <td>java.text.CollationElementIterator</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.text.CollationKey</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.text.Collator</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.text.Collator.diff">Diff</a></td> </tr>
+<tr> <td>java.text.DecimalFormatSymbols</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.text.DecimalFormatSymbols.diff">Diff</a></td> </tr>
 <tr> <td>java.text.RuleBasedCollator</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.util.AbstractCollection</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.AbstractCollection.diff">Diff</a></td> </tr>
+<tr> <td>java.util.AbstractList</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.AbstractList.diff">Diff</a></td> </tr>
+<tr> <td>java.util.AbstractMap</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.AbstractMap.diff">Diff</a></td> </tr>
+<tr> <td>java.util.AbstractSequentialList</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.AbstractSequentialList.diff">Diff</a></td> </tr>
+<tr> <td>java.util.AbstractSet</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.AbstractSet.diff">Diff</a></td> </tr>
+<tr> <td>java.util.ArrayList</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.ArrayList.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Arrays</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Arrays.diff">Diff</a></td> </tr>
+<tr> <td>java.util.BasicMapEntry</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.BasicMapEntry.diff">Diff</a></td> </tr>
+<tr> <td>java.util.BitSet</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.BitSet.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Calendar</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Calendar.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Collections</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Collections.diff">Diff</a></td> </tr>
+<tr> <td>java.util.ConcurrentModificationException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.ConcurrentModificationException.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Dictionary</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Dictionary.diff">Diff</a></td> </tr>
+<tr> <td>java.util.EmptyStackException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.EmptyStackException.diff">Diff</a></td> </tr>
+<tr> <td>java.util.GregorianCalendar</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.GregorianCalendar.diff">Diff</a></td> </tr>
+<tr> <td>java.util.HashMap</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.HashMap.diff">Diff</a></td> </tr>
+<tr> <td>java.util.HashSet</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.HashSet.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Hashtable</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Hashtable.diff">Diff</a></td> </tr>
+<tr> <td>java.util.IdentityHashMap</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.IdentityHashMap.diff">Diff</a></td> </tr>
+<tr> <td>java.util.LinkedHashMap</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.LinkedHashMap.diff">Diff</a></td> </tr>
+<tr> <td>java.util.LinkedHashSet</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
+<tr> <td>java.util.LinkedList</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.LinkedList.diff">Diff</a></td> </tr>
+<tr> <td>java.util.List</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.List.diff">Diff</a></td> </tr>
+<tr> <td>java.util.NoSuchElementException</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.NoSuchElementException.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Properties</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Properties.diff">Diff</a></td> </tr>
+<tr> <td>java.util.ResourceBundle</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.ResourceBundle.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Stack</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Stack.diff">Diff</a></td> </tr>
 <tr> <td>java.util.TimeZone</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.TimeZone.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Timer</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Timer.diff">Diff</a></td> </tr>
+<tr> <td>java.util.TreeMap</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.TreeMap.diff">Diff</a></td> </tr>
+<tr> <td>java.util.TreeSet</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.TreeSet.diff">Diff</a></td> </tr>
+<tr> <td>java.util.Vector</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.Vector.diff">Diff</a></td> </tr>
+<tr> <td>java.util.WeakHashMap</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.WeakHashMap.diff">Diff</a></td> </tr>
+<tr> <td>java.util.jar.Attributes</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.jar.Attributes.diff">Diff</a></td> </tr>
+<tr> <td>java.util.jar.JarEntry</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.jar.JarEntry.diff">Diff</a></td> </tr>
+<tr> <td>java.util.jar.JarInputStream</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.jar.JarInputStream.diff">Diff</a></td> </tr>
+<tr> <td>java.util.jar.JarOutputStream</td> <td>Yes</td> <td>Yes</td> <td bgcolor="#aaaaee"><a href="compare/java.util.jar.JarOutputStream.diff">Diff</a></td> </tr>
 <tr> <td>java.util.prefs.AbstractPreferences</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.util.prefs.BackingStoreException</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
 <tr> <td>java.util.prefs.InvalidPreferencesFormatException</td> <td bgcolor="#eeeeaa">No</td> <td>Yes</td> <td bgcolor="#eeeeaa">No</td> </tr>
Index: compare/java.io.ByteArrayOutputStream.diff
===================================================================
RCS file: java.io.ByteArrayOutputStream.diff
diff -N java.io.ByteArrayOutputStream.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.io.ByteArrayOutputStream.diff Tue Nov 6 17:21:23 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/io/ByteArrayOutputStream.java	Fri Aug 31 11:41:35 2001
++++ java/io/ByteArrayOutputStream.java	Fri Nov  2 21:44:51 2001
+@@ -186,7 +186,7 @@
+     return new String (buf, 0, count, hibyte);
+   }
+ 
+-  // Resize buffer to accomodate new bytes.
++  // Resize buffer to accommodate new bytes.
+   private void resize (int add)
+   {
+     if (count + add >= buf.length)
Index: compare/java.io.CharConversionException.diff
===================================================================
RCS file: java.io.CharConversionException.diff
diff -N java.io.CharConversionException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.io.CharConversionException.diff Tue Nov 6 17:21:23 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/io/CharConversionException.java	Sun Apr 15 11:57:24 2001
++++ java/io/CharConversionException.java	Fri Nov  2 21:44:51 2001
+@@ -33,7 +33,7 @@
+  */
+ 
+ /**
+-  * This exception is thrown to indicate that a problem occured with
++  * This exception is thrown to indicate that a problem occurred with
+   * an attempted character conversion.
+   *
+   * @version 0.0
Index: compare/java.io.PipedInputStream.diff
===================================================================
RCS file: java.io.PipedInputStream.diff
diff -N java.io.PipedInputStream.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.io.PipedInputStream.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/io/PipedInputStream.java	Sun Jan  7 16:06:09 2001
++++ java/io/PipedInputStream.java	Fri Nov  2 21:44:51 2001
+@@ -194,7 +194,7 @@
+ 	else
+ 	  copylen = Math.min (len, buffer.length - in);
+ 
+-	// Copy bytes until the pipe is filled, wrapping if neccessary.
++	// Copy bytes until the pipe is filled, wrapping if necessary.
+ 	System.arraycopy(buf, bufpos, buffer, in, copylen);
+ 	len -= copylen;
+ 	bufpos += copylen;
Index: compare/java.io.PipedReader.diff
===================================================================
RCS file: java.io.PipedReader.diff
diff -N java.io.PipedReader.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.io.PipedReader.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/io/PipedReader.java	Thu Aug 30 23:25:40 2001
++++ java/io/PipedReader.java	Fri Nov  2 21:44:51 2001
+@@ -181,7 +181,7 @@
+ 	  else
+ 	    copylen = Math.min (len, buffer.length - in);
+ 
+-	  // Copy chars until the pipe is filled, wrapping if neccessary.
++	  // Copy chars until the pipe is filled, wrapping if necessary.
+ 	  System.arraycopy(buf, bufpos, buffer, in, copylen);
+ 	  len -= copylen;
+ 	  bufpos += copylen;
Index: compare/java.io.PrintWriter.diff
===================================================================
RCS file: java.io.PrintWriter.diff
diff -N java.io.PrintWriter.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.io.PrintWriter.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/io/PrintWriter.java	Fri Feb  9 00:36:24 2001
++++ java/io/PrintWriter.java	Fri Nov  2 21:44:51 2001
+@@ -57,7 +57,7 @@
+   private boolean autoflush;
+ 
+   /**
+-   * This boolean indicates whether or not an error has ever occured
++   * This boolean indicates whether or not an error has ever occurred
+    * on this stream.
+    */
+   private boolean error;
Index: compare/java.io.WriteAbortedException.diff
===================================================================
RCS file: java.io.WriteAbortedException.diff
diff -N java.io.WriteAbortedException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.io.WriteAbortedException.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,8 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/io/WriteAbortedException.java	Sun Jul 23 11:57:08 2000
++++ java/io/WriteAbortedException.java	Fri Nov  2 21:44:51 2001
+@@ -1,4 +1,4 @@
+-/* WriteAbortedException.java -- An exception occured while writing a 
++/* WriteAbortedException.java -- An exception occurred while writing a 
+    serialization stream
+    Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ 
Index: compare/java.lang.Boolean.diff
===================================================================
RCS file: java.lang.Boolean.diff
diff -N java.lang.Boolean.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.Boolean.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Boolean.java	Mon Jul 23 14:20:24 2001
++++ java/lang/Boolean.java	Fri Oct 26 16:18:42 2001
+@@ -60,7 +60,7 @@
+      * The primitive type <code>boolean</code> is represented by this 
+      * <code>Class</code> object.
+      */
+-    public static final Class TYPE = VMClassLoader.getPrimitiveClass("boolean");
++    public static final Class TYPE = VMClassLoader.getPrimitiveClass('Z');
+     
+     /**
+      * The immutable value of this Boolean.
Index: compare/java.lang.Byte.diff
===================================================================
RCS file: java.lang.Byte.diff
diff -N java.lang.Byte.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.Byte.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Byte.java	Mon Jul 23 14:21:55 2001
++++ java/lang/Byte.java	Fri Oct 26 16:18:42 2001
+@@ -57,7 +57,7 @@
+    * The primitive type <code>byte</code> is represented by this 
+    * <code>Class</code> object.
+    */
+-  public static final Class TYPE = VMClassLoader.getPrimitiveClass("byte");
++  public static final Class TYPE = VMClassLoader.getPrimitiveClass('B');
+ 
+   /**
+    * The immutable value of this Byte.
Index: compare/java.lang.Double.diff
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/java/compare/java.lang.Double.diff,v
retrieving revision 1.1
diff -u -r1.1 java.lang.Double.diff
--- compare/java.lang.Double.diff 2001/10/16 16:38:15 1.1
+++ compare/java.lang.Double.diff 2001/11/07 01:21:24
@@ -1,49 +1,15 @@
---- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Double.java	Fri Oct 12 10:11:36 2001
-+++ java/lang/Double.java	Mon Oct 15 10:45:18 2001
-@@ -248,7 +248,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Double.java	Sun Oct 21 10:39:26 2001
++++ java/lang/Double.java	Fri Oct 26 16:18:42 2001
+@@ -80,7 +80,7 @@
+    * The primitive type <code>double</code> is represented by this
+    * <code>Class</code> object.
     */
-   public static boolean isNaN (double v)
-   {
--    return (doubleToLongBits (v) == 0x7ff8000000000000L);
-+    long bits = doubleToLongBits (v);
-+    long e = bits & 0x7ff0000000000000L;
-+    long f = bits & 0x000fffffffffffffL;
-+
-+    return e == 0x7ff0000000000000L && f != 0L;
-   }
+-  public static final Class TYPE = VMClassLoader.getPrimitiveClass ("double");
++  public static final Class TYPE = VMClassLoader.getPrimitiveClass('D');
  
    /**
-@@ -273,7 +277,10 @@
-    */
-   public static boolean isInfinite (double v)
-   {
--    return (v == POSITIVE_INFINITY || v == NEGATIVE_INFINITY);
-+    long bits = doubleToLongBits (v);
-+    long f = bits & 0x7fffffffffffffffL;
-+
-+    return f == 0x7ff0000000000000L;
-   }
- 
-   /**
-@@ -324,14 +331,14 @@
-       return isNaN (y) ? 0 : 1;
-     if (isNaN (y))
-       return -1;
--    if ((x == 0.0d) && (y == -0.0d))
-+    if (x == 0.0d && y == -0.0d)
-       return 1;
--    if ((x == -0.0d) && (y == 0.0d))
-+    if (x == -0.0d && y == 0.0d)
-       return -1;
-     if (x == y)
-       return 0;
- 
--    return (x > y) ? 1 : -1;
-+    return x > y ? 1 : -1;
-   }
- 
-   /**
-@@ -494,18 +501,12 @@
+    * The immutable value of this Double.
+@@ -504,13 +504,7 @@
     * @see #NEGATIVE_INFINITY
     * @since 1.2
     */
@@ -58,9 +24,3 @@
      throws NumberFormatException;
  
    /**
-    * Initialize JNI cache.  This method is called only by the 
-    * static initializer when using JNI.
-    */
--  private static native void initIDs ();
-+  private static void initIDs () { /* Not used in libgcj */ };
- }
Index: compare/java.lang.Float.diff
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/java/compare/java.lang.Float.diff,v
retrieving revision 1.1
diff -u -r1.1 java.lang.Float.diff
--- compare/java.lang.Float.diff 2001/10/16 16:38:15 1.1
+++ compare/java.lang.Float.diff 2001/11/07 01:21:24
@@ -1,59 +1,11 @@
---- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Float.java	Fri Oct 12 10:11:36 2001
-+++ java/lang/Float.java	Mon Oct 15 10:45:18 2001
-@@ -221,7 +221,12 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Float.java	Sun Oct 21 10:39:27 2001
++++ java/lang/Float.java	Fri Oct 26 16:18:42 2001
+@@ -79,7 +79,7 @@
+    * The primitive type <code>float</code> is represented by this 
+    * <code>Class</code> object.
     */
-   public boolean equals (Object obj)
-   {
--    return (obj instanceof Float && ((Float) obj).value == value);
-+    if (!(obj instanceof Float))
-+      return false;
-+
-+    Float f = (Float) obj;
-+
-+    return floatToIntBits (value) == floatToIntBits (f.floatValue ());
-   }
+-  public static final Class TYPE = VMClassLoader.getPrimitiveClass ("float");
++  public static final Class TYPE = VMClassLoader.getPrimitiveClass('F');
  
    /**
-@@ -359,7 +364,11 @@
-    */
-   public static boolean isNaN (float v)
-   {
--    return (floatToIntBits (v) == 0x7fc00000);
-+    int bits = floatToIntBits (v);
-+    int e = bits & 0x7f800000;
-+    int f = bits & 0x007fffff;
-+
-+    return e == 0x7f800000 && f != 0;
-   }
- 
-   /**
-@@ -384,7 +393,10 @@
-    */
-   public static boolean isInfinite (float v)
-   {
--    return (v == POSITIVE_INFINITY || v == NEGATIVE_INFINITY);
-+    int bits = floatToIntBits (v);
-+    int f = bits & 0x7fffffff;
-+
-+    return f == 0x7f800000;
-   }
- 
-   /**
-@@ -469,14 +481,14 @@
-       return isNaN (y) ? 0 : 1;
-     if (isNaN (y))
-       return -1;
--    if ((x == 0.0) && (y == -0.0))
-+    if (x == 0.0 && y == -0.0)
-       return 1;
--    if ((x == -0.0) && (y == 0.0))
-+    if (x == -0.0 && y == 0.0)
-       return -1;
-     if (x == y)
-       return 0;
- 
--    return (x > y) ? 1 : -1;
-+    return x > y ? 1 : -1;
-   }
- 
-   /**
+    * The immutable value of this Float.
Index: compare/java.lang.Integer.diff
===================================================================
RCS file: java.lang.Integer.diff
diff -N java.lang.Integer.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.Integer.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Integer.java	Mon Jul 30 12:07:52 2001
++++ java/lang/Integer.java	Fri Oct 26 16:18:42 2001
+@@ -58,7 +58,7 @@
+    * The primitive type <code>int</code> is represented by this 
+    * <code>Class</code> object.
+    */
+-  public static final Class TYPE = VMClassLoader.getPrimitiveClass ("int");
++  public static final Class TYPE = VMClassLoader.getPrimitiveClass ('I');
+ 
+   /**
+    * The immutable value of this Integer.
Index: compare/java.lang.Long.diff
===================================================================
RCS file: java.lang.Long.diff
diff -N java.lang.Long.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.Long.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Long.java	Mon Jul 23 14:15:25 2001
++++ java/lang/Long.java	Fri Oct 26 16:18:42 2001
+@@ -60,7 +60,7 @@
+    * The primitive type <code>long</code> is represented by this 
+    * <code>Class</code> object.
+    */
+-  public static final Class TYPE = VMClassLoader.getPrimitiveClass ("long");
++  public static final Class TYPE = VMClassLoader.getPrimitiveClass ('J');
+ 
+   /**
+    * The immutable value of this Long.
Index: compare/java.lang.Package.diff
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/java/compare/java.lang.Package.diff,v
retrieving revision 1.4
diff -u -r1.4 java.lang.Package.diff
--- compare/java.lang.Package.diff 2001/10/08 21:11:33 1.4
+++ compare/java.lang.Package.diff 2001/11/07 01:21:24
@@ -1,5 +1,14 @@
 --- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Package.java	Sun Oct  7 14:45:48 2001
-+++ java/lang/Package.java	Sun Oct  7 15:24:03 2001
++++ java/lang/Package.java	Fri Nov  2 21:44:51 2001
+@@ -39,7 +39,7 @@
+  * <a href="http://java.sun.com/products/jdk/1.3/docs/guide/versioning/spec/VersioningSpecification.html";>Product Versioning Specification</a>.
+  * It also allows packages to be sealed with respect to the originating URL.
+  * <p>
+- * The most usefull method is the <code>isCompatibleWith()</code> method that
++ * The most useful method is the <code>isCompatibleWith()</code> method that
+  * compares a desired version of a specification with the version of the
+  * specification as implemented by a package. A package is considered
+  * compatible with another version if the version of the specification is
 @@ -235,7 +235,8 @@
    public static Package getPackage(String name)
    {
Index: compare/java.lang.Short.diff
===================================================================
RCS file: java.lang.Short.diff
diff -N java.lang.Short.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.Short.diff Tue Nov 6 17:21:24 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Short.java	Mon Jul 23 14:15:25 2001
++++ java/lang/Short.java	Fri Oct 26 16:18:42 2001
+@@ -56,7 +56,7 @@
+    * The primitive type <code>short</code> is represented by this 
+    * <code>Class</code> object.
+    */
+-  public static final Class TYPE = VMClassLoader.getPrimitiveClass("short");
++  public static final Class TYPE = VMClassLoader.getPrimitiveClass('S');
+ 
+   /**
+    * The immutable value of this Short.
Index: compare/java.lang.Void.diff
===================================================================
RCS file: java.lang.Void.diff
diff -N java.lang.Void.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.Void.diff Tue Nov 6 17:21:25 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/Void.java	Mon Oct  1 14:44:13 2001
++++ java/lang/Void.java	Fri Oct 26 16:18:42 2001
+@@ -47,7 +47,7 @@
+    * The return type <code>void</code> is represented by this 
+    * <code>Class</code> object.
+    */
+-  public static final Class TYPE = VMClassLoader.getPrimitiveClass("void");
++  public static final Class TYPE = VMClassLoader.getPrimitiveClass('V');
+ 
+   /**
+    * Don't allow Void objects to be made.
Index: compare/java.lang.reflect.AccessibleObject.diff
===================================================================
RCS file: java.lang.reflect.AccessibleObject.diff
diff -N java.lang.reflect.AccessibleObject.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.reflect.AccessibleObject.diff Tue Nov 6 17:21:25 2001
@@ -0,0 +1,193 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/reflect/AccessibleObject.java	Sun Oct 21 10:39:27 2001
++++ java/lang/reflect/AccessibleObject.java	Mon Oct 15 16:07:13 2001
+@@ -1,5 +1,5 @@
+ /* java.lang.reflect.AccessibleObject
+-   Copyright (C) 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -7,7 +7,7 @@
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+-
++ 
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@@ -24,146 +24,54 @@
+ This exception does not however invalidate any other reasons why the
+ executable file might be covered by the GNU General Public License. */
+ 
+-
++ 
+ package java.lang.reflect;
+ 
+ /**
+- * This class is the superclass of various reflection classes, and
+- * allows sufficiently trusted code to bypass normal restrictions to
+- * do necessary things like invoke private methods outside of the
+- * class during Serialization.  If you don't have a good reason
+- * to mess with this, don't try. Fortunately, there are adequate
+- * security checks before you can set a reflection object as accessible.
+- *
+  * @author Tom Tromey <tromey@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Field
+- * @see Constructor
+- * @see Method
+- * @see ReflectPermission
+- * @since 1.2
+- * @status updated to 1.4
++ * @date December 12, 1998
++ */
++/* Written using JDK 1.2 beta docs.
++ * Status:  Believed complete and correct.
+  */
++
+ public class AccessibleObject
+ {
+-  /**
+-   * True if this object is marked accessible, which means the reflected
+-   * object bypasses normal security checks. <em>NOTE</em>Don't try messing
+-   * with this by reflection.  You'll mess yourself up.
+-   */
+-  // default visibility for use by inherited classes
+-  boolean flag = false;
+-
+-  /**
+-   * Only the three reflection classes that extend this can create an
+-   * accessible object.  This is not serializable for security reasons.
+-   */
+-  protected AccessibleObject()
++  protected AccessibleObject ()
+   {
++    flag = false;
+   }
+ 
+-  /**
+-   * Return the accessibility status of this object.
+-   *
+-   * @return true if this object bypasses security checks
+-   */
+-  public boolean isAccessible()
++  public boolean isAccessible ()
+   {
+     return flag;
+   }
+ 
+-  /**
+-   * Convenience method to set the flag on a number of objects with a single
+-   * security check. If a security manager exists, it is checked for
+-   * <code>ReflectPermission("suppressAccessChecks")</code>.<p>
+-   *
+-   * If <code>flag</code> is true, and the initial security check succeeds,
+-   * this can still fail if a forbidden object is encountered, leaving the
+-   * array half-modified. At the moment, the forbidden members are:<br>
+-   * <ul>
+-   *  <li>Any Constructor for java.lang.Class</li>
+-   *  <li>Any AccessibleObject for java.lang.reflect.AccessibleObject
+-   *      (this is not specified by Sun, but it closes a big security hole
+-   *      where you can use reflection to bypass the security checks that
+-   *      reflection is supposed to provide)</li>
+-   * </ul>
+-   * (Sun has not specified others, but good candidates might include
+-   * ClassLoader, String, and such. However, the more checks we do, the
+-   * slower this method gets).
+-   *
+-   * @param array the array of accessible objects
+-   * @param flag the desired state of accessibility, true to bypass security
+-   * @throws NullPointerException if array is null
+-   * @throws SecurityException if the request is denied
+-   * @see SecurityManager#checkPermission(java.security.Permission)
+-   * @see RuntimePermission
+-   */
+-  public static void setAccessible(AccessibleObject[] array, boolean flag)
++  public static void setAccessible (AccessibleObject[] array, boolean flag)
+   {
+-    checkPermission();
+-    for (int i = 0; i < array.length; i++)
+-      array[i].secureSetAccessible(flag);
+-  }
+-
+-  /**
+-   * Sets the accessibility flag for this reflection object. If a security
+-   * manager exists, it is checked for
+-   * <code>ReflectPermission("suppressAccessChecks")</code>.<p>
+-   *
+-   * If <code>flag</code> is true, and the initial security check succeeds,
+-   * this will still fail for a forbidden object. At the moment, the
+-   * forbidden members are:<br>
+-   * <ul>
+-   *  <li>Any Constructor for java.lang.Class</li>
+-   *  <li>Any AccessibleObject for java.lang.reflect.AccessibleObject
+-   *      (this is not specified by Sun, but it closes a big security hole
+-   *      where you can use reflection to bypass the security checks that
+-   *      reflection is supposed to provide)</li>
+-   * </ul>
+-   * (Sun has not specified others, but good candidates might include
+-   * ClassLoader, String, and such. However, the more checks we do, the
+-   * slower this method gets).
+-   *
+-   * @param flag the desired state of accessibility, true to bypass security
+-   * @throws NullPointerException if array is null
+-   * @throws SecurityException if the request is denied
+-   * @see SecurityManager#checkPermission(java.security.Permission)
+-   * @see RuntimePermission
+-   */
+-  public void setAccessible(boolean flag)
+-  {
+-    checkPermission();
+-    secureSetAccessible(flag);
++    checkPermission ();
++    // FIXME: check for invalid changes in the loop.
++    // For instance, can't set this flag to true for a Constructor for
++    // Class (example from the manual).
++    for (int i = 0; i < array.length; ++i)
++      array[i].flag = flag;
++  }
++
++  public void setAccessible (boolean flag)
++  {
++    checkPermission ();
++    // FIXME: check for invalid changes.
++    // For instance, can't set this flag to true for a Constructor for
++    // Class (example from the manual).
++    this.flag = flag;
+   }
+ 
+-  /**
+-   * Performs the specified security check, for
+-   * <code>ReflectPermission("suppressAccessChecks")</code>.
+-   *
+-   * @throws SecurityException if permission is denied
+-   */
+-  private static final void checkPermission()
++  private static final void checkPermission ()
+   {
+     SecurityManager sm = System.getSecurityManager();
+     if (sm != null)
+-      sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
++      sm.checkPermission (new ReflectPermission ("suppressAccessChecks"));
+   }
+ 
+-  /**
+-   * Performs the actual accessibility change, this must always be invoked
+-   * after calling checkPermission.
+-   *
+-   * @param flag the desired status
+-   * @throws SecurityException if flag is true and this is one of the
+-   *         forbidden members mentioned in {@link setAccessible(boolean)}.
+-   */
+-  private final void secureSetAccessible(boolean flag)
+-  {
+-    if (flag &&
+-        ((this instanceof Constructor
+-          && ((Constructor) this).getDeclaringClass() == Class.class)
+-         || ((Member) this).getDeclaringClass() == AccessibleObject.class))
+-      throw new SecurityException("Cannot make object accessible: " + this);
+-    this.flag = flag;
+-  }
++  private boolean flag;
+ }
Index: compare/java.lang.reflect.InvocationTargetException.diff
===================================================================
RCS file: java.lang.reflect.InvocationTargetException.diff
diff -N java.lang.reflect.InvocationTargetException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.reflect.InvocationTargetException.diff Tue Nov 6 17:21:25 2001
@@ -0,0 +1,162 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/reflect/InvocationTargetException.java	Sun Oct 21 10:39:27 2001
++++ java/lang/reflect/InvocationTargetException.java	Sat Sep  1 23:15:53 2001
+@@ -30,62 +30,45 @@
+ import java.io.PrintStream;
+ import java.io.PrintWriter;
+ 
++/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
++ * "The Java Language Specification", ISBN 0-201-63451-1
++ * Status:  Believed complete and correct.
++ */
++
+ /**
+  * InvocationTargetException is sort of a way to "wrap" whatever exception 
+- * comes up when a method or constructor is called via Reflection. As of
+- * JDK 1.4, it was retrofitted to match the exception chaining of all other
+- * exceptions, but <code>getTargetException()</code> still works.
++ * comes up when a method or constructor is called via Reflection.
+  *
+  * @author John Keiser
++ * @version 1.1.0, 31 May 1998
+  * @author Tom Tromey <tromey@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
++ * @date December 12, 1998
++ *
+  * @see Method#invoke(Object,Object[])
+  * @see Constructor#newInstance(Object[])
+- * @since 1.1
+- * @status stuck at 1.3; awaiting exception chaining in Throwable
+  */
+ 
+-public class InvocationTargetException
+-  extends Exception 
++public class InvocationTargetException extends Exception 
+ {
+-  /**
+-   * Compatible with JDK 1.1.
+-   */
+-  private static final long serialVersionUID = 4085088731926701167L;
++  static final long serialVersionUID = 4085088731926701167L;
+ 
+-  /**
+-   * The chained exception. This field is only around for serial compatibility.
+-   * @serial the chained exception
+-   */
+-  private final Throwable target;
+-
+-  /**
+-   * Construct an exception with null as the cause.
+-   */
++  private Throwable target = null;
++  
+   protected InvocationTargetException() 
+-  {
+-    // XXX Use this implementation when Throwable is ready.
+-    // this(null);
+-
+-    super();
+-    target = null;
+-  }
++    {
++      super();
++    }
+   
+   /**
+    * Create an <code>InvocationTargetException</code> using another 
+    * exception.
+-   *
+    * @param targetException the exception to wrap
+    */
+   public InvocationTargetException(Throwable targetException) 
+-  {
+-    // XXX Use this implementation when Throwable is ready.
+-    // super(targetException);
+-    // target = targetException;
+-
+-    super(targetException.toString());
+-    target = targetException;
+-  }
++    {
++      super(targetException.toString());
++      target = targetException;
++    }
+   
+   /** 
+    * Create an <code>InvocationTargetException</code> using another 
+@@ -95,34 +78,51 @@
+    * @param err an extra reason for the exception-throwing
+    */
+   public InvocationTargetException(Throwable targetException, String err) 
+-  {
+-    // XXX Use this implementation when Throwable is ready.
+-    // super(err, targetException);
+-    // target = targetException;
+-
+-    super(err);
+-    target = targetException;
+-  }
+-
++    {
++      super(err);
++      target = targetException;
++    }
++  
+   /**
+    * Get the wrapped (targeted) exception.
+-   *
++   * 
+    * @return the targeted exception.
+-   * @see #getCause()
+    */
+   public Throwable getTargetException() 
+-  {
+-    return target;
+-  }
+-
+-  /**
+-   * Returns the cause of this exception (which may be null).
+-   *
+-   * @return the cause.
+-   * @since 1.4
+-   */
+-  public Throwable getCause()
+-  {
+-    return target;
+-  }
++    {
++      return target;
++    }
++
++  public void printStackTrace()
++    {
++      if (target == null)
++	super.printStackTrace();
++      else
++      {
++	System.err.print(this.getClass() + ": ");
++	target.printStackTrace();
++      }
++    }
++
++  public void printStackTrace(PrintStream ps)
++    {
++      if (target == null)
++	super.printStackTrace(ps);
++      else
++      {
++	ps.print(this.getClass() + ": ");
++	target.printStackTrace(ps);
++      }
++    }
++
++  public void printStackTrace(PrintWriter pw)
++    {
++      if (target == null)
++	super.printStackTrace(pw);
++      else
++      {
++	pw.print(this.getClass() + ": ");
++	target.printStackTrace(pw);
++      }
++    }
+ }
Index: compare/java.lang.reflect.Member.diff
===================================================================
RCS file: java.lang.reflect.Member.diff
diff -N java.lang.reflect.Member.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.reflect.Member.diff Tue Nov 6 17:21:25 2001
@@ -0,0 +1,129 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/reflect/Member.java	Sun Oct 21 10:39:27 2001
++++ java/lang/reflect/Member.java	Sun Sep 30 12:18:30 2001
+@@ -1,4 +1,4 @@
+-/* java.lang.reflect.Member - common query methods in reflection
++/* java.lang.reflect.Member
+    Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+@@ -7,7 +7,7 @@
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+-
++ 
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@@ -27,63 +27,55 @@
+ 
+ package java.lang.reflect;
+ 
++/* Written using "Java Class Libraries", 2nd edition.
++ * Status:  Believed complete and correct.
++ */
++
+ /**
+- * Member is an interface that represents any member of a class (field or
+- * method) or a constructor. You can get information about the declaring
+- * class, name or modifiers of the member with this interface.
++ * Member is an interface that represents any member of a class.
++ * i.e. a field, a method or a constructor.
++ * You can get information about the declaring class, name or modifiers of
++ * the member with this interface.
+  *
+- * @author John Keiser
+- * @author Per Bothner <bothner@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Class
+- * @see Field
+- * @see Method
+- * @see Constructor
+- * @since 1.1
+- * @status updated to 1.4
++ * @author  John Keiser
++ * @author Per Bothner <bothner@cygnus.com> 
+  */
+-public interface Member
+-{
+-  /**
+-   * Represents all members, whether public, private, protected or
+-   * package-protected, but only which are declared in this class.
+-   * Used in SecurityManager.checkMemberAccess() to determine the
+-   * type of members to access.
+-   * @see SecurityManager#checkMemberAccess()
+-   */
+-  int DECLARED = 1;
+-
+-  /**
+-   * Represents public members only, but includes all inherited members.
+-   *  Used in SecurityManager.checkMemberAccess() to determine the type of
+-   * members to access.
+-   * @see SecurityManager#checkMemberAccess()
+-   */
+-  int PUBLIC = 0;
+-
+-  /**
+-   * Gets the class that declared this member. This is not the class where
+-   * this method was called, or even the class where this Member object
+-   * came to life, but the class that declares the member this represents.
+-   *
+-   * @return the class that declared this member
+-   */
+-  Class getDeclaringClass();
+-
+-  /**
+-   * Gets the simple name of this member. This will be a valid Java
+-   * identifier, with no qualification.
+-   *
+-   * @return the name of this member
+-   */
+-  String getName();
+-
+-  /**
+-   * Gets the modifiers this member uses.  Use the <code>Modifier</code>
+-   * class to interpret the values.
+-   *
+-   * @return an integer representing the modifiers to this Member
+-   * @see Modifier
+-   */
+-  int getModifiers();
++public interface Member {
++    /**
++     * Represents all members, whether public, private, protected or
++     * package-protected.
++     * Used in java.lang.SecurityManager.checkMemberAccess() to determine the
++     * type of members to access.
++     */
++    static final int DECLARED = 1;
++
++    /**
++     * Represents public members only.  Used inr
++     * java.lang.SecurityManager.checkMemberAccess() to determine the type of
++     * members to access.
++     */
++    static final int PUBLIC = 0;
++
++    /**
++     * Gets the class that declared this member.
++     * <STRONG>It is unclear whether this returns the class that actually
++     * syntactically declared the member, or the class where the
++     * <code>Member</code> object was gotten from.</STRONG>
++     * @return the class that declared this member.
++     */
++    Class getDeclaringClass();
++
++    /**
++     * Gets the modifiers this member uses.  Use the <code>Modifier</code>
++     * class to interpret the values.
++     * @see Modifier
++     * @return an integer representing the modifiers to this Member.
++     */
++    int getModifiers();
++
++    /**
++     * Gets the name of this member.
++     * @return the name of this member.
++     */
++    String getName();
+ }
Index: compare/java.lang.reflect.Modifier.diff
===================================================================
RCS file: java.lang.reflect.Modifier.diff
diff -N java.lang.reflect.Modifier.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.reflect.Modifier.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,379 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/reflect/Modifier.java	Sun Oct 21 10:39:27 2001
++++ java/lang/reflect/Modifier.java	Fri Oct  5 08:35:35 2001
+@@ -27,6 +27,12 @@
+ 
+ package java.lang.reflect;
+ 
++/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
++ * "The Java Language Specification", ISBN 0-201-63451-1
++ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
++ * Status: Believed complete and correct to version 1.2.
++ */
++
+ /**
+  * Modifier is a helper class with static methods to determine whether an
+  * int returned from getModifiers() represents static, public, protected,
+@@ -40,13 +46,12 @@
+  *
+  * @author John Keiser
+  * @author Tom Tromey <tromey@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
++ *
+  * @see Member#getModifiers()
+  * @see Method#getModifiers()
+  * @see Field#getModifiers()
+  * @see Constructor#getModifiers()
+  * @see Class#getModifiers()
+- * @since 1.1
+  */
+ public class Modifier
+ {
+@@ -55,267 +60,226 @@
+    * worthless.  However, this function is in the 1.1 spec, so it is added
+    * for completeness.</STRONG>
+    */
+-  public Modifier()
+-  {
+-  }
++  public Modifier() {}
+ 
+-  /**
+-   * Public: accessible from any other class.
+-   */
++  /** Public: accessible from any other class. **/
+   public static final int PUBLIC = 0x0001;
+ 
+-  /**
+-   * Private: accessible only from the same enclosing class.
+-   */
++  /** Private: accessible only from the declaring class. **/
+   public static final int PRIVATE = 0x0002;
+ 
+-  /**
+-   * Protected: accessible only to subclasses, or within the package.
+-   */
++  /** Protected: accessible only to subclasses. **/
+   public static final int PROTECTED = 0x0004;
+ 
+-  /**
+-   * Static:<br><ul>
+-   * <li>Class: no enclosing instance for nested class.</li>
+-   * <li>Field or Method: can be accessed or invoked without an
+-   *     instance of the declaring class.</li>
+-   * </ul>
+-   */
++  /** Static: field or method - can be accessed or invoked without an
++      instance of the declaring class. **/
+   public static final int STATIC = 0x0008;
+ 
+-  /**
+-   * Final:<br><ul>
+-   * <li>Class: no subclasses allowed.</li>
+-   * <li>Field: cannot be changed.</li>
+-   * <li>Method: cannot be overriden.</li>
+-   * </ul>
++  /** Final:<BR>
++   * <UL>
++   * <LI> Class: no subclasses allowed. </LI>
++   * <LI> Field: cannot be changed. </LI>
++   * <LI> Method: cannot be overriden. </LI>
++   * </UL>
+    */
+   public static final int FINAL = 0x0010;
+ 
+-  /**
+-   * Synchronized: Method: lock the class while calling this method.
+-   */
++  /** Synchronized: lock the class while calling this method. **/
+   public static final int SYNCHRONIZED = 0x0020;
+ 
+-  /**
+-   * Volatile: Field: cannot be cached.
+-   */
++  /** Volatile: cannot be cached.<P> **/
+   public static final int VOLATILE = 0x0040;
+ 
+-  /**
+-   * Transient: Field: not serialized or deserialized.
+-   */
++  /** Transient: not serialized or deserialized. **/
+   public static final int TRANSIENT = 0x0080;
+ 
+-  /**
+-   * Native: Method: use JNI to call this method.
+-   */
++  /** Native: use JNI to call this method. **/
+   public static final int NATIVE = 0x0100;
+ 
+-  /**
+-   * Interface: Class: is an interface.
+-   */
++  /** Interface: is an interface. **/
+   public static final int INTERFACE = 0x0200;
+ 
+-  /**
+-   * Abstract:<br><ul>
+-   * <li>Class: may not be instantiated.</li>
+-   * <li>Method: may not be called.</li>
+-   * </ul>
+-   */
++  /** Abstract: class - may not be instantiated;
++      method - may not be called. **/
+   public static final int ABSTRACT = 0x0400;
+ 
+-  /**
+-   * Strictfp: Method: expressions are FP-strict.<p>
+-   * Also used as a modifier for classes, to mean that all initializers
+-   * and constructors are FP-strict, but does not show up in
+-   * Class.getModifiers.
+-   */
++  /** Class or method - expressions are FP-strict. **/
+   public static final int STRICT = 0x0800;
+ 
+ 
+-  /**
+-   * Super - treat invokespecial as polymorphic so that super.foo() works
+-   * according to the JLS. This is a reuse of the synchronized constant
+-   * to patch a hole in JDK 1.0. *shudder*.
+-   */
+-  static final int SUPER = 0x0020;
++  /* NOTE: THIS IS HERE BECAUSE IT IS IN THE VM SPEC.
++     I INCLUDE IT FOR COMPLETENESS.  IT ATTACHES TO A CLASS AND MEANS
++     "Treat superclasses specially in invokespecial". Note that it is the
++     same as synchronized.  Reuse of the constant.  *shudder* */
++  private static final int SUPER = 0x0020;
+ 
+-  /**
+-   * All the flags, only used by code in this package.
+-   */
++  // This can only used by other code in this package, so it is not public.
+   static final int ALL_FLAGS = 0xfff;
+ 
+-  /**
+-   * Check whether the given modifier is abstract.
++  /** Check whether the given modifier is abstract.
+    * @param mod the modifier.
+    * @return <code>true</code> if abstract, <code>false</code> otherwise.
+    */
+-  public static boolean isAbstract(int mod)
++  public static boolean isAbstract (int mod)
+   {
+     return (mod & ABSTRACT) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is final.
++  /** Check whether the given modifier is final.
+    * @param mod the modifier.
+    * @return <code>true</code> if final, <code>false</code> otherwise.
+    */
+-  public static boolean isFinal(int mod)
++  public static boolean isFinal (int mod)
+   {
+     return (mod & FINAL) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is an interface.
++  /** Check whether the given modifier is an interface.
+    * @param mod the modifier.
+    * @return <code>true</code> if an interface, <code>false</code> otherwise.
+    */
+-  public static boolean isInterface(int mod)
++  public static boolean isInterface (int mod)
+   {
+     return (mod & INTERFACE) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is native.
++  /** Check whether the given modifier is native.
+    * @param mod the modifier.
+    * @return <code>true</code> if native, <code>false</code> otherwise.
+    */
+-  public static boolean isNative(int mod)
++  public static boolean isNative (int mod)
+   {
+     return (mod & NATIVE) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is private.
++  /** Check whether the given modifier is private.
+    * @param mod the modifier.
+    * @return <code>true</code> if private, <code>false</code> otherwise.
+    */
+-  public static boolean isPrivate(int mod)
++  public static boolean isPrivate (int mod)
+   {
+     return (mod & PRIVATE) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is protected.
++  /** Check whether the given modifier is protected.
+    * @param mod the modifier.
+    * @return <code>true</code> if protected, <code>false</code> otherwise.
+    */
+-  public static boolean isProtected(int mod)
++  public static boolean isProtected (int mod)
+   {
+     return (mod & PROTECTED) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is public.
++  /** Check whether the given modifier is public.
+    * @param mod the modifier.
+    * @return <code>true</code> if public, <code>false</code> otherwise.
+    */
+-  public static boolean isPublic(int mod)
++  public static boolean isPublic (int mod)
+   {
+     return (mod & PUBLIC) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is static.
++  /** Check whether the given modifier is static.
+    * @param mod the modifier.
+    * @return <code>true</code> if static, <code>false</code> otherwise.
+    */
+-  public static boolean isStatic(int mod)
++  public static boolean isStatic (int mod)
+   {
+     return (mod & STATIC) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is strictfp.
++  /** Check whether the given modifier is strictfp.
+    * @param mod the modifier.
+    * @return <code>true</code> if strictfp, <code>false</code> otherwise.
+    */
+-  public static boolean isStrict(int mod)
++  public static boolean isStrict (int mod)
+   {
+     return (mod & STRICT) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is synchronized.
++  /** Check whether the given modifier is synchronized.
+    * @param mod the modifier.
+    * @return <code>true</code> if synchronized, <code>false</code> otherwise.
+    */
+-  public static boolean isSynchronized(int mod)
++  public static boolean isSynchronized (int mod)
+   {
+     return (mod & SYNCHRONIZED) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is transient.
++  /** Check whether the given modifier is transient.
+    * @param mod the modifier.
+    * @return <code>true</code> if transient, <code>false</code> otherwise.
+    */
+-  public static boolean isTransient(int mod)
++  public static boolean isTransient (int mod)
+   {
+     return (mod & TRANSIENT) != 0;
+   }
+ 
+-  /**
+-   * Check whether the given modifier is volatile.
++  /** Check whether the given modifier is volatile.
+    * @param mod the modifier.
+    * @return <code>true</code> if volatile, <code>false</code> otherwise.
+    */
+-  public static boolean isVolatile(int mod)
++  public static boolean isVolatile (int mod)
+   {
+     return (mod & VOLATILE) != 0;
+   }
+ 
+-  /**
+-   * Get a string representation of all the modifiers represented by the
+-   * given int. The keywords are printed in this order:
++  /** Get a string representation of all the modifiers represented by the
++   * given int.
++   * The keywords are printed in this order:
+    * <code>&lt;public|private|protected&gt; abstract static final transient
+-   * volatile native synchronized interface strictfp</code>.
++   * volatile native synchronized interface strictfp</code><P>
++   *
++   * <STRONG>This is, near as I can tell, the "canonical order" of modifiers
++   * mentioned by Sun in the reference implementation.  I have inferred this
++   * from the order of printing in the Field, Method and Constructor
++   * classes.</STRONG>
+    *
+    * @param mod the modifier.
+    * @return the String representing the modifiers.
+    */
+-  public static String toString(int mod)
++  public static String toString (int mod)
+   {
+-    return toString(mod, new StringBuffer()).toString();
++    StringBuffer r = new StringBuffer ();
++    toString(mod, r);
++    return r.toString();
+   }
+ 
+   /**
+-   * Package helper method that can take a StringBuffer.
++   * Package private helper toString() method that can take a StringBuffer.
+    * @param mod the modifier
+    * @param r the StringBuffer to which the String representation is appended
+-   * @return r, with information appended
+    */
+-  static StringBuffer toString(int mod, StringBuffer r)
++  static void toString (int mod, StringBuffer r)
+   {
+-    if (isPublic(mod))
++    if (isPublic (mod))
+       r.append("public ");
+-    if (isPrivate(mod))
+-      r.append("private ");
+-    if (isProtected(mod))
++    if (isProtected (mod))
+       r.append("protected ");
+-    if (isAbstract(mod))
++    if (isPrivate (mod))
++      r.append("private ");
++    if (isAbstract (mod))
+       r.append("abstract ");
+-    if (isStatic(mod))
++    if (isStatic (mod))
+       r.append("static ");
+-    if (isFinal(mod))
++    if (isFinal (mod))
+       r.append("final ");
+-    if (isTransient(mod))
++    if (isTransient (mod))
+       r.append("transient ");
+-    if (isVolatile(mod))
++    if (isVolatile (mod))
+       r.append("volatile ");
+-    if (isNative(mod))
++    if (isNative (mod))
+       r.append("native ");
+-    if (isSynchronized(mod))
++    if (isSynchronized (mod))
+       r.append("synchronized ");
+-    if (isInterface(mod))
++    if (isInterface (mod))
+       r.append("interface ");
+-    if (isStrict(mod))
++    if (isStrict (mod))
+       r.append("strictfp ");
+     
+     // Trim trailing space.
+-    if ((mod & ALL_FLAGS) != 0)
+-      r.setLength(r.length() - 1);
+-    return r;
++    int l = r.length();
++    if (l > 0)
++      r.setLength(l - 1);
+   }
+ }
Index: compare/java.lang.reflect.ReflectPermission.diff
===================================================================
RCS file: java.lang.reflect.ReflectPermission.diff
diff -N java.lang.reflect.ReflectPermission.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.lang.reflect.ReflectPermission.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,92 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/lang/reflect/ReflectPermission.java	Sun Oct 21 10:39:27 2001
++++ java/lang/reflect/ReflectPermission.java	Mon Feb 19 15:25:11 2001
+@@ -1,5 +1,5 @@
+ /* ReflectPermission.java - named permission for reflaction
+-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 2000, 2001  Free Software Foundation
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -7,7 +7,7 @@
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+-
++ 
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@@ -27,6 +27,7 @@
+ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+  * "The Java Language Specification", ISBN 0-201-63451-1
+  * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
++ * Status: Believed complete and correct to version 1.2.
+  */
+ 
+ package java.lang.reflect;
+@@ -35,57 +36,29 @@
+ 
+ /**
+  * This class implements permissions for reflection.  This is a named
+- * permission, and the only defined name is suppressAccessChecks, which
+- * allows suppression of normal Java objects when using reflection.
+- *
+- * <table>
+- *  <tr>
+- *   <th>Permission Target Name</th>
+- *   <th>What Permission Allows</th>
+- *   <th>Risk of Allowing Permission</th>
+- *  </tr>
+- *  <tr>
+- *   <td><code>suppressAccessChecks</code></td>
+- *   <td>Ability to access fields, invoke methods, and construct objects
+- *       via reflection, including non-public members in contexts where
+- *       such access is not legal at compile-time.</td>
+- *   <td>This is dangerous. It exposes possibly confidential information,
+- *       and malicious code could interfere with the internals of the Virtual
+- *       Machine by corrupting private data.</td>
+- *  </tr>
+- * </table>
++ * permission, and the only defined name is suppressAccessChecks.
+  *
+  * @author Tom Tromey <tromey@redhat.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @since 1.2
+- * @status updated to 1.4
++ * @date November 18, 2000
+  */
+-public final class ReflectPermission
+-  extends BasicPermission
++public final class ReflectPermission extends BasicPermission
+ {
+   /**
+-   * Compatible with JDK 1.2.
+-   */
+-  private static final long serialVersionUID = 7412737110241507485L;
+-
+-  /**
+    * Construct a ReflectPermission with the given name.
+-   *
+    * @param name The permission name
+    */
+-  public ReflectPermission(String name)
++  public ReflectPermission (String name)
+   {
+-    super(name);
++    super (name);
+   }
+ 
+   /**
+    * Construct a ReflectPermission with the given name.
+-   *
+    * @param name The permission name
+-   * @param actions The actions; this is ignored and should be null
++   * @param actions The actions; this is ignored and should be null.
+    */
+-  public ReflectPermission(String name, String actions)
++  public ReflectPermission (String name, String actions)
+   {
+-    super(name, actions);
++    super (name, actions);
+   }
+ }
Index: compare/java.net.BindException.diff
===================================================================
RCS file: java.net.BindException.diff
diff -N java.net.BindException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.net.BindException.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,17 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/net/BindException.java	Sun Apr 15 11:57:25 2001
++++ java/net/BindException.java	Fri Nov  2 21:44:51 2001
+@@ -1,4 +1,4 @@
+-/* BindException.java -- An exception occured while binding to a socket
++/* BindException.java -- An exception occurred while binding to a socket
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+@@ -33,7 +33,7 @@
+  */
+ 
+ /**
+-  * This exception indicates that an error occured while attempting to bind
++  * This exception indicates that an error occurred while attempting to bind
+   * socket to a particular port.
+   *
+   * @author Aaron M. Renn (arenn@urbanophile.com)
Index: compare/java.net.ConnectException.diff
===================================================================
RCS file: java.net.ConnectException.diff
diff -N java.net.ConnectException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.net.ConnectException.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,17 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/net/ConnectException.java	Sun Apr 15 11:57:25 2001
++++ java/net/ConnectException.java	Fri Nov  2 21:44:51 2001
+@@ -1,4 +1,4 @@
+-/* ConnectException.java -- An exception occured while connecting to a host
++/* ConnectException.java -- An exception occurred while connecting to a host
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+@@ -34,7 +34,7 @@
+  */
+ 
+ /**
+-  * This exception indicates that an error occured while attempting to
++  * This exception indicates that an error occurred while attempting to
+   * connect to a remote host.  Often this indicates that the remote host
+   * refused the connection (ie, is not listening on the target socket).
+   *
Index: compare/java.net.ProtocolException.diff
===================================================================
RCS file: java.net.ProtocolException.diff
diff -N java.net.ProtocolException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.net.ProtocolException.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,17 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/net/ProtocolException.java	Sun Apr 15 11:57:25 2001
++++ java/net/ProtocolException.java	Fri Nov  2 21:44:51 2001
+@@ -1,4 +1,4 @@
+-/* ProtocolException.java -- A low level protocol error occured
++/* ProtocolException.java -- A low level protocol error occurred
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+@@ -34,7 +34,7 @@
+ 
+ /**
+   * This exception indicates that some sort of low level protocol
+-  * exception occured.  Look in the descriptive message (if any) for
++  * exception occurred.  Look in the descriptive message (if any) for
+   * details on what went wrong
+   *
+   * @author Aaron M. Renn (arenn@urbanophile.com)
Index: compare/java.net.SocketException.diff
===================================================================
RCS file: java.net.SocketException.diff
diff -N java.net.SocketException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.net.SocketException.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,17 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/net/SocketException.java	Sun Apr 15 11:57:25 2001
++++ java/net/SocketException.java	Fri Nov  2 21:44:51 2001
+@@ -1,4 +1,4 @@
+-/* SocketException.java -- An exception occured while performing a socket op
++/* SocketException.java -- An exception occurred while performing a socket op
+    Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+@@ -31,7 +31,7 @@
+  */
+ 
+ /**
+-  * This exception indicates that a generic error occured related to an
++  * This exception indicates that a generic error occurred related to an
+   * operation on a socket.  Check the descriptive message (if any) for
+   * details on the nature of this error
+   *
Index: compare/java.net.UnknownServiceException.diff
===================================================================
RCS file: java.net.UnknownServiceException.diff
diff -N java.net.UnknownServiceException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.net.UnknownServiceException.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,8 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/net/UnknownServiceException.java	Sun Apr 15 11:57:25 2001
++++ java/net/UnknownServiceException.java	Fri Nov  2 21:44:51 2001
+@@ -1,4 +1,4 @@
+-/* UnknownServiceException.java -- A service error occured
++/* UnknownServiceException.java -- A service error occurred
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
Index: compare/java.security.SecureRandom.diff
===================================================================
RCS file: java.security.SecureRandom.diff
diff -N java.security.SecureRandom.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.security.SecureRandom.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,20 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/security/SecureRandom.java	Wed Oct 17 18:13:24 2001
++++ java/security/SecureRandom.java	Fri Nov  2 21:44:51 2001
+@@ -55,7 +55,7 @@
+      It is not seeded and should be seeded using setSeed or else
+      on the first call to getnextBytes it will force a seed.
+ 
+-     It is maintained for backwards compatability and programs
++     It is maintained for backwards compatibility and programs
+      should use getInstance.
+    */
+   public SecureRandom()
+@@ -115,7 +115,7 @@
+      It is seeded with the passed function and is useful if the user
+      has access to hardware random device (like a radiation detector).
+ 
+-     It is maintained for backwards compatability and programs
++     It is maintained for backwards compatibility and programs
+      should use getInstance.
+ 
+      @param seed Seed bytes for class
Index: compare/java.security.SignedObject.diff
===================================================================
RCS file: java.security.SignedObject.diff
diff -N java.security.SignedObject.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.security.SignedObject.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,22 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/security/SignedObject.java	Wed Sep 26 08:18:45 2001
++++ java/security/SignedObject.java	Fri Nov  2 21:44:51 2001
+@@ -80,7 +80,7 @@
+      @param signingKey the key to sign with
+      @param signingEngine the signature engine to use
+ 
+-     @throws IOException serialization error occured
++     @throws IOException serialization error occurred
+      @throws InvalidKeyException invalid key
+      @throws SignatureException signing error
+    */
+@@ -108,8 +108,8 @@
+ 
+      @return the encapsulated object
+ 
+-     @throws IOException de-serialization error occured
+-     @throws ClassNotFoundException de-serialization error occured
++     @throws IOException de-serialization error occurred
++     @throws ClassNotFoundException de-serialization error occurred
+    */
+   public Object getObject() throws IOException, ClassNotFoundException
+   {
Index: compare/java.security.cert.X509Certificate.diff
===================================================================
RCS file: java.security.cert.X509Certificate.diff
diff -N java.security.cert.X509Certificate.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.security.cert.X509Certificate.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/security/cert/X509Certificate.java	Wed Mar 22 12:26:26 2000
++++ java/security/cert/X509Certificate.java	Fri Nov  2 21:44:51 2001
+@@ -288,7 +288,7 @@
+ 
+      @return the DER encoded tbsCertificate
+ 
+-     @throws CertificateEncodingException if encoding error occured
++     @throws CertificateEncodingException if encoding error occurred
+   */
+   public abstract byte[] getTBSCertificate() throws CertificateEncodingException;
+ 
Index: compare/java.security.interfaces.DSAKey.diff
===================================================================
RCS file: java.security.interfaces.DSAKey.diff
diff -N java.security.interfaces.DSAKey.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.security.interfaces.DSAKey.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,8 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/security/interfaces/DSAKey.java	Wed Sep 26 08:18:45 2001
++++ java/security/interfaces/DSAKey.java	Fri Nov  2 21:44:51 2001
+@@ -1,4 +1,4 @@
+-/* DSAKey.java -- Interface for Digital Signature Algorith key
++/* DSAKey.java -- Interface for Digital Signature Algorithm key
+    Copyright (C) 1998 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
Index: compare/java.sql.DatabaseMetaData.diff
===================================================================
RCS file: java.sql.DatabaseMetaData.diff
diff -N java.sql.DatabaseMetaData.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.sql.DatabaseMetaData.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,44 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/sql/DatabaseMetaData.java	Sun Jan  7 16:06:09 2001
++++ java/sql/DatabaseMetaData.java	Fri Nov  2 21:44:51 2001
+@@ -47,7 +47,7 @@
+ public static final int bestRowNotPseudo = 1;
+ 
+ /**
+-  * The best row identifer is a pseudo-column.
++  * The best row identifier is a pseudo-column.
+   */
+ public static final int bestRowPseudo = 2;
+ 
+@@ -58,12 +58,12 @@
+ public static final int bestRowTemporary = 0;
+ 
+ /**
+-  * The best row identifer is valid to the end of the transaction.
++  * The best row identifier is valid to the end of the transaction.
+   */
+ public static final int bestRowTransaction = 1;
+ 
+ /**
+-  * The best row identifer is valid to the end of the session.
++  * The best row identifier is valid to the end of the session.
+   */
+ public static final int bestRowSession = 2;
+ 
+@@ -2696,7 +2696,7 @@
+   * <li>TYPE_SCEHM - The schema name, which may be <code>null</code>.
+   * <li>TYPE_NAME - The user defined data type name.
+   * <li>CLASS_NAME - The Java class name this type maps to.
+-  * <li>DATA_TYPE - A type identifer from <code>Types</code> for this type.
++  * <li>DATA_TYPE - A type identifier from <code>Types</code> for this type.
+   * This will be one of <code>JAVA_OBJECT</code>, <code>STRUCT</code>, or
+   * <code>DISTINCT</code>.
+   * <li>REMARKS - Comments about this data type.
+@@ -2708,7 +2708,7 @@
+   * @param schema The schema to retrieve information from, or the empty string
+   * to return entities not associated with a schema.
+   * @param typePattern The type name pattern to match.
+-  * @param types The type identifer patterns (from <code>Types</code>) to
++  * @param types The type identifier patterns (from <code>Types</code>) to
+   * match.
+   *
+   * @return A <code>ResultSet</code> with the requested type information
Index: compare/java.text.DecimalFormatSymbols.diff
===================================================================
RCS file: java.text.DecimalFormatSymbols.diff
diff -N java.text.DecimalFormatSymbols.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.text.DecimalFormatSymbols.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/text/DecimalFormatSymbols.java	Sun Sep  2 13:37:58 2001
++++ java/text/DecimalFormatSymbols.java	Fri Nov  2 21:44:51 2001
+@@ -476,7 +476,7 @@
+   }
+ 
+   /**
+-   * This method sets the charcter used to represen the digit zero.
++   * This method sets the character used to represent the digit zero.
+    *
+    * @param zeroDigit The character used to represent the digit zero.
+    */
Index: compare/java.util.AbstractCollection.diff
===================================================================
RCS file: java.util.AbstractCollection.diff
diff -N java.util.AbstractCollection.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.AbstractCollection.diff Tue Nov 6 17:21:26 2001
@@ -0,0 +1,505 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/AbstractCollection.java	Fri Oct 26 16:06:56 2001
++++ java/util/AbstractCollection.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,5 @@
+ /* AbstractCollection.java -- Abstract implementation of most of Collection
+-   Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -42,118 +42,77 @@
+  * backing data structure allows for a more efficient implementation. The
+  * precise implementation used by AbstractCollection is documented, so that
+  * subclasses can tell which methods could be implemented more efficiently.
+- * <p>
+- *
+- * The programmer should provide a no-argument constructor, and one that
+- * accepts another Collection, as recommended by the Collection interface.
+- * Unfortunately, there is no way to enforce this in Java.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see AbstractSet
+- * @see AbstractList
+- * @since 1.2
+- * @status updated to 1.4
+  */
+ public abstract class AbstractCollection implements Collection
+ {
+   /**
+-   * The main constructor, for use by subclasses.
+-   */
+-  protected AbstractCollection()
+-  {
+-  }
+-
+-  /**
+    * Return an Iterator over this collection. The iterator must provide the
+    * hasNext and next methods and should in addition provide remove if the
+    * collection is modifiable.
+-   *
+-   * @return an iterator
+    */
+   public abstract Iterator iterator();
+ 
+   /**
+-   * Return the number of elements in this collection. If there are more than
+-   * Integer.MAX_VALUE elements, return Integer.MAX_VALUE.
+-   *
+-   * @return the size
++   * Return the number of elements in this collection.
+    */
+   public abstract int size();
+ 
+   /**
+-   * Add an object to the collection (optional operation). This implementation
+-   * always throws an UnsupportedOperationException - it should be
+-   * overridden if the collection is to be modifiable. If the collection
+-   * does not accept duplicates, simply return false. Collections may specify
+-   * limitations on what may be added.
++   * Add an object to the collection. This implementation always throws an
++   * UnsupportedOperationException - it should be overridden if the collection
++   * is to be modifiable.
+    *
+    * @param o the object to add
+    * @return true if the add operation caused the Collection to change
+-   * @throws UnsupportedOperationException if the add operation is not
+-   *         supported on this collection
+-   * @throws NullPointerException if the collection does not support null
+-   * @throws ClassCastException if the object is of the wrong type
+-   * @throws IllegalArgumentException if some aspect of the object prevents
+-   *         it from being added
++   * @exception UnsupportedOperationException if the add operation is not
++   *   supported on this collection
+    */
+   public boolean add(Object o)
+   {
+-    throw new UnsupportedOperationException();
++    throw new java.lang.UnsupportedOperationException();
+   }
+ 
+   /**
+-   * Add all the elements of a given collection to this collection (optional
+-   * operation). This implementation obtains an Iterator over the given
+-   * collection and iterates over it, adding each element with the
+-   * add(Object) method (thus this method will fail with an
+-   * UnsupportedOperationException if the add method does). The behavior is
+-   * unspecified if the specified collection is modified during the iteration,
+-   * including the special case of trying addAll(this) on a non-empty
+-   * collection.
++   * Add all the elements of a given collection to this collection. This
++   * implementation obtains an Iterator over the given collection and iterates
++   * over it, adding each element with the add(Object) method (thus this method
++   * will fail with an UnsupportedOperationException if the add method does).
+    *
+    * @param c the collection to add the elements of to this collection
+    * @return true if the add operation caused the Collection to change
+-   * @throws UnsupportedOperationException if the add operation is not
+-   *         supported on this collection
+-   * @throws NullPointerException if this collection does not support null,
+-   *         or if the specified collection is null
+-   * @throws ClassCastException if an object in c is of the wrong type
+-   * @throws IllegalArgumentException if some aspect of an object in c prevents
+-   *         it from being added
+-   * @see #add(Object)
++   * @exception UnsupportedOperationException if the add operation is not
++   *   supported on this collection
+    */
+   public boolean addAll(Collection c)
+   {
+     Iterator itr = c.iterator();
++    int size = c.size();
+     boolean modified = false;
+-    int pos = size();
+-    while (--pos >= 0)
+-      modified |= add(itr.next());
++    for (int pos = 0; pos < size; pos++)
++      {
++	modified |= add(itr.next());
++      }
+     return modified;
+   }
+ 
+   /**
+-   * Remove all elements from the collection (optional operation). This
+-   * implementation obtains an iterator over the collection and calls next
+-   * and remove on it repeatedly (thus this method will fail with an
+-   * UnsupportedOperationException if the Iterator's remove method does)
+-   * until there are no more elements to remove.
++   * Remove all elements from the collection. This implementation obtains an
++   * iterator over the collection and calls next and remove on it repeatedly
++   * (thus this method will fail with an UnsupportedOperationException if the
++   * Iterator's remove method does) until there are no more elements to remove.
+    * Many implementations will have a faster way of doing this.
+    *
+-   * @throws UnsupportedOperationException if the Iterator returned by
+-   *         iterator does not provide an implementation of remove
+-   * @see Iterator#remove()
++   * @exception UnsupportedOperationException if the Iterator returned by
++   *   iterator does not provide an implementation of remove
+    */
+   public void clear()
+   {
+     Iterator itr = iterator();
+-    int pos = size();
+-    while (--pos >= 0)
++    int size = size();
++    for (int pos = 0; pos < size; pos++)
+       {
+-        itr.next();
+-        itr.remove();
++	itr.next();
++	itr.remove();
+       }
+   }
+ 
+@@ -171,10 +130,12 @@
+   public boolean contains(Object o)
+   {
+     Iterator itr = iterator();
+-    int pos = size();
+-    while (--pos >= 0)
+-      if (equals(o, itr.next()))
+-        return true;
++    int size = size();
++    for (int pos = 0; pos < size; pos++)
++      {
++	if (o == null ? itr.next() == null : o.equals(itr.next()))
++	  return true;
++      }
+     return false;
+   }
+ 
+@@ -186,17 +147,17 @@
+    *
+    * @param c the collection to test against
+    * @return true if this collection contains all the elements in the given
+-   *         collection
+-   * @throws NullPointerException if the given collection is null
+-   * @see #contains(Object)
++   *   collection
+    */
+   public boolean containsAll(Collection c)
+   {
+     Iterator itr = c.iterator();
+-    int pos = size();
+-    while (--pos >= 0)
+-      if (!contains(itr.next()))
+-        return false;
++    int size = c.size();
++    for (int pos = 0; pos < size; pos++)
++      {
++	if (!contains(itr.next()))
++	  return false;
++      }
+     return true;
+   }
+ 
+@@ -205,7 +166,6 @@
+    * size() == 0.
+    *
+    * @return true if this collection is empty.
+-   * @see #size()
+    */
+   public boolean isEmpty()
+   {
+@@ -213,131 +173,92 @@
+   }
+ 
+   /**
+-   * Remove a single instance of an object from this collection (optional
+-   * operation). That is, remove one element e such that
+-   * <code>(o == null ? e == null : o.equals(e))</code>, if such an element
+-   * exists. This implementation obtains an iterator over the collection
+-   * and iterates over it, testing each element for equality with the given
+-   * object. If it is equal, it is removed by the iterator's remove method
+-   * (thus this method will fail with an UnsupportedOperationException if
+-   * the Iterator's remove method does). After the first element has been
++   * Remove a single instance of an object from this collection. That is,
++   * remove one element e such that (o == null ? e == null : o.equals(e)), if
++   * such an element exists. This implementation obtains an iterator over the
++   * collection and iterates over it, testing each element for equality with
++   * the given object. If it is equal, it is removed by the iterator's remove
++   * method (thus this method will fail with an UnsupportedOperationException
++   * if the Iterator's remove method does). After the first element has been
+    * removed, true is returned; if the end of the collection is reached, false
+    * is returned.
+    *
+    * @param o the object to remove from this collection
+    * @return true if the remove operation caused the Collection to change, or
+-   *         equivalently if the collection did contain o.
+-   * @throws UnsupportedOperationException if this collection's Iterator
+-   *         does not support the remove method
+-   * @see Iterator#remove()
++   *   equivalently if the collection did contain o.
++   * @exception UnsupportedOperationException if this collection's Iterator
++   *   does not support the remove method
+    */
+   public boolean remove(Object o)
+   {
+     Iterator itr = iterator();
+-    int pos = size();
+-    while (--pos >= 0)
+-      if (equals(o, itr.next()))
+-        {
+-          itr.remove();
+-          return true;
+-        }
++    int size = size();
++    for (int pos = 0; pos < size; pos++)
++      {
++	if (o == null ? itr.next() == null : o.equals(itr.next()))
++	  {
++	    itr.remove();
++	    return true;
++	  }
++      }
+     return false;
+   }
+ 
+   /**
+    * Remove from this collection all its elements that are contained in a given
+-   * collection (optional operation). This implementation iterates over this
+-   * collection, and for each element tests if it is contained in the given
+-   * collection. If so, it is removed by the Iterator's remove method (thus
+-   * this method will fail with an UnsupportedOperationException if the
+-   * Iterator's remove method does).
++   * collection. This implementation iterates over this collection, and for
++   * each element tests if it is contained in the given collection. If so, it
++   * is removed by the Iterator's remove method (thus this method will fail
++   * with an UnsupportedOperationException if the Iterator's remove method
++   * does).
+    *
+    * @param c the collection to remove the elements of
+    * @return true if the remove operation caused the Collection to change
+-   * @throws UnsupportedOperationException if this collection's Iterator
+-   *         does not support the remove method
+-   * @see Iterator#remove()
++   * @exception UnsupportedOperationException if this collection's Iterator
++   *   does not support the remove method
+    */
+   public boolean removeAll(Collection c)
+   {
+-    return removeAllInternal(c);
+-  }
+-
+-  /**
+-   * Remove from this collection all its elements that are contained in a given
+-   * collection (optional operation). This implementation iterates over this
+-   * collection, and for each element tests if it is contained in the given
+-   * collection. If so, it is removed by the Iterator's remove method (thus
+-   * this method will fail with an UnsupportedOperationException if the
+-   * Iterator's remove method does). This method is necessary for ArrayList,
+-   * which cannot publicly override removeAll but can optimize this call.
+-   *
+-   * @param c the collection to remove the elements of
+-   * @return true if the remove operation caused the Collection to change
+-   * @throws UnsupportedOperationException if this collection's Iterator
+-   *         does not support the remove method
+-   * @see Iterator#remove()
+-   */
+-  boolean removeAllInternal(Collection c)
+-  {
+     Iterator itr = iterator();
++    int size = size();
+     boolean modified = false;
+-    int pos = size();
+-    while (--pos >= 0)
+-      if (c.contains(itr.next()))
+-        {
+-          itr.remove();
+-          modified = true;
+-        }
++    for (int pos = 0; pos < size; pos++)
++      {
++	if (c.contains(itr.next()))
++	  {
++	    itr.remove();
++	    modified = true;
++	  }
++      }
+     return modified;
+   }
+ 
+   /**
+    * Remove from this collection all its elements that are not contained in a
+-   * given collection (optional operation). This implementation iterates over
+-   * this collection, and for each element tests if it is contained in the
+-   * given collection. If not, it is removed by the Iterator's remove method
+-   * (thus this method will fail with an UnsupportedOperationException if
+-   * the Iterator's remove method does).
++   * given collection. This implementation iterates over this collection, and
++   * for each element tests if it is contained in the given collection. If not,
++   * it is removed by the Iterator's remove method (thus this method will fail
++   * with an UnsupportedOperationException if the Iterator's remove method
++   * does).
+    *
+    * @param c the collection to retain the elements of
+    * @return true if the remove operation caused the Collection to change
+-   * @throws UnsupportedOperationException if this collection's Iterator
+-   *         does not support the remove method
+-   * @see Iterator#remove()
++   * @exception UnsupportedOperationException if this collection's Iterator
++   *   does not support the remove method
+    */
+   public boolean retainAll(Collection c)
+   {
+-    return retainAllInternal(c);
+-  }
+-
+-  /**
+-   * Remove from this collection all its elements that are not contained in a
+-   * given collection (optional operation). This implementation iterates over
+-   * this collection, and for each element tests if it is contained in the
+-   * given collection. If not, it is removed by the Iterator's remove method
+-   * (thus this method will fail with an UnsupportedOperationException if
+-   * the Iterator's remove method does). This method is necessary for
+-   * ArrayList, which cannot publicly override retainAll but can optimize
+-   * this call.
+-   *
+-   * @param c the collection to retain the elements of
+-   * @return true if the remove operation caused the Collection to change
+-   * @throws UnsupportedOperationException if this collection's Iterator
+-   *         does not support the remove method
+-   * @see Iterator#remove()
+-   */
+-  boolean retainAllInternal(Collection c)
+-  {
+     Iterator itr = iterator();
++    int size = size();
+     boolean modified = false;
+-    int pos = size();
+-    while (--pos >= 0)
+-      if (!c.contains(itr.next()))
+-        {
+-          itr.remove();
+-          modified = true;
+-        }
++    for (int pos = 0; pos < size; pos++)
++      {
++	if (!c.contains(itr.next()))
++	  {
++	    itr.remove();
++	    modified = true;
++	  }
++      }
+     return modified;
+   }
+ 
+@@ -345,18 +266,18 @@
+    * Return an array containing the elements of this collection. This
+    * implementation creates an Object array of size size() and then iterates
+    * over the collection, setting each element of the array from the value
+-   * returned by the iterator. The returned array is safe, and is not backed
+-   * by the collection.
++   * returned by the iterator.
+    *
+    * @return an array containing the elements of this collection
+    */
+   public Object[] toArray()
+   {
+     Iterator itr = iterator();
+-    int size = size();
+-    Object[] a = new Object[size];
+-    for (int pos = 0; pos < size; pos++)
+-      a[pos] = itr.next();
++    Object[]a = new Object[size()];
++    for (int pos = 0; pos < a.length; pos++)
++      {
++	a[pos] = itr.next();
++      }
+     return a;
+   }
+ 
+@@ -372,29 +293,29 @@
+    * obtained over the collection and the elements are placed in the array as
+    * they are returned by the iterator. Finally the first spare element, if
+    * any, of the array is set to null, and the created array is returned.
+-   * The returned array is safe; it is not backed by the collection. Note that
+-   * null may not mark the last element, if the collection allows null
+-   * elements.
+    *
+    * @param a the array to copy into, or of the correct run-time type
+    * @return the array that was produced
+-   * @throws NullPointerException if the given array is null
+-   * @throws ArrayStoreException if the type of the array precludes holding
+-   *         one of the elements of the Collection
++   * @exception ClassCastException if the type of the array precludes holding
++   *   one of the elements of the Collection
+    */
+-  public Object[] toArray(Object[] a)
++  public Object[] toArray(Object[]a)
+   {
+     int size = size();
+     if (a.length < size)
+-      a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
+-                                       size);
+-    else if (a.length > size)
+-      a[size] = null;
+-
++      {
++	a = (Object[])Array.newInstance(a.getClass().getComponentType(),
++					size);
++      }
+     Iterator itr = iterator();
+     for (int pos = 0; pos < size; pos++)
+-      a[pos] = itr.next();
+-
++      {
++	a[pos] = itr.next();
++      }
++    if (a.length > size)
++      {
++	a[size] = null;
++      }
+     return a;
+   }
+ 
+@@ -410,41 +331,15 @@
+   public String toString()
+   {
+     Iterator itr = iterator();
++    int size = size();
+     StringBuffer r = new StringBuffer("[");
+-    for (int pos = size(); pos > 0; pos--)
++    for (int pos = 0; pos < size; pos++)
+       {
+-        r.append(itr.next());
+-        if (pos > 1)
+-          r.append(", ");
++	r.append(itr.next());
++	if (pos < size - 1)
++	  r.append(", ");
+       }
+     r.append("]");
+     return r.toString();
+-  }
+-
+-  /**
+-   * Compare two objects according to Collection semantics.
+-   *
+-   * @param o1 the first object
+-   * @param o2 the second object
+-   * @return o1 == null ? o2 == null : o1.equals(o2)
+-   */
+-  // Package visible for use throughout java.util.
+-  // It may be inlined since it is final.
+-  static final boolean equals(Object o1, Object o2)
+-  {
+-    return o1 == null ? o2 == null : o1.equals(o2);
+-  }
+-
+-  /**
+-   * Hash an object according to Collection semantics.
+-   *
+-   * @param o the object to hash
+-   * @return o1 == null ? 0 : o1.hashCode()
+-   */
+-  // Package visible for use throughout java.util.
+-  // It may be inlined since it is final.
+-  static final int hashCode(Object o)
+-  {
+-    return o == null ? 0 : o.hashCode();
+   }
+ }
Index: compare/java.util.AbstractList.diff
===================================================================
RCS file: java.util.AbstractList.diff
diff -N java.util.AbstractList.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.AbstractList.diff Tue Nov 6 17:21:27 2001
@@ -0,0 +1,1089 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/AbstractList.java	Fri Oct 26 16:06:56 2001
++++ java/util/AbstractList.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,5 @@
+ /* AbstractList.java -- Abstract implementation of most of List
+-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -25,191 +25,67 @@
+ executable file might be covered by the GNU General Public License. */
+ 
+ 
++// TO DO:
++// ~ Doc comments for almost everything.
++// ~ Better general commenting
++
+ package java.util;
+ 
+ /**
+  * A basic implementation of most of the methods in the List interface to make
+- * it easier to create a List based on a random-access data structure. If
+- * the list is sequential (such as a linked list), use AbstractSequentialList.
+- * To create an unmodifiable list, it is only necessary to override the
+- * size() and get(int) methods (this contrasts with all other abstract
+- * collection classes which require an iterator to be provided). To make the
+- * list modifiable, the set(int, Object) method should also be overridden, and
+- * to make the list resizable, the add(int, Object) and remove(int) methods
+- * should be overridden too. Other methods should be overridden if the
+- * backing data structure allows for a more efficient implementation.
+- * The precise implementation used by AbstractList is documented, so that
+- * subclasses can tell which methods could be implemented more efficiently.
+- * <p>
+- *
+- * As recommended by Collection and List, the subclass should provide at
+- * least a no-argument and a Collection constructor. This class is not
+- * synchronized.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see List
+- * @see AbstractSequentialList
+- * @see AbstractCollection
+- * @see ListIterator
+- * @since 1.2
+- * @status updated to 1.4
++ * it easier to create a List based on a random-access data structure. To
++ * create an unmodifiable list, it is only necessary to override the size() and
++ * get(int) methods (this contrasts with all other abstract collection classes
++ * which require an iterator to be provided). To make the list modifiable, the
++ * set(int, Object)  method should also be overridden, and to make the list
++ * resizable, the add(int, Object) and remove(int) methods should be overridden
++ * too. Other methods should be overridden if the backing data structure allows
++ * for a more efficient implementation. The precise implementation used by
++ * AbstractList is documented, so that subclasses can tell which methods could
++ * be implemented more efficiently.
+  */
+ public abstract class AbstractList extends AbstractCollection implements List
+ {
+   /**
+    * A count of the number of structural modifications that have been made to
+-   * the list (that is, insertions and removals). Structural modifications
+-   * are ones which change the list size or affect how iterations would
+-   * behave. This field is available for use by Iterator and ListIterator,
+-   * in order to throw a {@link ConcurrentModificationException} in response
+-   * to the next operation on the iterator. This <i>fail-fast</i> behavior
+-   * saves the user from many subtle bugs otherwise possible from concurrent
+-   * modification during iteration.
+-   * <p>
+-   *
+-   * To make lists fail-fast, increment this field by just 1 in the
+-   * <code>add(int, Object)</code> and <code>remove(int)</code> methods.
+-   * Otherwise, this field may be ignored.
+-   */
+-  protected int modCount;
+-
+-  /**
+-   * The main constructor, for use by subclasses.
++   * the list (that is, insertions and removals).
+    */
+-  protected AbstractList()
+-  {
+-  }
++  protected transient int modCount = 0;
+ 
+-  /**
+-   * Returns the elements at the specified position in the list.
+-   *
+-   * @param index the element to return
+-   * @return the element at that position
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   */
+   public abstract Object get(int index);
+ 
+-  /**
+-   * Insert an element into the list at a given position (optional operation).
+-   * This shifts all existing elements from that position to the end one
+-   * index to the right.  This version of add has no return, since it is
+-   * assumed to always succeed if there is no exception. This implementation
+-   * always throws UnsupportedOperationException, and must be overridden to
+-   * make a modifiable List.  If you want fail-fast iterators, be sure to
+-   * increment modCount when overriding this.
+-   *
+-   * @param index the location to insert the item
+-   * @param o the object to insert
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         add operation
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
+-   * @throws ClassCastException if o cannot be added to this list due to its
+-   *         type
+-   * @throws IllegalArgumentException if o cannot be added to this list for
+-   *         some other reason
+-   * @see #modCount
+-   */
+   public void add(int index, Object o)
+   {
+     throw new UnsupportedOperationException();
+   }
+ 
+-  /**
+-   * Add an element to the end of the list (optional operation). If the list
+-   * imposes restraints on what can be inserted, such as no null elements,
+-   * this should be documented. This implementation calls
+-   * <code>add(size(), o);</code>, and will fail if that version does.
+-   *
+-   * @param o the object to add
+-   * @return true, as defined by Collection for a modified list
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         add operation
+-   * @throws ClassCastException if o cannot be added to this list due to its
+-   *         type
+-   * @throws IllegalArgumentException if o cannot be added to this list for
+-   *         some other reason
+-   * @see #add(int, Object)
+-   */
+   public boolean add(Object o)
+   {
+     add(size(), o);
+     return true;
+   }
+ 
+-  /**
+-   * Insert the contents of a collection into the list at a given position
+-   * (optional operation). Shift all elements at that position to the right
+-   * by the number of elements inserted. This operation is undefined if
+-   * this list is modified during the operation (for example, if you try
+-   * to insert a list into itself). This implementation uses the iterator of
+-   * the collection, repeatedly calling add(int, Object); this will fail
+-   * if add does. This can often be made more efficient.
+-   *
+-   * @param index the location to insert the collection
+-   * @param c the collection to insert
+-   * @return true if the list was modified by this action, that is, if c is
+-   *         non-empty
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         addAll operation
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
+-   * @throws ClassCastException if some element of c cannot be added to this
+-   *         list due to its type
+-   * @throws IllegalArgumentException if some element of c cannot be added
+-   *         to this list for some other reason
+-   * @throws NullPointerException if the specified collection is null
+-   * @see #add(int, Object)
+-   */
+   public boolean addAll(int index, Collection c)
+   {
+     Iterator itr = c.iterator();
+     int size = c.size();
+-    for (int pos = size; pos > 0; pos--)
+-      add(index++, itr.next());
+-    return size > 0;
++    for (int pos = 0; pos < size; pos++)
++      {
++	add(index++, itr.next());
++      }
++    return (size > 0);
+   }
+ 
+-  /**
+-   * Clear the list, such that a subsequent call to isEmpty() would return
+-   * true (optional operation). This implementation calls
+-   * <code>removeRange(0, size())</code>, so it will fail unless remove
+-   * or removeRange is overridden.
+-   *
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         clear operation
+-   * @see #remove(int)
+-   * @see #removeRange(int, int)
+-   */
+   public void clear()
+   {
+     removeRange(0, size());
+   }
+ 
+-  /**
+-   * Test whether this list is equal to another object. A List is defined to be
+-   * equal to an object if and only if that object is also a List, and the two
+-   * lists have the same sequence. Two lists l1 and l2 are equal if and only
+-   * if <code>l1.size() == l2.size()</code>, and for every integer n between 0
+-   * and <code>l1.size() - 1</code> inclusive, <code>l1.get(n) == null ?
+-   * l2.get(n) == null : l1.get(n).equals(l2.get(n))</code>.
+-   * <p>
+-   *
+-   * This implementation returns true if the object is this, or false if the
+-   * object is not a List.  Otherwise, it iterates over both lists (with
+-   * iterator()), returning false if two elements compare false or one list
+-   * is shorter, and true if the iteration completes successfully.
+-   *
+-   * @param o the object to test for equality with this list
+-   * @return true if o is equal to this list
+-   * @see Object#equals(Object)
+-   * @see #hashCode()
+-   */
+   public boolean equals(Object o)
+   {
+     if (o == this)
+       return true;
+-    if (! (o instanceof List))
++    if (!(o instanceof List))
+       return false;
+     int size = size();
+     if (size != ((List) o).size())
+@@ -218,272 +94,77 @@
+     Iterator itr1 = iterator();
+     Iterator itr2 = ((List) o).iterator();
+ 
+-    while (--size >= 0)
+-      if (! equals(itr1.next(), itr2.next()))
+-        return false;
++    for (int pos = 0; pos < size; pos++)
++      {
++	Object e = itr1.next();
++	if (e == null ? itr2.next() != null : !e.equals(itr2.next()))
++	  return false;
++      }
+     return true;
+   }
+ 
+-  /**
+-   * Obtain a hash code for this list. In order to obey the general contract of
+-   * the hashCode method of class Object, this value is calculated as follows:
+-   * <pre>
+-   *   hashCode = 1;
+-   *   Iterator i = list.iterator();
+-   *   while (i.hasNext())
+-   *     {
+-   *       Object obj = i.next();
+-   *       hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
+-   *     }
+-   * </pre>
+-   * This ensures that the general contract of Object.hashCode() is adhered to.
+-   *
+-   * @return the hash code of this list
+-   * @see Object#hashCode()
+-   * @see #equals(Object)
+-   */
+   public int hashCode()
+   {
+     int hashCode = 1;
+     Iterator itr = iterator();
+-    int pos = size();
+-    while (--pos >= 0)
+-      hashCode = 31 * hashCode + hashCode(itr.next());
++    int size = size();
++    for (int pos = 0; pos < size; pos++)
++      {
++	Object obj = itr.next();
++	hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
++      }
+     return hashCode;
+   }
+ 
+-  /**
+-   * Obtain the first index at which a given object is to be found in this
+-   * list. This implementation follows a listIterator() until a match is found,
+-   * or returns -1 if the list end is reached.
+-   *
+-   * @param o the object to search for
+-   * @return the least integer n such that <code>o == null ? get(n) == null :
+-   *         o.equals(get(n))</code>, or -1 if there is no such index
+-   */
+   public int indexOf(Object o)
+   {
+-    ListIterator itr = listIterator();
++    ListIterator itr = listIterator(0);
+     int size = size();
+     for (int pos = 0; pos < size; pos++)
+-      if (equals(o, itr.next()))
+-        return pos;
++      {
++	if (o == null ? itr.next() == null : o.equals(itr.next()))
++	  return pos;
++      }
+     return -1;
+   }
+ 
+-  /**
+-   * Obtain an Iterator over this list, whose sequence is the list order.
+-   * This implementation uses size(), get(int), and remove(int) of the
+-   * backing list, and does not support remove unless the list does. This
+-   * implementation is fail-fast if you correctly maintain modCount.
+-   * Also, this implementation is specified by Sun to be distinct from
+-   * listIterator, although you could easily implement it as
+-   * <code>return listIterator(0)</code>.
+-   *
+-   * @return an Iterator over the elements of this list, in order
+-   * @see #modCount
+-   */
+   public Iterator iterator()
+   {
+-    // Bah, Sun's implementation forbids using listIterator(0).
+-    return new Iterator()
+-    {
+-      private int pos = 0;
+-      private int size = size();
+-      private int last = -1;
+-      private int knownMod = modCount;
+-
+-      // This will get inlined, since it is private.
+-      private void checkMod()
+-      {
+-        if (knownMod != modCount)
+-          throw new ConcurrentModificationException();
+-      }
+-
+-      public boolean hasNext()
+-      {
+-        checkMod();
+-        return pos < size;
+-      }
+-
+-      public Object next()
+-      {
+-        checkMod();
+-        if (pos == size)
+-          throw new NoSuchElementException();
+-        last = pos++;
+-        return get(pos);
+-      }
+-
+-      public void remove()
+-      {
+-        checkMod();
+-        if (last < 0)
+-          throw new IllegalStateException();
+-        AbstractList.this.remove(last);
+-        pos--;
+-        size--;
+-        last = -1;
+-        knownMod = modCount;
+-      }
+-    };
++    return new AbstractListItr(0);
+   }
+ 
+-  /**
+-   * Obtain the last index at which a given object is to be found in this
+-   * list. This implementation grabs listIterator(size()), then searches
+-   * backwards for a match or returns -1.
+-   *
+-   * @return the greatest integer n such that <code>o == null ? get(n) == null
+-   *         : o.equals(get(n))</code>, or -1 if there is no such index
+-   */
+   public int lastIndexOf(Object o)
+   {
+-    int pos = size();
+-    ListIterator itr = listIterator(pos);
+-    while (--pos >= 0)
+-      if (equals(o, itr.previous()))
+-        return pos;
++    int size = size();
++    ListIterator itr = listIterator(size);
++    for (int pos = size; pos > 0; pos--)
++      {
++	if (o == null ? itr.previous() == null : o.equals(itr.previous()))
++	  return pos - 1;
++      }
+     return -1;
+   }
+ 
+   /**
+-   * Obtain a ListIterator over this list, starting at the beginning. This
+-   * implementation returns listIterator(0).
++   * Return an Iterator over this List. This implementation calls
++   * listIterator(0).
+    *
+-   * @return a ListIterator over the elements of this list, in order, starting
+-   *         at the beginning
++   * @return an Iterator over this List
+    */
+   public ListIterator listIterator()
+   {
+     return listIterator(0);
+   }
+ 
+-  /**
+-   * Obtain a ListIterator over this list, starting at a given position.
+-   * A first call to next() would return the same as get(index), and a
+-   * first call to previous() would return the same as get(index - 1).
+-   * <p>
+-   *
+-   * This implementation uses size(), get(int), set(int, Object),
+-   * add(int, Object), and remove(int) of the backing list, and does not
+-   * support remove, set, or add unless the list does. This implementation
+-   * is fail-fast if you correctly maintain modCount.
+-   *
+-   * @param index the position, between 0 and size() inclusive, to begin the
+-   *        iteration from
+-   * @return a ListIterator over the elements of this list, in order, starting
+-   *         at index
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
+-   * @see #modCount
+-   */
+-  public ListIterator listIterator(final int index)
++  public ListIterator listIterator(int index)
+   {
+     if (index < 0 || index > size())
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size());
+-
+-    return new ListIterator()
+-    {
+-      private int knownMod = modCount;
+-      private int position = index;
+-      private int lastReturned = -1;
+-      private int size = size();
+-
+-      // This will get inlined, since it is private.
+-      private void checkMod()
+-      {
+-        if (knownMod != modCount)
+-          throw new ConcurrentModificationException();
+-      }
+-
+-      public boolean hasNext()
+-      {
+-        checkMod();
+-        return position < size;
+-      }
+-
+-      public boolean hasPrevious()
+-      {
+-        checkMod();
+-        return position > 0;
+-      }
+-
+-      public Object next()
+-      {
+-        checkMod();
+-        if (position == size)
+-          throw new NoSuchElementException();
+-        lastReturned = position++;
+-        return get(lastReturned);
+-      }
+-
+-      public Object previous()
+-      {
+-        checkMod();
+-        if (position == 0)
+-          throw new NoSuchElementException();
+-        lastReturned = --position;
+-        return get(lastReturned);
+-      }
+-
+-      public int nextIndex()
+-      {
+-        checkMod();
+-        return position;
+-      }
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size());
+ 
+-      public int previousIndex()
+-      {
+-        checkMod();
+-        return position - 1;
+-      }
+-
+-      public void remove()
+-      {
+-        checkMod();
+-        if (lastReturned < 0)
+-          throw new IllegalStateException();
+-        AbstractList.this.remove(lastReturned);
+-        size--;
+-        position = lastReturned;
+-        lastReturned = -1;
+-        knownMod = modCount;
+-      }
+-
+-      public void set(Object o)
+-      {
+-        checkMod();
+-        if (lastReturned < 0)
+-          throw new IllegalStateException();
+-        AbstractList.this.set(lastReturned, o);
+-      }
+-
+-      public void add(Object o)
+-      {
+-        checkMod();
+-        AbstractList.this.add(position++, o);
+-        size++;
+-        lastReturned = -1;
+-        knownMod = modCount;
+-      }
+-    };
++    return new AbstractListItr(index);
+   }
+ 
+-  /**
+-   * Remove the element at a given position in this list (optional operation).
+-   * Shifts all remaining elements to the left to fill the gap. This
+-   * implementation always throws an UnsupportedOperationException.
+-   * If you want fail-fast iterators, be sure to increment modCount when
+-   * overriding this.
+-   *
+-   * @param index the position within the list of the object to remove
+-   * @return the object that was removed
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         remove operation
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   * @see #modCount
+-   */
+   public Object remove(int index)
+   {
+     throw new UnsupportedOperationException();
+@@ -494,10 +175,8 @@
+    * removeRange methods of the class which implements subList, which are
+    * difficult for subclasses to override directly. Therefore, this method
+    * should be overridden instead by the more efficient implementation, if one
+-   * exists. Overriding this can reduce quadratic efforts to constant time
+-   * in some cases!
++   * exists.
+    * <p>
+-   *
+    * This implementation first checks for illegal or out of range arguments. It
+    * then obtains a ListIterator over the list using listIterator(fromIndex).
+    * It then calls next() and remove() on this iterator repeatedly, toIndex -
+@@ -511,131 +190,152 @@
+     ListIterator itr = listIterator(fromIndex);
+     for (int index = fromIndex; index < toIndex; index++)
+       {
+-        itr.next();
+-        itr.remove();
++	itr.next();
++	itr.remove();
+       }
+   }
+ 
+-  /**
+-   * Replace an element of this list with another object (optional operation).
+-   * This implementation always throws an UnsupportedOperationException.
+-   *
+-   * @param index the position within this list of the element to be replaced
+-   * @param o the object to replace it with
+-   * @return the object that was replaced
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         set operation
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   * @throws ClassCastException if o cannot be added to this list due to its
+-   *         type
+-   * @throws IllegalArgumentException if o cannot be added to this list for
+-   *         some other reason
+-   */
+   public Object set(int index, Object o)
+   {
+     throw new UnsupportedOperationException();
+   }
+ 
+-  /**
+-   * Obtain a List view of a subsection of this list, from fromIndex
+-   * (inclusive) to toIndex (exclusive). If the two indices are equal, the
+-   * sublist is empty. The returned list should be modifiable if and only
+-   * if this list is modifiable. Changes to the returned list should be
+-   * reflected in this list. If this list is structurally modified in
+-   * any way other than through the returned list, the result of any subsequent
+-   * operations on the returned list is undefined.
+-   * <p>
+-   *
+-   * This implementation returns a subclass of AbstractList. It stores, in
+-   * private fields, the offset and size of the sublist, and the expected
+-   * modCount of the backing list. If the backing list implements RandomAccess,
+-   * the sublist will also.
+-   * <p>
+-   *
+-   * The subclass's <code>set(int, Object)</code>, <code>get(int)</code>,
+-   * <code>add(int, Object)</code>, <code>remove(int)</code>,
+-   * <code>addAll(int, Collection)</code> and
+-   * <code>removeRange(int, int)</code> methods all delegate to the
+-   * corresponding methods on the backing abstract list, after
+-   * bounds-checking the index and adjusting for the offset. The
+-   * <code>addAll(Collection c)</code> method merely returns addAll(size, c).
+-   * The <code>listIterator(int)</code> method returns a "wrapper object"
+-   * over a list iterator on the backing list, which is created with the
+-   * corresponding method on the backing list. The <code>iterator()</code>
+-   * method merely returns listIterator(), and the <code>size()</code> method
+-   * merely returns the subclass's size field.
+-   * <p>
+-   *
+-   * All methods first check to see if the actual modCount of the backing
+-   * list is equal to its expected value, and throw a
+-   * ConcurrentModificationException if it is not. 
+-   *
+-   * @param fromIndex the index that the returned list should start from
+-   *        (inclusive)
+-   * @param toIndex the index that the returned list should go to (exclusive)
+-   * @return a List backed by a subsection of this list
+-   * @throws IndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; size()
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @see ConcurrentModificationException
+-   * @see RandomAccess
+-   */
+   public List subList(int fromIndex, int toIndex)
+   {
+-    // This follows the specification of AbstractList, but is inconsistent
+-    // with the one in List. Don't you love Sun's inconsistencies?
+     if (fromIndex > toIndex)
+       throw new IllegalArgumentException(fromIndex + " > " + toIndex);
+     if (fromIndex < 0 || toIndex > size())
+       throw new IndexOutOfBoundsException();
+ 
+-    if (this instanceof RandomAccess)
+-      return new RandomAccessSubList(this, fromIndex, toIndex);
+     return new SubList(this, fromIndex, toIndex);
+   }
+ 
+-} // class AbstractList
++  class AbstractListItr implements ListIterator
++  {
++    private int knownMod = modCount;
++    private int position;
++    private int lastReturned = -1;
++    private int size = size();
++
++    AbstractListItr(int start_pos)
++    {
++      this.position = start_pos;
++    }
++
++    private void checkMod()
++    {
++      if (knownMod != modCount)
++	throw new ConcurrentModificationException();
++    }
++
++    public boolean hasNext()
++    {
++      checkMod();
++      return position < size;
++    }
++
++    public boolean hasPrevious()
++    {
++      checkMod();
++      return position > 0;
++    }
++
++    public Object next()
++    {
++      checkMod();
++      if (position < size)
++	{
++	  lastReturned = position++;
++	  return get(lastReturned);
++	}
++      else
++	{
++	  throw new NoSuchElementException();
++	}
++    }
++
++    public Object previous()
++    {
++      checkMod();
++      if (position > 0)
++	{
++	  lastReturned = --position;
++	  return get(lastReturned);
++	}
++      else
++	{
++	  throw new NoSuchElementException();
++	}
++    }
++
++    public int nextIndex()
++    {
++      checkMod();
++      return position;
++    }
++
++    public int previousIndex()
++    {
++      checkMod();
++      return position - 1;
++    }
++
++    public void remove()
++    {
++      checkMod();
++      if (lastReturned < 0)
++	{
++	  throw new IllegalStateException();
++	}
++      AbstractList.this.remove(lastReturned);
++      knownMod++;
++      position = lastReturned;
++      lastReturned = -1;
++    }
++
++    public void set(Object o)
++    {
++      checkMod();
++      if (lastReturned < 0)
++	throw new IllegalStateException();
++      AbstractList.this.set(lastReturned, o);
++    }
++
++    public void add(Object o)
++    {
++      checkMod();
++      AbstractList.this.add(position++, o);
++      lastReturned = -1;
++      knownMod++;
++    }
++  }				// AbstractList.Iterator
++}
++
+ 
+ 
+-/**
+- * This class follows the implementation requirements set forth in
+- * {@link AbstractList#subList(int, int)}. Some compilers have problems
+- * with AbstractList.this.modCount if this class is nested in AbstractList,
+- * even though the JLS defines that to be legal, so we make it a top-level
+- * class.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- */
+ class SubList extends AbstractList
+ {
+-  private final AbstractList backingList;
+-  private final int offset;
++  private AbstractList backingList;
++  private int offset;
+   private int size;
+ 
+-  /**
+-   * Construct the sublist.
+-   *
+-   * @param backing the list this comes from
+-   * @param fromIndex the lower bound, inclusive
+-   * @param toIndex the upper bound, exclusive
+-   */
+-  SubList(AbstractList backing, int fromIndex, int toIndex)
++  public SubList(AbstractList backing, int fromIndex, int toIndex)
+   {
+     backingList = backing;
+-    modCount = backing.modCount;
++    modCount = backingList.modCount;
+     offset = fromIndex;
+     size = toIndex - fromIndex;
+   }
+ 
+   /**
+    * This method checks the two modCount fields to ensure that there has
+-   * not been a concurrent modification, returning if all is okay.
++   * not been a concurrent modification. It throws an exception if there
++   * has been, and otherwise returns normally.
++   * Note that since this method is private, it will be inlined.
+    *
+-   * @throws ConcurrentModificationException if the backing list has been
+-   *         modified externally to this sublist
++   * @exception ConcurrentModificationException if there has been a
++   *   concurrent modification.
+    */
+-  // This will get inlined, since it is private.
+   private void checkMod()
+   {
+     if (modCount != backingList.modCount)
+@@ -645,64 +345,45 @@
+   /**
+    * This method checks that a value is between 0 and size (inclusive). If
+    * it is not, an exception is thrown.
++   * Note that since this method is private, it will be inlined.
+    *
+-   * @param index the value to check
+-   * @throws IndexOutOfBoundsException if the value is out of range
++   * @exception IndexOutOfBoundsException if the value is out of range.
+    */
+-  // This will get inlined, since it is private.
+   private void checkBoundsInclusive(int index)
+   {
+     if (index < 0 || index > size)
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size);
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
+   }
+ 
+   /**
+    * This method checks that a value is between 0 (inclusive) and size
+    * (exclusive). If it is not, an exception is thrown.
++   * Note that since this method is private, it will be inlined.
+    *
+-   * @param index the value to check
+-   * @throws IndexOutOfBoundsException if the value is out of range
++   * @exception IndexOutOfBoundsException if the value is out of range.
+    */
+-  // This will get inlined, since it is private.
+   private void checkBoundsExclusive(int index)
+   {
+     if (index < 0 || index >= size)
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size);
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to return the private field size.
+-   *
+-   * @return the sublist size
+-   */
+   public int size()
+   {
+     checkMod();
+     return size;
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to delegate to the backing list.
+-   *
+-   * @param index the location to modify
+-   * @param o the new value
+-   * @return the old value
+-   */
+   public Object set(int index, Object o)
+   {
+     checkMod();
+     checkBoundsExclusive(index);
+-    return backingList.set(index + offset, o);
++    o = backingList.set(index + offset, o);
++    return o;
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to delegate to the backing list.
+-   *
+-   * @param index the location to get from
+-   * @return the object at that location
+-   */
+   public Object get(int index)
+   {
+     checkMod();
+@@ -710,109 +391,62 @@
+     return backingList.get(index + offset);
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to delegate to the backing list.
+-   *
+-   * @param index the index to insert at
+-   * @param o the object to add
+-   */
+   public void add(int index, Object o)
+   {
+     checkMod();
+     checkBoundsInclusive(index);
+     backingList.add(index + offset, o);
++    this.modCount++;
+     size++;
+-    modCount = backingList.modCount;
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to delegate to the backing list.
+-   *
+-   * @param index the index to remove
+-   * @return the removed object
+-   */
+   public Object remove(int index)
+   {
+     checkMod();
+     checkBoundsExclusive(index);
+     Object o = backingList.remove(index + offset);
++    this.modCount++;
+     size--;
+-    modCount = backingList.modCount;
+     return o;
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to delegate to the backing list.
+-   * This does no bounds checking, as it assumes it will only be called
+-   * by trusted code like clear() which has already checked the bounds.
+-   *
+-   * @param fromIndex the lower bound, inclusive
+-   * @param toIndex the upper bound, exclusive
+-   */
+-  protected void removeRange(int fromIndex, int toIndex)
++  public void removeRange(int fromIndex, int toIndex)
+   {
+     checkMod();
++    checkBoundsExclusive(fromIndex);
++    checkBoundsInclusive(toIndex);
+ 
++    // this call will catch the toIndex < fromIndex condition
+     backingList.removeRange(offset + fromIndex, offset + toIndex);
++    this.modCount = backingList.modCount;
+     size -= toIndex - fromIndex;
+-    modCount = backingList.modCount;
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to delegate to the backing list.
+-   *
+-   * @param index the location to insert at
+-   * @param c the collection to insert
+-   * @return true if this list was modified, in other words, c is non-empty
+-   */
+   public boolean addAll(int index, Collection c)
+   {
+     checkMod();
+     checkBoundsInclusive(index);
+     int csize = c.size();
+     boolean result = backingList.addAll(offset + index, c);
++    this.modCount = backingList.modCount;
+     size += csize;
+-    modCount = backingList.modCount;
+     return result;
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to return addAll(size, c).
+-   *
+-   * @param c the collection to insert
+-   * @return true if this list was modified, in other words, c is non-empty
+-   */
+-  public boolean addAll(Collection c)
+-  {
+-    return addAll(size, c);
+-  }
+-
+-  /**
+-   * Specified by AbstractList.subList to return listIterator().
+-   *
+-   * @return an iterator over the sublist
+-   */
+   public Iterator iterator()
+   {
+-    return listIterator();
++    return listIterator(0);
+   }
+ 
+-  /**
+-   * Specified by AbstractList.subList to return a wrapper around the
+-   * backing list's iterator.
+-   *
+-   * @param index the start location of the iterator
+-   * @return a list iterator over the sublist
+-   */
+   public ListIterator listIterator(final int index)
+-  {
++  {      
+     checkMod();
+     checkBoundsInclusive(index);
+ 
+-    return new ListIterator()
++    return new ListIterator() 
+     {
+-      private final ListIterator i = backingList.listIterator(index + offset);
+-      private int position = index;
++      ListIterator i = backingList.listIterator(index + offset);
++      int position = index;
+ 
+       public boolean hasNext()
+       {
+@@ -828,36 +462,44 @@
+ 
+       public Object next()
+       {
+-        if (position == size)
++        if (position < size)
++	  {
++            Object o = i.next();
++            position++;
++            return o;
++          }
++	else
+           throw new NoSuchElementException();
+-        position++;
+-        return i.next();
+       }
+ 
+       public Object previous()
+       {
+-        if (position == 0)
++        if (position > 0)
++	  {
++            Object o = i.previous();
++            position--;
++            return o;
++          }
++	else
+           throw new NoSuchElementException();
+-        position--;
+-        return i.previous();
+       }
+ 
+       public int nextIndex()
+       {
+-        return i.nextIndex() - offset;
++        return offset + i.nextIndex();
+       }
+ 
+       public int previousIndex()
+       {
+-        return i.previousIndex() - offset;
++        return offset + i.previousIndex();
+       }
+ 
+       public void remove()
+       {
+         i.remove();
++	modCount++;
+         size--;
+         position = nextIndex();
+-        modCount = backingList.modCount;
+       }
+ 
+       public void set(Object o)
+@@ -868,14 +510,14 @@
+       public void add(Object o)
+       {
+         i.add(o);
++	modCount++;
+         size++;
+         position++;
+-        modCount = backingList.modCount;
+       }
+ 
+       // Here is the reason why the various modCount fields are mostly
+       // ignored in this wrapper listIterator.
+-      // If the backing listIterator is failfast, then the following holds:
++      // IF the backing listIterator is failfast, then the following holds:
+       //   Using any other method on this list will call a corresponding
+       //   method on the backing list *after* the backing listIterator
+       //   is created, which will in turn cause a ConcurrentModException
+@@ -888,31 +530,9 @@
+       //   only, but somewhat pointless when the list can be changed under
+       //   us.
+       // Either way, no explicit handling of modCount is needed.
+-      // However modCount = backingList.modCount must be executed in add
+-      // and remove, and size must also be updated in these two methods,
+-      // since they do not go through the corresponding methods of the subList.
++      // However modCount++ must be executed in add and remove, and size
++      // must also be updated in these two methods, since they do not go
++      // through the corresponding methods of the subList.
+     };
+   }
+-} // class SubList
+-
+-/**
+- * This class is a RandomAccess version of SubList, as required by
+- * {@link AbstractList#subList(int, int)}.
+- *
+- * @author Eric Blake <ebb9@email.byu.edu>
+- */
+-final class RandomAccessSubList extends SubList
+-  implements RandomAccess
+-{
+-  /**
+-   * Construct the sublist.
+-   *
+-   * @param backing the list this comes from
+-   * @param fromIndex the lower bound, inclusive
+-   * @param toIndex the upper bound, exclusive
+-   */
+-  RandomAccessSubList(AbstractList backing, int fromIndex, int toIndex)
+-  {
+-    super(backing, fromIndex, toIndex);
+-  }
+-} // class RandomAccessSubList
++}  // SubList
Index: compare/java.util.AbstractMap.diff
===================================================================
RCS file: java.util.AbstractMap.diff
diff -N java.util.AbstractMap.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.AbstractMap.diff Tue Nov 6 17:21:28 2001
@@ -0,0 +1,665 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/AbstractMap.java	Fri Oct 26 16:06:56 2001
++++ java/util/AbstractMap.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,5 @@
+ /* AbstractMap.java -- Abstract implementation of most of Map
+-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -25,70 +25,22 @@
+ executable file might be covered by the GNU General Public License. */
+ 
+ 
++// TO DO:
++// comments
++// test suite
++
+ package java.util;
+ 
+-/**
+- * An abstract implementation of Map to make it easier to create your own
+- * implementations. In order to create an unmodifiable Map, subclass
+- * AbstractMap and implement the <code>entrySet</code> (usually via an
+- * AbstractSet).  To make it modifiable, also implement <code>put</code>,
+- * and have <code>entrySet().iterator()</code> support <code>remove</code>.
+- * <p>
+- *
+- * It is recommended that classes which extend this support at least the
+- * no-argument constructor, and a constructor which accepts another Map.
+- * Further methods in this class may be overridden if you have a more
+- * efficient implementation.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Map
+- * @see Collection
+- * @see HashMap
+- * @see LinkedHashMap
+- * @see TreeMap
+- * @see WeakHashMap
+- * @see IdentityHashMap
+- * @since 1.2
+- * @status updated to 1.4
+- */
+ public abstract class AbstractMap implements Map
+ {
+-  /** An "enum" of iterator types. */
+-  // Package visible for use by subclasses.
+-  static final int KEYS = 0,
+-                   VALUES = 1,
+-                   ENTRIES = 2;
+-
+-  /**
+-   * The cache for {@link #keySet()}.
+-   */
+-  // Package visible for use by subclasses.
+-  Set keys;
+-
+-  /**
+-   * The cache for {@link #values()}.
+-   */
+-  // Package visible for use by subclasses.
+-  Collection values;
+-
+   /**
+-   * The main constructor, for use by subclasses.
+-   */
+-  protected AbstractMap()
+-  {
+-  }
+-
+-  /**
+-   * Remove all entries from this Map (optional operation). This default
+-   * implementation calls entrySet().clear(). NOTE: If the entry set does
+-   * not permit clearing, then this will fail, too. Subclasses often
+-   * override this for efficiency.  Your implementation of entrySet() should
+-   * not call <code>AbstractMap.clear</code> unless you want an infinite loop.
++   * Remove all entries from this Map. This default implementation calls
++   * entrySet().clear().
+    *
+-   * @throws UnsupportedOperationException if <code>entrySet().clear()</code>
+-   *         does not support clearing.
+-   * @see Set#clear()
++   * @throws UnsupportedOperationException
++   * @specnote The JCL book claims that this implementation always throws 
++   *           UnsupportedOperationException, while the online docs claim it
++   *           calls entrySet().clear(). We take the later to be correct.
+    */
+   public void clear()
+   {
+@@ -96,414 +48,246 @@
+   }
+ 
+   /**
+-   * Create a shallow copy of this Map, no keys or values are copied. The
+-   * default implementation simply calls <code>super.clone()</code>.
+-   *
+-   * @return the shallow clone
+-   * @throws CloneNotSupportedException if a subclass is not Cloneable
+-   * @see Cloneable
+-   * @see Object#clone()
++   * Create a shallow copy of this Map, no keys or values are copied.
+    */
+-  protected Object clone() throws CloneNotSupportedException
++  protected Object clone () throws CloneNotSupportedException
+   {
+-    AbstractMap copy = (AbstractMap) super.clone();
+-    // Clear out the caches; they are stale.
+-    copy.keys = null;
+-    copy.values = null;
+-    return copy;
++    return super.clone ();
+   }
+ 
+-  /**
+-   * Returns true if this contains a mapping for the given key. This
+-   * implementation does a linear search, O(n), over the
+-   * <code>entrySet()</code>, returning <code>true</code> if a match
+-   * is found, <code>false</code> if the iteration ends. Many subclasses
+-   * can implement this more efficiently.
+-   *
+-   * @param key the key to search for
+-   * @return true if the map contains the key
+-   * @throws NullPointerException if key is <code>null</code> but the map
+-   *         does not permit null keys
+-   * @see #containsValue(Object)
+-   */
+   public boolean containsKey(Object key)
+   {
+-    Iterator entries = entrySet().iterator();
+-    int pos = size();
+-    while (--pos >= 0)
+-      if (equals(key, ((Map.Entry) entries.next()).getKey()))
+-        return true;
++    Object k;
++    Set es = entrySet();
++    Iterator entries = es.iterator();
++    int size = size();
++    for (int pos = 0; pos < size; pos++)
++      {
++	k = ((Map.Entry) entries.next()).getKey();
++	if (key == null ? k == null : key.equals(k))
++	  return true;
++      }
+     return false;
+   }
+ 
+-  /**
+-   * Returns true if this contains at least one mapping with the given value.
+-   * This implementation does a linear search, O(n), over the
+-   * <code>entrySet()</code>, returning <code>true</code> if a match
+-   * is found, <code>false</code> if the iteration ends. A match is
+-   * defined as <code>(value == null ? v == null : value.equals(v))</code>
+-   * Subclasses are unlikely to implement this more efficiently.
+-   *
+-   * @param value the value to search for
+-   * @return true if the map contains the value
+-   * @see #containsKey(Object)
+-   */
+   public boolean containsValue(Object value)
+   {
+-    Iterator entries = entrySet().iterator();
+-    int pos = size();
+-    while (--pos >= 0)
+-      if (equals(value, ((Map.Entry) entries.next()).getValue()))
+-        return true;
++    Object v;
++    Set es = entrySet();
++    Iterator entries = es.iterator();
++    int size = size();
++    for (int pos = 0; pos < size; pos++)
++      {
++	v = ((Map.Entry) entries.next()).getValue();
++	if (value == null ? v == null : value.equals(v))
++	  return true;
++      }
+     return false;
+   }
+ 
+-  /**
+-   * Returns a set view of the mappings in this Map.  Each element in the
+-   * set must be an implementation of Map.Entry.  The set is backed by
+-   * the map, so that changes in one show up in the other.  Modifications
+-   * made while an iterator is in progress cause undefined behavior.  If
+-   * the set supports removal, these methods must be valid:
+-   * <code>Iterator.remove</code>, <code>Set.remove</code>,
+-   * <code>removeAll</code>, <code>retainAll</code>, and <code>clear</code>.
+-   * Element addition is not supported via this set.
+-   *
+-   * @return the entry set
+-   * @see Map.Entry
+-   */
+   public abstract Set entrySet();
+ 
+-  /**
+-   * Compares the specified object with this map for equality. Returns
+-   * <code>true</code> if the other object is a Map with the same mappings,
+-   * that is,<br>
+-   * <code>o instanceof Map && entrySet().equals(((Map) o).entrySet();</code>
+-   *
+-   * @param o the object to be compared
+-   * @return true if the object equals this map
+-   * @see Set#equals(Object)
+-   */
+   public boolean equals(Object o)
+   {
+-    return (o == this ||
+-            (o instanceof Map &&
+-             entrySet().equals(((Map) o).entrySet())));
++    if (o == this)
++      return true;
++    if (!(o instanceof Map))
++      return false;
++
++    Map m = (Map) o;
++    Set s = m.entrySet();
++    Iterator itr = entrySet().iterator();
++    int size = size();
++
++    if (m.size() != size)
++      return false;
++
++    for (int pos = 0; pos < size; pos++)
++      {
++	if (!s.contains(itr.next()))
++	  return false;
++      }
++    return true;
+   }
+ 
+-  /**
+-   * Returns the value mapped by the given key. Returns <code>null</code> if
+-   * there is no mapping.  However, in Maps that accept null values, you
+-   * must rely on <code>containsKey</code> to determine if a mapping exists.
+-   * This iteration takes linear time, searching entrySet().iterator() of
+-   * the key.  Many implementations override this method.
+-   *
+-   * @param key the key to look up
+-   * @return the value associated with the key, or null if key not in map
+-   * @throws NullPointerException if this map does not accept null keys
+-   * @see #containsKey(Object)
+-   */
+   public Object get(Object key)
+   {
+-    Iterator entries = entrySet().iterator();
+-    int pos = size();
+-    while (--pos >= 0)
++    Set s = entrySet();
++    Iterator entries = s.iterator();
++    int size = size();
++
++    for (int pos = 0; pos < size; pos++)
+       {
+-        Map.Entry entry = (Map.Entry) entries.next();
+-        if (equals(key, entry.getKey()))
+-          return entry.getValue();
++	Map.Entry entry = (Map.Entry) entries.next();
++	Object k = entry.getKey();
++	if (key == null ? k == null : key.equals(k))
++	  return entry.getValue();
+       }
++
+     return null;
+   }
+ 
+-  /**
+-   * Returns the hash code for this map. As defined in Map, this is the sum
+-   * of all hashcodes for each Map.Entry object in entrySet, or basically
+-   * entrySet().hashCode().
+-   *
+-   * @return the hash code
+-   * @see Map.Entry#hashCode()
+-   * @see Set#hashCode()
+-   */
+   public int hashCode()
+   {
+-    return entrySet().hashCode();
++    int hashcode = 0;
++    Iterator itr = entrySet().iterator();
++    int size = size();
++    for (int pos = 0; pos < size; pos++)
++      {
++	hashcode += itr.next().hashCode();
++      }
++    return hashcode;
+   }
+ 
+-  /**
+-   * Returns true if the map contains no mappings. This is implemented by
+-   * <code>size() == 0</code>.
+-   *
+-   * @return true if the map is empty
+-   * @see #size()
+-   */
+   public boolean isEmpty()
+   {
+     return size() == 0;
+   }
+ 
+-  /**
+-   * Returns a set view of this map's keys. The set is backed by the map,
+-   * so changes in one show up in the other. Modifications while an iteration
+-   * is in progress produce undefined behavior. The set supports removal
+-   * if entrySet() does, but does not support element addition.
+-   * <p>
+-   *
+-   * This implementation creates an AbstractSet, where the iterator wraps
+-   * the entrySet iterator, size defers to the Map's size, and contains
+-   * defers to the Map's containsKey. The set is created on first use, and
+-   * returned on subsequent uses, although since no synchronization occurs,
+-   * there is a slight possibility of creating two sets.
+-   *
+-   * @return a Set view of the keys
+-   * @see Set#iterator()
+-   * @see #size()
+-   * @see #containsKey(Object)
+-   * @see #values()
+-   */
+   public Set keySet()
+   {
+-    if (keys == null)
+-      keys = new AbstractSet()
++    if (this.keySet == null)
+       {
+-        public int size()
+-        {
+-          return AbstractMap.this.size();
+-        }
+-
+-        public boolean contains(Object key)
+-        {
+-          return containsKey(key);
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          return new Iterator()
+-          {
+-            private final Iterator map_iterator = entrySet().iterator();
+-
+-            public boolean hasNext()
+-            {
+-              return map_iterator.hasNext();
+-            }
+-
+-            public Object next()
+-            {
+-              return ((Map.Entry) map_iterator.next()).getKey();
+-            }
+-
+-            public void remove()
+-            {
+-              map_iterator.remove();
+-            }
+-          };
+-        }
+-      };
+-    return keys;
++	this.keySet = new AbstractSet()
++	{
++	  public int size()
++	  {
++	    return AbstractMap.this.size();
++	  }
++
++	  public boolean contains(Object key)
++	  {
++	    return AbstractMap.this.containsKey(key);
++	  }
++
++	  public Iterator iterator()
++	  {
++	    return new Iterator()
++	    {
++	      Iterator map_iterator = AbstractMap.this.entrySet().iterator();
++
++	      public boolean hasNext()
++	      {
++		return map_iterator.hasNext();
++	      }
++
++	      public Object next()
++	      {
++		return ((Map.Entry) map_iterator.next()).getKey();
++	      }
++
++	      public void remove()
++	      {
++		map_iterator.remove();
++	      }
++	    };
++	  }
++	};
++      }
++
++    return this.keySet;
+   }
+ 
+-  /**
+-   * Associates the given key to the given value (optional operation). If the
+-   * map already contains the key, its value is replaced. This implementation
+-   * simply throws an UnsupportedOperationException. Be aware that in a map
+-   * that permits <code>null</code> values, a null return does not always
+-   * imply that the mapping was created.
+-   *
+-   * @param key the key to map
+-   * @param value the value to be mapped
+-   * @return the previous value of the key, or null if there was no mapping
+-   * @throws UnsupportedOperationException if the operation is not supported
+-   * @throws ClassCastException if the key or value is of the wrong type
+-   * @throws IllegalArgumentException if something about this key or value
+-   *         prevents it from existing in this map
+-   * @throws NullPointerException if the map forbids null keys or values
+-   * @see #containsKey(Object)
+-   */
+   public Object put(Object key, Object value)
+   {
+     throw new UnsupportedOperationException();
+   }
+ 
+-  /**
+-   * Copies all entries of the given map to this one (optional operation). If
+-   * the map already contains a key, its value is replaced. This implementation
+-   * simply iterates over the map's entrySet(), calling <code>put</code>,
+-   * so it is not supported if puts are not.
+-   *
+-   * @param m the mapping to load into this map
+-   * @throws UnsupportedOperationException if the operation is not supported
+-   * @throws ClassCastException if a key or value is of the wrong type
+-   * @throws IllegalArgumentException if something about a key or value
+-   *         prevents it from existing in this map
+-   * @throws NullPointerException if the map forbids null keys or values, or
+-   *         if <code>m</code> is null.
+-   * @see #put(Object, Object)
+-   */
+   public void putAll(Map m)
+   {
++    Map.Entry entry;
+     Iterator entries = m.entrySet().iterator();
+-    int pos = size();
+-    while (--pos >= 0)
++    int size = m.size();
++
++    for (int pos = 0; pos < size; pos++)
+       {
+-        Map.Entry entry = (Map.Entry) entries.next();
+-        put(entry.getKey(), entry.getValue());
++	entry = (Map.Entry) entries.next();
++	put(entry.getKey(), entry.getValue());
+       }
+   }
+ 
+-  /**
+-   * Removes the mapping for this key if present (optional operation). This
+-   * implementation iterates over the entrySet searching for a matching
+-   * key, at which point it calls the iterator's <code>remove</code> method.
+-   * It returns the result of <code>getValue()</code> on the entry, if found,
+-   * or null if no entry is found. Note that maps which permit null values
+-   * may also return null if the key was removed.  If the entrySet does not
+-   * support removal, this will also fail. This is O(n), so many
+-   * implementations override it for efficiency.
+-   *
+-   * @param key the key to remove
+-   * @return the value the key mapped to, or null if not present
+-   * @throws UnsupportedOperationException if deletion is unsupported
+-   * @see Iterator#remove()
+-   */
+   public Object remove(Object key)
+   {
+     Iterator entries = entrySet().iterator();
+-    int pos = size();
+-    while (--pos >= 0)
++    int size = size();
++
++    for (int pos = 0; pos < size; pos++)
+       {
+-        Map.Entry entry = (Map.Entry) entries.next();
+-        if (equals(key, entry.getKey()))
+-          {
+-            // Must get the value before we remove it from iterator.
+-            Object r = entry.getValue();
+-            entries.remove();
+-            return r;
+-          }
++	Map.Entry entry = (Map.Entry) entries.next();
++	Object k = entry.getKey();
++	if (key == null ? k == null : key.equals(k))
++	  {
++	    Object value = entry.getValue();
++	    entries.remove();
++	    return value;
++	  }
+       }
++
+     return null;
+   }
+ 
+-  /**
+-   * Returns the number of key-value mappings in the map. If there are more
+-   * than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. This is
+-   * implemented as <code>entrySet().size()</code>.
+-   *
+-   * @return the number of mappings
+-   * @see Set#size()
+-   */
+   public int size()
+   {
+     return entrySet().size();
+   }
+ 
+-  /**
+-   * Returns a String representation of this map. This is a listing of the
+-   * map entries (which are specified in Map.Entry as being
+-   * <code>getKey() + "=" + getValue()</code>), separated by a comma and
+-   * space (", "), and surrounded by braces ('{' and '}'). This implementation
+-   * uses a StringBuffer and iterates over the entrySet to build the String.
+-   * Note that this can fail with an exception if underlying keys or
+-   * values complete abruptly in toString().
+-   *
+-   * @return a String representation
+-   * @see Map.Entry#toString()
+-   */
+   public String toString()
+   {
+     Iterator entries = entrySet().iterator();
++    int size = size();
+     StringBuffer r = new StringBuffer("{");
+-    for (int pos = size(); pos > 0; pos--)
++    for (int pos = 0; pos < size; pos++)
+       {
+-        // Append the toString value of the entries rather than calling
+-        // getKey/getValue. This is more efficient and it matches the JDK
+-        // behaviour.
+-        r.append(entries.next());
+-        if (pos > 1)
+-          r.append(", ");
++        // Append the toString value of the entries rather than calling 
++	// getKey/getValue. This is more efficient and it matches the JDK
++	// behaviour.
++	r.append(entries.next());	
++	if (pos < size - 1)
++	  r.append(", ");
+       }
+     r.append("}");
+     return r.toString();
+   }
+ 
+-  /**
+-   * Returns a collection or bag view of this map's values. The collection
+-   * is backed by the map, so changes in one show up in the other.
+-   * Modifications while an iteration is in progress produce undefined
+-   * behavior. The collection supports removal if entrySet() does, but
+-   * does not support element addition.
+-   * <p>
+-   *
+-   * This implementation creates an AbstractCollection, where the iterator
+-   * wraps the entrySet iterator, size defers to the Map's size, and contains
+-   * defers to the Map's containsValue. The collection is created on first
+-   * use, and returned on subsequent uses, although since no synchronization
+-   * occurs, there is a slight possibility of creating two collections.
+-   *
+-   * @return a Collection view of the values
+-   * @see Collection#iterator()
+-   * @see #size()
+-   * @see #containsValue(Object)
+-   * @see #keySet()
+-   */
+   public Collection values()
+   {
+-    if (values == null)
+-      values = new AbstractCollection()
++    if (this.valueCollection == null)
+       {
+-        public int size()
+-        {
+-          return AbstractMap.this.size();
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          return new Iterator()
+-          {
+-            private final Iterator map_iterator = entrySet().iterator();
+-
+-            public boolean hasNext()
+-            {
+-              return map_iterator.hasNext();
+-            }
+-
+-            public Object next()
+-            {
+-              return ((Map.Entry) map_iterator.next()).getValue();
+-            }
+-
+-            public void remove()
+-            {
+-              map_iterator.remove();
+-            }
+-          };
+-        }
+-      };
+-    return values;
+-  }
++	this.valueCollection = new AbstractCollection()
++	{
++	  public int size()
++	  {
++	    return AbstractMap.this.size();
++	  }
++
++	  public Iterator iterator()
++	  {
++	    return new Iterator()
++	    {
++	      Iterator map_iterator = AbstractMap.this.entrySet().iterator();
++
++	      public boolean hasNext()
++	      {
++		return map_iterator.hasNext();
++	      }
++
++	      public Object next()
++	      {
++		return ((Map.Entry) map_iterator.next()).getValue();
++	      }
++
++	      public void remove()
++	      {
++		map_iterator.remove();
++	      }
++	    };
++	  }
++	};
++      }
+ 
+-  /**
+-   * Compare two objects according to Collection semantics.
+-   *
+-   * @param o1 the first object
+-   * @param o2 the second object
+-   * @return o1 == null ? o2 == null : o1.equals(o2)
+-   */
+-  // Package visible for use throughout java.util.
+-  // It may be inlined since it is final.
+-  static final boolean equals(Object o1, Object o2)
+-  {
+-    return o1 == null ? o2 == null : o1.equals(o2);
++    return this.valueCollection;
+   }
+ 
+-  /**
+-   * Hash an object according to Collection semantics.
+-   *
+-   * @param o the object to hash
+-   * @return o1 == null ? 0 : o1.hashCode()
+-   */
+-  // Package visible for use throughout java.util.
+-  // It may be inlined since it is final.
+-  static final int hashCode(Object o)
+-  {
+-    return o == null ? 0 : o.hashCode();
+-  }
++  private Collection valueCollection = null;
++  private Set keySet = null;
+ }
Index: compare/java.util.AbstractSequentialList.diff
===================================================================
RCS file: java.util.AbstractSequentialList.diff
diff -N java.util.AbstractSequentialList.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.AbstractSequentialList.diff Tue Nov 6 17:21:28 2001
@@ -0,0 +1,243 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/AbstractSequentialList.java	Fri Oct 19 18:43:44 2001
++++ java/util/AbstractSequentialList.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,5 @@
+ /* AbstractSequentialList.java -- List implementation for sequential access
+-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -25,191 +25,100 @@
+ executable file might be covered by the GNU General Public License. */
+ 
+ 
++// TO DO:
++// ~ Lots of doc comments still missing.
++// ~ The class comment should include a description of what should be overridden
++//   to provide what features, as should the listIterator comment.
++
+ package java.util;
+ 
+ /**
+  * Abstract superclass to make it easier to implement the List interface when
+- * backed by a sequential-access store, such as a linked list. For random
+- * access data, use AbstractList. This class implements the random access
+- * methods (<code>get</code>, <code>set</code>, <code>add</code>, and
+- * <code>remove</code>) atop the list iterator, opposite of AbstractList's
+- * approach of implementing the iterator atop random access.
+- * <p>
+- *
+- * To implement a list, you need an implementation for <code>size()</code>
+- * and <code>listIterator</code>.  With just <code>hasNext</code>,
+- * <code>next</code>, <code>hasPrevious</code>, <code>previous</code>,
+- * <code>nextIndex</code>, and <code>previousIndex</code>, you have an
+- * unmodifiable list. For a modifiable one, add <code>set</code>, and for
+- * a variable-size list, add <code>add</code> and <code>remove</code>.
+- * <p>
+- *
+- * The programmer should provide a no-argument constructor, and one that
+- * accepts another Collection, as recommended by the Collection interface.
+- * Unfortunately, there is no way to enforce this in Java.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see List
+- * @see AbstractList
+- * @see AbstractCollection
+- * @see ListIterator
+- * @see LinkedList
+- * @since 1.2
+- * @status updated to 1.4
++ * backed by a sequential-access store, such as a linked list.
+  */
+ public abstract class AbstractSequentialList extends AbstractList
+ {
+   /**
+-   * The main constructor, for use by subclasses.
+-   */
+-  protected AbstractSequentialList()
+-  {
+-  }
+-
+-  /**
+    * Returns a ListIterator over the list, starting from position index.
+    * Subclasses must provide an implementation of this method.
+    *
+-   * @param index the starting position of the list
+-   * @return the list iterator
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
++   * @exception IndexOutOfBoundsException if index < 0 || index > size()
+    */
+   public abstract ListIterator listIterator(int index);
+ 
+   /**
+-   * Insert an element into the list at a given position (optional operation).
+-   * This shifts all existing elements from that position to the end one
+-   * index to the right. This version of add has no return, since it is
+-   * assumed to always succeed if there is no exception. This iteration
+-   * uses listIterator(index).add(o).
+-   *
+-   * @param index the location to insert the item
+-   * @param o the object to insert
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         add operation
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
+-   * @throws ClassCastException if o cannot be added to this list due to its
+-   *         type
+-   * @throws IllegalArgumentException if o cannot be added to this list for
+-   *         some other reason
++   * Add an element to the list at a given index. This implementation obtains a
++   * ListIterator positioned at the specified index, and then adds the element
++   * using the ListIterator's add method.
++   *
++   * @param index the position to add the element
++   * @param o the element to insert
++   * @exception IndexOutOfBoundsException if index < 0 || index > size()
++   * @exception UnsupportedOperationException if the iterator returned by
++   *   listIterator(index) does not support the add method.
+    */
+   public void add(int index, Object o)
+   {
+-    listIterator(index).add(o);
++    ListIterator i = listIterator(index);
++    i.add(o);
+   }
+ 
+   /**
+-   * Insert the contents of a collection into the list at a given position
+-   * (optional operation). Shift all elements at that position to the right
+-   * by the number of elements inserted. This operation is undefined if
+-   * this list is modified during the operation (for example, if you try
+-   * to insert a list into itself).
+-   * <p>
+-   *
+-   * This implementation grabs listIterator(index), then proceeds to use add
+-   * for each element returned by c's iterator. Sun's online specs are wrong,
+-   * claiming that this also calls next(): listIterator.add() correctly
+-   * skips the added element.
+-   *
+-   * @param index the location to insert the collection
+-   * @param c the collection to insert
+-   * @return true if the list was modified by this action, that is, if c is
+-   *         non-empty
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         addAll operation
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
+-   * @throws ClassCastException if some element of c cannot be added to this
+-   *         list due to its type
+-   * @throws IllegalArgumentException if some element of c cannot be added
+-   *         to this list for some other reason
+-   * @throws NullPointerException if the specified collection is null
+-   * @see #add(int, Object)
++   * @specnote The spec in the JDK1.3 online docs is wrong. The implementation
++   *           should not call next() to skip over new elements as they are
++   *           added, because iterator.add() should add new elements BEFORE
++   *           the cursor.
+    */
+   public boolean addAll(int index, Collection c)
+   {
++    boolean modified = false;
+     Iterator ci = c.iterator();
+     int size = c.size();
+     ListIterator i = listIterator(index);
+-    for (int pos = size; pos > 0; pos--)
+-      i.add(ci.next());
+-    return size > 0;
++    for (int pos = 0; pos < size; pos++)
++      {
++	i.add(ci.next());
++      }
++    return (size > 0);
+   }
+ 
+-  /**
+-   * Get the element at a given index in this list. This implementation
+-   * returns listIterator(index).next().
+-   *
+-   * @param index the index of the element to be returned
+-   * @return the element at index index in this list
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   */
+   public Object get(int index)
+   {
+-    // This is a legal listIterator position, but an illegal get.
+-    if (index == size())
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size());
+-    return listIterator(index).next();
++    ListIterator i = listIterator(index);
++    if (index < 0 || index > size())
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size());
++    return i.next();
+   }
+ 
+   /**
+-   * Obtain an Iterator over this list, whose sequence is the list order. This
+-   * implementation returns listIterator().
++   * Return an Iterator over this List. This implementation returns
++   * listIterator().
+    *
+-   * @return an Iterator over the elements of this list, in order
++   * @return an Iterator over this List
+    */
+   public Iterator iterator()
+   {
+     return listIterator();
+   }
+ 
+-  /**
+-   * Remove the element at a given position in this list (optional operation).
+-   * Shifts all remaining elements to the left to fill the gap. This
+-   * implementation uses listIterator(index) and ListIterator.remove().
+-   *
+-   * @param index the position within the list of the object to remove
+-   * @return the object that was removed
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         remove operation
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   */
+   public Object remove(int index)
+   {
+-    // This is a legal listIterator position, but an illegal remove.
+-    if (index == size())
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size());
+     ListIterator i = listIterator(index);
++    if (index < 0 || index > size())
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size());
+     Object removed = i.next();
+     i.remove();
+     return removed;
+   }
+ 
+-  /**
+-   * Replace an element of this list with another object (optional operation).
+-   * This implementation uses listIterator(index) and ListIterator.set(o).
+-   *
+-   * @param index the position within this list of the element to be replaced
+-   * @param o the object to replace it with
+-   * @return the object that was replaced
+-   * @throws UnsupportedOperationException if this list does not support the
+-   *         set operation
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   * @throws ClassCastException if o cannot be added to this list due to its
+-   *         type
+-   * @throws IllegalArgumentException if o cannot be added to this list for
+-   *         some other reason
+-   */
+   public Object set(int index, Object o)
+   {
+-    // This is a legal listIterator position, but an illegal set.
+-    if (index == size())
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size());
+     ListIterator i = listIterator(index);
++    if (index < 0 || index > size())
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size());
+     Object old = i.next();
+     i.set(o);
+     return old;
Index: compare/java.util.AbstractSet.diff
===================================================================
RCS file: java.util.AbstractSet.diff
diff -N java.util.AbstractSet.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.AbstractSet.diff Tue Nov 6 17:21:28 2001
@@ -0,0 +1,105 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/AbstractSet.java	Fri Oct 19 18:43:44 2001
++++ java/util/AbstractSet.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,5 @@
+ /* AbstractSet.java -- Abstract implementation of most of Set
+-   Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -35,28 +35,10 @@
+  * on them - specifically, no element may be in the set more than once). This
+  * class simply provides implementations of equals() and hashCode() to fulfil
+  * the requirements placed on them by the Set interface.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see AbstractCollection
+- * @see Set
+- * @see HashSet
+- * @see TreeSet
+- * @see LinkedHashSet
+- * @since 1.2
+- * @status updated to 1.4
+  */
+ public abstract class AbstractSet extends AbstractCollection implements Set
+ {
+   /**
+-   * The main constructor, for use by subclasses.
+-   */
+-  protected AbstractSet()
+-  {
+-  }
+-
+-  /**
+    * Tests whether the given object is equal to this Set. This implementation
+    * first checks whether this set <em>is</em> the given object, and returns
+    * true if so. Otherwise, if o is a Set and is the same size as this one, it
+@@ -68,9 +50,12 @@
+    */
+   public boolean equals(Object o)
+   {
+-    return (o == this ||
+-            (o instanceof Set && ((Set) o).size() == size()
+-             && containsAll((Collection) o)));
++    if (o == this)
++      return true;
++    else if (o instanceof Set && ((Set) o).size() == size())
++      return containsAll((Collection) o);
++    else
++      return false;
+   }
+ 
+   /**
+@@ -84,43 +69,14 @@
+   public int hashCode()
+   {
+     Iterator itr = iterator();
++    int size = size();
+     int hash = 0;
+-    int pos = size();
+-    while (--pos >= 0)
+-      hash += hashCode(itr.next());
++    for (int pos = 0; pos < size; pos++)
++      {
++	Object obj = itr.next();
++	if (obj != null)
++	  hash += obj.hashCode();
++      }
+     return hash;
+   }
+-
+-  /**
+-   * Removes from this set all elements in the given collection (optional
+-   * operation). This implementation uses <code>size()</code> to determine
+-   * the smaller collection.  Then, if this set is smaller, it iterates
+-   * over the set, calling Iterator.remove if the collection contains
+-   * the element.  If this set is larger, it iterates over the collection,
+-   * calling Set.remove for all elements in the collection. Note that
+-   * this operation will fail if a remove methods is not supported.
+-   *
+-   * @param c the collection of elements to remove
+-   * @return true if the set was modified as a result
+-   * @throws UnsupportedOperationException if remove is not supported
+-   * @throws NullPointerException if the collection is null
+-   * @see AbstractCollection#remove(Object)
+-   * @see Collection#contains(Object)
+-   * @see Iterator#remove()
+-   */
+-  public boolean removeAll(Collection c)
+-  {
+-    int oldsize = size();
+-    int count = c.size();
+-    Iterator i;
+-    if (oldsize < count)
+-      for (i = iterator(), count = oldsize; count > 0; count--)
+-        if (c.contains(i.next()))
+-          i.remove();
+-    else
+-      for (i = c.iterator(); count > 0; count--)
+-        remove(i.next());
+-    return oldsize != size();
+-  }
+-
+ }
Index: compare/java.util.ArrayList.diff
===================================================================
RCS file: java.util.ArrayList.diff
diff -N java.util.ArrayList.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.ArrayList.diff Tue Nov 6 17:21:28 2001
@@ -0,0 +1,764 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/ArrayList.java	Fri Oct 26 16:06:57 2001
++++ java/util/ArrayList.java	Tue Oct 16 09:14:34 2001
+@@ -1,6 +1,6 @@
+ /* ArrayList.java -- JDK1.2's answer to Vector; this is an array-backed
+    implementation of the List interface
+-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -35,534 +35,383 @@
+ import java.io.ObjectOutputStream;
+ 
+ /**
+- * An array-backed implementation of the List interface.  This implements
+- * all optional list operations, and permits null elements, so that it is
+- * better than Vector, which it replaces. Random access is roughly constant
+- * time, and iteration is roughly linear time, so it is nice and fast, with
+- * less overhead than a LinkedList.
+- * <p>
++ * An array-backed implementation of the List interface.  ArrayList
++ * performs well on simple tasks:  random access into a list, appending
++ * to or removing from the end of a list, checking the size, &c.
+  *
+- * Each list has a capacity, and as the array reaches that capacity it
+- * is automatically transferred to a larger array. You also have access to
+- * ensureCapacity and trimToSize to control the backing array's size, avoiding
+- * reallocation or wasted memory.
+- * <p>
+- *
+- * ArrayList is not synchronized, so if you need multi-threaded access,
+- * consider using:<br>
+- * <code>List l = Collections.synchronizedList(new ArrayList(...));</code>
+- * <p>
+- *
+- * The iterators are <i>fail-fast</i>, meaning that any structural
+- * modification, except for <code>remove()</code> called on the iterator
+- * itself, cause the iterator to throw a
+- * {@link ConcurrentModificationException} rather than exhibit
+- * non-deterministic behavior.
+- *
+- * @author Jon A. Zeppieri
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see List
+- * @see LinkedList
+- * @see Vector
+- * @see Collections#synchronizedList(List)
+- * @see AbstractList
+- * @status updated to 1.4
++ * @author        Jon A. Zeppieri
++ * @see           java.util.AbstractList
++ * @see           java.util.List
+  */
+ public class ArrayList extends AbstractList
+-  implements List, RandomAccess, Cloneable, Serializable
++  implements List, Cloneable, Serializable
+ {
+-  /**
+-   * Compatible with JDK 1.2
+-   */
+-  private static final long serialVersionUID = 8683452581122892189L;
+-
+-  /**
+-   * The default capacity for new ArrayLists.
+-   */
++  /** the default capacity for new ArrayLists */
+   private static final int DEFAULT_CAPACITY = 16;
+ 
+-  /**
+-   * The number of elements in this list.
+-   * @serial the list size
+-   */
+-  private int size;
++  /** the number of elements in this list */
++  int size;
+ 
+-  /**
+-   * Where the data is stored.
+-   */
+-  private transient Object[] data;
++  /** where the data is stored */
++  transient Object[] data;
+ 
+-  /**
+-   * Construct a new ArrayList with the supplied initial capacity.
++  /** 
++   * Construct a new ArrayList with the supplied initial capacity. 
+    *
+-   * @param capacity initial capacity of this ArrayList
+-   * @throws IllegalArgumentException if capacity is negative
++   * @param capacity Initial capacity of this ArrayList
+    */
+   public ArrayList(int capacity)
+   {
+-    // Must explicitly check, to get correct exception.
+-    if (capacity < 0)
+-      throw new IllegalArgumentException();
+     data = new Object[capacity];
+   }
+ 
++
+   /**
+-   * Construct a new ArrayList with the default capcity (16).
++   * Construct a new ArrayList with the default capcity 
+    */
+   public ArrayList()
+   {
+     this(DEFAULT_CAPACITY);
+   }
+ 
+-  /**
++  /** 
+    * Construct a new ArrayList, and initialize it with the elements
+-   * in the supplied Collection. The initial capacity is 110% of the
+-   * Collection's size.
++   * in the supplied Collection; Sun specs say that the initial 
++   * capacity is 110% of the Collection's size.
+    *
+    * @param c the collection whose elements will initialize this list
+-   * @throws NullPointerException if c is null
+    */
+   public ArrayList(Collection c)
+   {
+-    this((int) (c.size() * 1.1f));
++    this((int) (c.size() * 1.1));
+     addAll(c);
+   }
+ 
+   /**
+-   * Trims the capacity of this List to be equal to its size;
+-   * a memory saver.
+-   */
+-  public void trimToSize()
+-  {
+-    // Not a structural change from the perspective of iterators on this list,
+-    // so don't update modCount.
+-    if (size != data.length)
+-      {
+-        Object[] newData = new Object[size];
+-        System.arraycopy(data, 0, newData, 0, size);
+-        data = newData;
+-      }
+-  }
+-
+-  /**
+    * Guarantees that this list will have at least enough capacity to
+-   * hold minCapacity elements. This implementation will grow the list to
+-   * max(current * 2, minCapacity) if (minCapacity > current). The JCL says
+-   * explictly that "this method increases its capacity to minCap", while
+-   * the JDK 1.3 online docs specify that the list will grow to at least the
+-   * size specified.
++   * hold minCapacity elements. 
+    *
++   * @specnote This implementation will grow the list to 
++   *   max(current * 2, minCapacity) if (minCapacity > current). The JCL says
++   *   explictly that "this method increases its capacity to minCap", while
++   *   the JDK 1.3 online docs specify that the list will grow to at least the
++   *   size specified.
+    * @param minCapacity the minimum guaranteed capacity
+    */
+   public void ensureCapacity(int minCapacity)
+   {
++    Object[] newData;
+     int current = data.length;
+ 
+     if (minCapacity > current)
+       {
+-        Object[] newData = new Object[Math.max(current * 2, minCapacity)];
+-        System.arraycopy(data, 0, newData, 0, size);
+-        data = newData;
++	newData = new Object[Math.max((current * 2), minCapacity)];
++	System.arraycopy(data, 0, newData, 0, size);
++	data = newData;
+       }
+   }
+ 
+   /**
+-   * Returns the number of elements in this list.
+-   *
+-   * @return the list size
+-   */
+-  public int size()
+-  {
+-    return size;
+-  }
+-
+-  /**
+-   * Checks if the list is empty.
++   * Appends the supplied element to the end of this list.
+    *
+-   * @return true if there are no elements
++   * @param       e      the element to be appended to this list
+    */
+-  public boolean isEmpty()
++  public boolean add(Object e)
+   {
+-    return size == 0;
++    modCount++;
++    if (size == data.length)
++      ensureCapacity(size + 1);
++    data[size++] = e;
++    return true;
+   }
+ 
+   /**
+-   * Returns true iff element is in this ArrayList.
++   * Retrieves the element at the user-supplied index.
+    *
+-   * @param e the element whose inclusion in the List is being tested
+-   * @return true if the list contains e
++   * @param    index        the index of the element we are fetching
++   * @throws   IndexOutOfBoundsException  (iIndex < 0) || (iIndex >= size())
+    */
+-  public boolean contains(Object e)
++  public Object get(int index)
+   {
+-    return indexOf(e) != -1;
++    if (index < 0 || index >= size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
++    return data[index];
+   }
+ 
+   /**
+-   * Returns the lowest index at which element appears in this List, or
+-   * -1 if it does not appear.
+-   *
+-   * @param e the element whose inclusion in the List is being tested
+-   * @return the index where e was found
++   * Returns the number of elements in this list 
+    */
+-  public int indexOf(Object e)
++  public int size()
+   {
+-    for (int i = 0; i < size; i++)
+-      if (equals(e, data[i]))
+-        return i;
+-    return -1;
++    return size;
+   }
+ 
+   /**
+-   * Returns the highest index at which element appears in this List, or
+-   * -1 if it does not appear.
++   * Removes the element at the user-supplied index
+    *
+-   * @param e the element whose inclusion in the List is being tested
+-   * @return the index where e was found
++   * @param     iIndex      the index of the element to be removed
++   * @return    the removed Object
++   * @throws    IndexOutOfBoundsException  (iIndex < 0) || (iIndex >= size())
+    */
+-  public int lastIndexOf(Object e)
++  public Object remove(int index)
+   {
+-    for (int i = size - 1; i >= 0; i--)
+-      if (equals(e, data[i]))
+-        return i;
+-    return -1;
++    modCount++;
++    if (index < 0 || index > size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
++    Object r = data[index];
++    if (index != --size)
++      System.arraycopy(data, (index + 1), data, index, (size - index));
++    data[size] = null;
++    return r;
+   }
+ 
+   /**
+-   * Creates a shallow copy of this ArrayList (elements are not cloned).
++   * Removes all elements in the half-open interval [iFromIndex, iToIndex).
+    *
+-   * @return the cloned object
++   * @param     fromIndex   the first index which will be removed
++   * @param     toIndex     one greater than the last index which will be 
++   *                         removed
+    */
+-  public Object clone()
++  protected void removeRange(int fromIndex, int toIndex)
+   {
+-    ArrayList clone = null;
+-    try
+-      {
+-        clone = (ArrayList) super.clone();
+-        clone.data = (Object[]) data.clone();
+-      }
+-    catch (CloneNotSupportedException e)
++    modCount++;
++    if (fromIndex != toIndex)
+       {
+-        // Impossible to get here.
++	System.arraycopy(data, toIndex, data, fromIndex, size - toIndex);
++	size -= (toIndex - fromIndex);
+       }
+-    return clone;
+-  }
+-
+-  /**
+-   * Returns an Object array containing all of the elements in this ArrayList.
+-   * The array is independent of this list.
+-   *
+-   * @return an array representation of this list
+-   */
+-  public Object[] toArray()
+-  {
+-    Object[] array = new Object[size];
+-    System.arraycopy(data, 0, array, 0, size);
+-    return array;
+-  }
+-
+-  /**
+-   * Returns an Array whose component type is the runtime component type of
+-   * the passed-in Array.  The returned Array is populated with all of the
+-   * elements in this ArrayList.  If the passed-in Array is not large enough
+-   * to store all of the elements in this List, a new Array will be created
+-   * and returned; if the passed-in Array is <i>larger</i> than the size
+-   * of this List, then size() index will be set to null.
+-   *
+-   * @param a the passed-in Array
+-   * @return an array representation of this list
+-   * @throws ArrayStoreException if the runtime type of a does not allow
+-   *         an element in this list
+-   * @throws NullPointerException if a is null
+-   */
+-  public Object[] toArray(Object[] a)
+-  {
+-    if (a.length < size)
+-      a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
+-                                       size);
+-    else if (a.length > size)
+-      a[size] = null;
+-    System.arraycopy(data, 0, a, 0, size);
+-    return a;
+-  }
+-
+-  /**
+-   * Retrieves the element at the user-supplied index.
+-   *
+-   * @param index the index of the element we are fetching
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   */
+-  public Object get(int index)
+-  {
+-    checkBoundExclusive(index);
+-    return data[index];
+-  }
+-
+-  /**
+-   * Sets the element at the specified index.
+-   *
+-   * @param index the index at which the element is being set
+-   * @param e the element to be set
+-   * @return the element previously at the specified index
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= 0
+-   */
+-  public Object set(int index, Object e)
+-  {
+-    checkBoundExclusive(index);
+-    Object result = data[index];
+-    data[index] = e;
+-    return result;
+-  }
+-
+-  /**
+-   * Appends the supplied element to the end of this list.
+-   *
+-   * @param e the element to be appended to this list
+-   * @return true, the add will always succeed
+-   */
+-  public boolean add(Object e)
+-  {
+-    modCount++;
+-    if (size == data.length)
+-      ensureCapacity(size + 1);
+-    data[size++] = e;
+-    return true;
+   }
+ 
+   /**
+    * Adds the supplied element at the specified index, shifting all
+    * elements currently at that index or higher one to the right.
+    *
+-   * @param index the index at which the element is being added
+-   * @param e the item being added
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
++   * @param     index      the index at which the element is being added
++   * @param     e          the item being added
+    */
+   public void add(int index, Object e)
+   {
+-    checkBoundInclusive(index);
+     modCount++;
++    if (index < 0 || index > size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
+     if (size == data.length)
+       ensureCapacity(size + 1);
+     if (index != size)
+-      System.arraycopy(data, index, data, index + 1, size - index);
++      System.arraycopy(data, index, data, index + 1, size - index);    
+     data[index] = e;
+     size++;
+   }
+ 
+-  /**
+-   * Removes the element at the user-supplied index.
++  /** 
++   * Add each element in the supplied Collection to this List.
+    *
+-   * @param index the index of the element to be removed
+-   * @return the removed Object
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   */
+-  public Object remove(int index)
+-  {
+-    checkBoundExclusive(index);
+-    Object r = data[index];
+-    modCount++;
+-    if (index != --size)
+-      System.arraycopy(data, index + 1, data, index, size - index);
+-    // Aid for garbage collection by releasing this pointer.
+-    data[size] = null;
+-    return r;
+-  }
+-
+-  /**
+-   * Removes all elements from this List
+-   */
+-  public void clear()
+-  {
+-    if (size > 0)
+-      {
+-        modCount++;
+-        // Allow for garbage collection.
+-        Arrays.fill(data, 0, size, null);
+-        size = 0;
+-      }
+-  }
+-
+-  /**
+-   * Add each element in the supplied Collection to this List. It is undefined
+-   * what happens if you modify the list while this is taking place; for
+-   * example, if the collection contains this list.
+-   *
+-   * @param c a Collection containing elements to be added to this List
+-   * @return true if the list was modified, in other words c is not empty
+-   * @throws NullPointerException if c is null
++   * @param        c          a Collection containing elements to be 
++   *                          added to this List
+    */
+   public boolean addAll(Collection c)
+   {
+     return addAll(size, c);
+   }
+ 
+-  /**
++  /** 
+    * Add all elements in the supplied collection, inserting them beginning
+    * at the specified index.
+    *
+-   * @param index the index at which the elements will be inserted
+-   * @param c the Collection containing the elements to be inserted
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; 0
+-   * @throws NullPointerException if c is null
++   * @param     index       the index at which the elements will be inserted
++   * @param     c           the Collection containing the elements to be
++   *                        inserted
+    */
+   public boolean addAll(int index, Collection c)
+   {
+-    checkBoundInclusive(index);
++    if (index < 0 || index > size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
++    modCount++;
+     Iterator itr = c.iterator();
+     int csize = c.size();
+ 
+-    modCount++;
+     if (csize + size > data.length)
+       ensureCapacity(size + csize);
+     int end = index + csize;
+-    if (index != size)
++    if (size > 0 && index != size)
+       System.arraycopy(data, index, data, end, csize);
+     size += csize;
+-    for ( ; index < end; index++)
+-      data[index] = itr.next();
+-    return csize > 0;
++    for (; index < end; index++)
++      {
++        data[index] = itr.next();
++      }
++    return (csize > 0);
+   }
+ 
+   /**
+-   * Removes all elements in the half-open interval [fromIndex, toIndex).
+-   * You asked for it if you call this with invalid arguments.
+-   *
+-   * @param fromIndex the first index which will be removed
+-   * @param toIndex one greater than the last index which will be removed
++   * Creates a shallow copy of this ArrayList
+    */
+-  protected void removeRange(int fromIndex, int toIndex)
++  public Object clone()
+   {
+-    if (fromIndex != toIndex)
++    ArrayList clone = null;
++    try
+       {
+-        modCount++;
+-        System.arraycopy(data, toIndex, data, fromIndex, size - toIndex);
+-        size -= toIndex - fromIndex;
++	clone = (ArrayList) super.clone();
++	clone.data = new Object[data.length];
++	System.arraycopy(data, 0, clone.data, 0, size);
+       }
++    catch (CloneNotSupportedException e) {}
++    return clone;
+   }
+ 
+-  /**
+-   * Checks that the index is in the range of possible elements (inclusive).
++  /** 
++   * Returns true iff oElement is in this ArrayList.
+    *
+-   * @param index the index to check
+-   * @throws IndexOutOfBoundsException if index &gt; size
++   * @param     e     the element whose inclusion in the List is being
++   *                  tested
+    */
+-  private void checkBoundInclusive(int index)
++  public boolean contains(Object e)
+   {
+-    // Implementation note: we do not check for negative ranges here, since
+-    // use of a negative index will cause an ArrayIndexOutOfBoundsException,
+-    // a subclass of the required exception, with no effort on our part.
+-    if (index > size)
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size);
++    return (indexOf(e) != -1);
+   }
+ 
+   /**
+-   * Checks that the index is in the range of existing elements (exclusive).
++   * Returns the lowest index at which oElement appears in this List, or 
++   * -1 if it does not appear.
+    *
+-   * @param index the index to check
+-   * @throws IndexOutOfBoundsException if index &gt;= size
++   * @param    e       the element whose inclusion in the List is being
++   *                   tested
+    */
+-  private void checkBoundExclusive(int index)
++  public int indexOf(Object e)
+   {
+-    // Implementation note: we do not check for negative ranges here, since
+-    // use of a negative index will cause an ArrayIndexOutOfBoundsException,
+-    // a subclass of the required exception, with no effort on our part.
+-    if (index >= size)
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size);
++    for (int i = 0; i < size; i++)
++      {
++	if (e == null ? data[i] == null : e.equals(data[i]))
++	  return i;
++      }
++    return -1;
+   }
+ 
+   /**
+-   * Remove from this list all elements contained in the given collection.
+-   * This is not public, due to Sun's API, but this performs in linear
+-   * time while the default behavior of AbstractList would be quadratic.
++   * Returns the highest index at which oElement appears in this List, or 
++   * -1 if it does not appear.
+    *
+-   * @param c the collection to filter out
+-   * @return true if this list changed
+-   * @throws NullPointerException if c is null
++   * @param    e       the element whose inclusion in the List is being
++   *                   tested
+    */
+-  boolean removeAllInternal(Collection c)
++  public int lastIndexOf(Object e)
+   {
+     int i;
+-    int j;
+-    for (i = 0; i < size; i++)
+-      if (c.contains(data[i]))
+-        break;
+-    if (i == size)
+-      return false;
+ 
+-    modCount++;
+-    for (j = i++; i < size; i++)
+-      if (! c.contains(data[i]))
+-        data[j++] = data[i];
+-    size -= i - j;
+-    return true;
++    for (i = size - 1; i >= 0; i--)
++      {
++	if (e == null ? data[i] == null : e.equals(data[i]))
++	  return i;
++      }
++    return -1;
+   }
+ 
+   /**
+-   * Retain in this vector only the elements contained in the given collection.
+-   * This is not public, due to Sun's API, but this performs in linear
+-   * time while the default behavior of AbstractList would be quadratic.
+-   *
+-   * @param c the collection to filter by
+-   * @return true if this vector changed
+-   * @throws NullPointerException if c is null
+-   * @since 1.2
++   * Removes all elements from this List
+    */
+-  boolean retainAllInternal(Collection c)
++  public void clear()
+   {
+-    int i;
+-    int j;
+-    for (i = 0; i < size; i++)
+-      if (! c.contains(data[i]))
+-        break;
+-    if (i == size)
+-      return false;
+-
+     modCount++;
+-    for (j = i++; i < size; i++)
+-      if (c.contains(data[i]))
+-        data[j++] = data[i];
+-    size -= i - j;
+-    return true;
++    for (int i = 0; i < size; i++)
++      {
++	data[i] = null;
++      }    
++    size = 0;
+   }
+ 
+   /**
+-   * Serializes this object to the given stream.
++   * Sets the element at the specified index.
+    *
+-   * @param out the stream to write to
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the size field (int), the length of the backing array
+-   *             (int), followed by its elements (Objects) in proper order.
++   * @param     index   the index at which the element is being set
++   * @param     e       the element to be set
++   * @return    the element previously at the specified index, or null if
++   *            none was there
+    */
+-  private void writeObject(ObjectOutputStream s) throws IOException
++  public Object set(int index, Object e)
+   {
+-    // The 'size' field.
+-    s.defaultWriteObject();
+-    // We serialize unused list entries to preserve capacity.
+-    int len = data.length;
+-    s.writeInt(len);
+-    for (int i = 0; i < len; i++)
+-      s.writeObject(data[i]);
++    Object result;
++    if (index < 0 || index >= size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
++    result = data[index];
++    // SEH: no structural change, so don't update modCount
++    data[index] = e;
++    return result;
+   }
+ 
+   /**
+-   * Deserializes this object from the given stream.
++   * Returns an Object Array containing all of the elements in this ArrayList
++   */
++  public Object[] toArray()
++  {
++    Object[] array = new Object[size];
++    System.arraycopy(data, 0, array, 0, size);
++    return array;
++  }
++
++  /**
++   * Returns an Array whose component type is the runtime component type of
++   * the passed-in Array.  The returned Array is populated with all of the
++   * elements in this ArrayList.  If the passed-in Array is not large enough
++   * to store all of the elements in this List, a new Array will be created 
++   * and returned; if the passed-in Array is <i>larger</i> than the size
++   * of this List, then size() index will be set to null.
+    *
+-   * @param in the stream to read from
+-   * @throws ClassNotFoundException if the underlying stream fails
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the size field (int), the length of the backing array
+-   *             (int), followed by its elements (Objects) in proper order.
++   * @param      array      the passed-in Array
+    */
+-  private void readObject(ObjectInputStream s)
++  public Object[] toArray(Object[] array)
++  {
++    if (array.length < size)
++      array = (Object[]) Array.newInstance(array.getClass().getComponentType(), 
++        				   size);
++    else if (array.length > size)
++      array[size] = null;
++    System.arraycopy(data, 0, array, 0, size);
++    return array;
++  }
++
++  /**
++   * Trims the capacity of this List to be equal to its size; 
++   * a memory saver.   
++   */
++  public void trimToSize()
++  {
++    // not a structural change from the perspective of iterators on this list, 
++    // so don't update modCount
++    Object[] newData = new Object[size];
++    System.arraycopy(data, 0, newData, 0, size);
++    data = newData;
++  }
++
++  private void writeObject(ObjectOutputStream out) throws IOException
++  {
++    int i;
++
++    // The 'size' field.
++    out.defaultWriteObject();
++
++    // FIXME: Do we really want to serialize unused list entries??
++    out.writeInt(data.length);
++    for (i = 0; i < data.length; i++)
++      out.writeObject(data[i]);
++  }
++
++  private void readObject(ObjectInputStream in)
+     throws IOException, ClassNotFoundException
+   {
++    int i;
++    int capacity;
++
+     // the `size' field.
+-    s.defaultReadObject();
+-    int capacity = s.readInt();
++    in.defaultReadObject();
++
++    capacity = in.readInt();
+     data = new Object[capacity];
+-    for (int i = 0; i < capacity; i++)
+-      data[i] = s.readObject();
++
++    for (i = 0; i < capacity; i++)
++      data[i] = in.readObject();
+   }
+ }
Index: compare/java.util.Arrays.diff
===================================================================
RCS file: java.util.Arrays.diff
diff -N java.util.Arrays.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Arrays.diff Tue Nov 6 17:21:29 2001
@@ -0,0 +1,3657 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Arrays.java	Fri Oct 26 16:06:57 2001
++++ java/util/Arrays.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,5 @@
+ /* Arrays.java -- Utility class with methods to operate on arrays
+-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -25,32 +25,16 @@
+ executable file might be covered by the GNU General Public License. */
+ 
+ 
+-package java.util;
++// TO DO:
++// ~ Fix the behaviour of sort and binarySearch as applied to float and double
++//   arrays containing NaN values. See the JDC, bug ID 4143272.
+ 
+-import java.io.Serializable;
+-import java.lang.reflect.Array;
++package java.util;
+ 
+ /**
+  * This class contains various static utility methods performing operations on
+  * arrays, and a method to provide a List "view" of an array to facilitate
+- * using arrays with Collection-based APIs. All methods throw a
+- * {@link NullPointerException} if the parameter array is null.
+- * <p>
+- *
+- * Implementations may use their own algorithms, but must obey the general
+- * properties; for example, the sort must be stable and n*log(n) complexity.
+- * Sun's implementation of sort, and therefore ours, is a tuned quicksort,
+- * adapted from Jon L. Bentley and M. Douglas McIlroy's "Engineering a Sort
+- * Function", Software-Practice and Experience, Vol. 23(11) P. 1249-1265
+- * (November 1993). This algorithm offers n*log(n) performance on many data
+- * sets that cause other quicksorts to degrade to quadratic performance.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Comparable
+- * @see Comparator
+- * @since 1.2
+- * @status updated to 1.4
++ * using arrays with Collection-based APIs.
+  */
+ public class Arrays
+ {
+@@ -61,8 +45,14 @@
+   {
+   }
+ 
+-
+-// binarySearch
++  private static Comparator defaultComparator = new Comparator()
++  {
++    public int compare(Object o1, Object o2)
++    {
++      return ((Comparable) o1).compareTo(o2);
++    }
++  };
++
+   /**
+    * Perform a binary search of a byte array for a key. The array must be
+    * sorted (as by the sort() method) - if it is not, the behaviour of this
+@@ -73,26 +63,32 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
+    */
+-  public static int binarySearch(byte[] a, byte key)
++  public static int binarySearch(byte[]a, byte key)
+   {
+     int low = 0;
+     int hi = a.length - 1;
+     int mid = 0;
+     while (low <= hi)
+       {
+-        mid = (low + hi) >> 1;
+-        final byte d = a[mid];
+-        if (d == key)
+-          return mid;
+-        else if (d > key)
+-          hi = mid - 1;
+-        else
+-          // This gets the insertion point right on the last loop.
+-          low = ++mid;
++	mid = (low + hi) >> 1;
++	final byte d = a[mid];
++	if (d == key)
++	  {
++	    return mid;
++	  }
++	else if (d > key)
++	  {
++	    hi = mid - 1;
++	  }
++	else
++	  {
++	    // This gets the insertion point right on the last loop
++	    low = ++mid;
++	  }
+       }
+     return -mid - 1;
+   }
+@@ -107,32 +103,38 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
+    */
+-  public static int binarySearch(char[] a, char key)
++  public static int binarySearch(char[]a, char key)
+   {
+     int low = 0;
+     int hi = a.length - 1;
+     int mid = 0;
+     while (low <= hi)
+       {
+-        mid = (low + hi) >> 1;
+-        final char d = a[mid];
+-        if (d == key)
+-          return mid;
+-        else if (d > key)
+-          hi = mid - 1;
+-        else
+-          // This gets the insertion point right on the last loop.
+-          low = ++mid;
++	mid = (low + hi) >> 1;
++	final char d = a[mid];
++	if (d == key)
++	  {
++	    return mid;
++	  }
++	else if (d > key)
++	  {
++	    hi = mid - 1;
++	  }
++	else
++	  {
++	    // This gets the insertion point right on the last loop
++	    low = ++mid;
++	  }
+       }
+     return -mid - 1;
+   }
+ 
+   /**
+-   * Perform a binary search of a short array for a key. The array must be
++   * Perform a binary search of a double array for a key. The array must be
+    * sorted (as by the sort() method) - if it is not, the behaviour of this
+    * method is undefined, and may be an infinite loop. If the array contains
+    * the key more than once, any one of them may be found. Note: although the
+@@ -141,32 +143,38 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
+    */
+-  public static int binarySearch(short[] a, short key)
++  public static int binarySearch(double[]a, double key)
+   {
+     int low = 0;
+     int hi = a.length - 1;
+     int mid = 0;
+     while (low <= hi)
+       {
+-        mid = (low + hi) >> 1;
+-        final short d = a[mid];
+-        if (d == key)
+-          return mid;
+-        else if (d > key)
+-          hi = mid - 1;
+-        else
+-          // This gets the insertion point right on the last loop.
+-          low = ++mid;
++	mid = (low + hi) >> 1;
++	final double d = a[mid];
++	if (d == key)
++	  {
++	    return mid;
++	  }
++	else if (d > key)
++	  {
++	    hi = mid - 1;
++	  }
++	else
++	  {
++	    // This gets the insertion point right on the last loop
++	    low = ++mid;
++	  }
+       }
+     return -mid - 1;
+   }
+ 
+   /**
+-   * Perform a binary search of an int array for a key. The array must be
++   * Perform a binary search of a float array for a key. The array must be
+    * sorted (as by the sort() method) - if it is not, the behaviour of this
+    * method is undefined, and may be an infinite loop. If the array contains
+    * the key more than once, any one of them may be found. Note: although the
+@@ -175,32 +183,38 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
+    */
+-  public static int binarySearch(int[] a, int key)
++  public static int binarySearch(float[]a, float key)
+   {
+     int low = 0;
+     int hi = a.length - 1;
+     int mid = 0;
+     while (low <= hi)
+       {
+-        mid = (low + hi) >> 1;
+-        final int d = a[mid];
+-        if (d == key)
+-          return mid;
+-        else if (d > key)
+-          hi = mid - 1;
+-        else
+-          // This gets the insertion point right on the last loop.
+-          low = ++mid;
++	mid = (low + hi) >> 1;
++	final float d = a[mid];
++	if (d == key)
++	  {
++	    return mid;
++	  }
++	else if (d > key)
++	  {
++	    hi = mid - 1;
++	  }
++	else
++	  {
++	    // This gets the insertion point right on the last loop
++	    low = ++mid;
++	  }
+       }
+     return -mid - 1;
+   }
+ 
+   /**
+-   * Perform a binary search of a long array for a key. The array must be
++   * Perform a binary search of an int array for a key. The array must be
+    * sorted (as by the sort() method) - if it is not, the behaviour of this
+    * method is undefined, and may be an infinite loop. If the array contains
+    * the key more than once, any one of them may be found. Note: although the
+@@ -209,32 +223,38 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
+    */
+-  public static int binarySearch(long[] a, long key)
++  public static int binarySearch(int[]a, int key)
+   {
+     int low = 0;
+     int hi = a.length - 1;
+     int mid = 0;
+     while (low <= hi)
+       {
+-        mid = (low + hi) >> 1;
+-        final long d = a[mid];
+-        if (d == key)
+-          return mid;
+-        else if (d > key)
+-          hi = mid - 1;
+-        else
+-          // This gets the insertion point right on the last loop.
+-          low = ++mid;
++	mid = (low + hi) >> 1;
++	final int d = a[mid];
++	if (d == key)
++	  {
++	    return mid;
++	  }
++	else if (d > key)
++	  {
++	    hi = mid - 1;
++	  }
++	else
++	  {
++	    // This gets the insertion point right on the last loop
++	    low = ++mid;
++	  }
+       }
+     return -mid - 1;
+   }
+ 
+   /**
+-   * Perform a binary search of a float array for a key. The array must be
++   * Perform a binary search of a long array for a key. The array must be
+    * sorted (as by the sort() method) - if it is not, the behaviour of this
+    * method is undefined, and may be an infinite loop. If the array contains
+    * the key more than once, any one of them may be found. Note: although the
+@@ -243,33 +263,38 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
+    */
+-  public static int binarySearch(float[] a, float key)
++  public static int binarySearch(long[]a, long key)
+   {
+-    // Must use Float.compare to take into account NaN, +-0.
+     int low = 0;
+     int hi = a.length - 1;
+     int mid = 0;
+     while (low <= hi)
+       {
+-        mid = (low + hi) >> 1;
+-        final int r = Float.compare(a[mid], key);
+-        if (r == 0)
+-          return mid;
+-        else if (r > 0)
+-          hi = mid - 1;
+-        else
+-          // This gets the insertion point right on the last loop
+-          low = ++mid;
++	mid = (low + hi) >> 1;
++	final long d = a[mid];
++	if (d == key)
++	  {
++	    return mid;
++	  }
++	else if (d > key)
++	  {
++	    hi = mid - 1;
++	  }
++	else
++	  {
++	    // This gets the insertion point right on the last loop
++	    low = ++mid;
++	  }
+       }
+     return -mid - 1;
+   }
+ 
+   /**
+-   * Perform a binary search of a double array for a key. The array must be
++   * Perform a binary search of a short array for a key. The array must be
+    * sorted (as by the sort() method) - if it is not, the behaviour of this
+    * method is undefined, and may be an infinite loop. If the array contains
+    * the key more than once, any one of them may be found. Note: although the
+@@ -278,27 +303,63 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
+    */
+-  public static int binarySearch(double[] a, double key)
++  public static int binarySearch(short[]a, short key)
+   {
+-    // Must use Double.compare to take into account NaN, +-0.
+     int low = 0;
+     int hi = a.length - 1;
+     int mid = 0;
+     while (low <= hi)
+       {
+-        mid = (low + hi) >> 1;
+-        final int r = Double.compare(a[mid], key);
+-        if (r == 0)
+-          return mid;
+-        else if (r > 0)
+-          hi = mid - 1;
+-        else
+-          // This gets the insertion point right on the last loop
+-          low = ++mid;
++	mid = (low + hi) >> 1;
++	final short d = a[mid];
++	if (d == key)
++	  {
++	    return mid;
++	  }
++	else if (d > key)
++	  {
++	    hi = mid - 1;
++	  }
++	else
++	  {
++	    // This gets the insertion point right on the last loop
++	    low = ++mid;
++	  }
++      }
++    return -mid - 1;
++  }
++
++  /**
++   * This method does the work for the Object binary search methods. 
++   * @exception NullPointerException if the specified comparator is null.
++   * @exception ClassCastException if the objects are not comparable by c.
++   */
++  private static int objectSearch(Object[]a, Object key, final Comparator c)
++  {
++    int low = 0;
++    int hi = a.length - 1;
++    int mid = 0;
++    while (low <= hi)
++      {
++	mid = (low + hi) >> 1;
++	final int d = c.compare(key, a[mid]);
++	if (d == 0)
++	  {
++	    return mid;
++	  }
++	else if (d < 0)
++	  {
++	    hi = mid - 1;
++	  }
++	else
++	  {
++	    // This gets the insertion point right on the last loop
++	    low = ++mid;
++	  }	    
+       }
+     return -mid - 1;
+   }
+@@ -315,16 +376,16 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
+-   * @throws ClassCastException if key could not be compared with one of the
+-   *         elements of a
+-   * @throws NullPointerException if a null element in a is compared
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
++   * @exception ClassCastException if key could not be compared with one of the
++   *   elements of a
++   * @exception NullPointerException if a null element has compareTo called
+    */
+-  public static int binarySearch(Object[] a, Object key)
++  public static int binarySearch(Object[]a, Object key)
+   {
+-    return binarySearch(a, key, null);
++    return objectSearch(a, key, defaultComparator);
+   }
+ 
+   /**
+@@ -339,310 +400,343 @@
+    *
+    * @param a the array to search (must be sorted)
+    * @param key the value to search for
+-   * @param c the comparator by which the array is sorted; or null to
+-   *        use the elements' natural order
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value.
+-   * @throws ClassCastException if key could not be compared with one of the
+-   *         elements of a
+-   * @throws NullPointerException if a null element is compared with natural
+-   *         ordering (only possible when c is null)
++   * @param c the comparator by which the array is sorted
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
++   * @exception ClassCastException if key could not be compared with one of the
++   *   elements of a
+    */
+-  public static int binarySearch(Object[] a, Object key, Comparator c)
++  public static int binarySearch(Object[]a, Object key, Comparator c)
+   {
+-    int low = 0;
+-    int hi = a.length - 1;
+-    int mid = 0;
+-    while (low <= hi)
+-      {
+-        mid = (low + hi) >> 1;
+-        final int d = Collections.compare(key, a[mid], c);
+-        if (d == 0)
+-          return mid;
+-        else if (d < 0)
+-          hi = mid - 1;
+-        else
+-          // This gets the insertion point right on the last loop
+-          low = ++mid;
+-      }
+-    return -mid - 1;
++    return objectSearch(a, key, c);
+   }
+ 
+-
+-// equals
+   /**
+-   * Compare two boolean arrays for equality.
++   * Compare two byte arrays for equality.
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a2 is of the same length
+-   *         as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
++   * @returns true if a1 and a2 are both null, or if a2 is of the same length
++   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
+    */
+-  public static boolean equals(boolean[] a1, boolean[] a2)
++  public static boolean equals(byte[]a1, byte[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (a1[i] != a2[i])
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (a1[i] != a2[i])
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
+ 
+     return false;
+   }
+ 
+   /**
+-   * Compare two byte arrays for equality.
++   * Compare two char arrays for equality.
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a2 is of the same length
+-   *         as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
++   * @returns true if a1 and a2 are both null, or if a2 is of the same length
++   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
+    */
+-  public static boolean equals(byte[] a1, byte[] a2)
++  public static boolean equals(char[]a1, char[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (a1[i] != a2[i])
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (a1[i] != a2[i])
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
++
+     return false;
+   }
+ 
+   /**
+-   * Compare two char arrays for equality.
++   * Compare two double arrays for equality.
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a2 is of the same length
+-   *         as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
++   * @returns true if a1 and a2 are both null, or if a2 is of the same length
++   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
+    */
+-  public static boolean equals(char[] a1, char[] a2)
++  public static boolean equals(double[]a1, double[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (a1[i] != a2[i])
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (a1[i] != a2[i])
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
++
+     return false;
+   }
+ 
+   /**
+-   * Compare two short arrays for equality.
++   * Compare two float arrays for equality.
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a2 is of the same length
+-   *         as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
++   * @returns true if a1 and a2 are both null, or if a2 is of the same length
++   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
+    */
+-  public static boolean equals(short[] a1, short[] a2)
++  public static boolean equals(float[]a1, float[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (a1[i] != a2[i])
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (a1[i] != a2[i])
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
++
+     return false;
+   }
+ 
+   /**
+-   * Compare two int arrays for equality.
++   * Compare two long arrays for equality.
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a2 is of the same length
+-   *         as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
++   * @returns true if a1 and a2 are both null, or if a2 is of the same length
++   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
+    */
+-  public static boolean equals(int[] a1, int[] a2)
++  public static boolean equals(long[]a1, long[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (a1[i] != a2[i])
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (a1[i] != a2[i])
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
++
+     return false;
+   }
+ 
+   /**
+-   * Compare two long arrays for equality.
++   * Compare two short arrays for equality.
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a2 is of the same length
+-   *         as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
++   * @returns true if a1 and a2 are both null, or if a2 is of the same length
++   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
+    */
+-  public static boolean equals(long[] a1, long[] a2)
++  public static boolean equals(short[]a1, short[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (a1[i] != a2[i])
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (a1[i] != a2[i])
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
++
+     return false;
+   }
+ 
+   /**
+-   * Compare two float arrays for equality.
++   * Compare two boolean arrays for equality.
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a2 is of the same length
+-   *         as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
++   * @returns true if a1 and a2 are both null, or if a2 is of the same length
++   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
+    */
+-  public static boolean equals(float[] a1, float[] a2)
++  public static boolean equals(boolean[]a1, boolean[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
+-    // Must use Float.compare to take into account NaN, +-0.
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (Float.compare(a1[i], a2[i]) != 0)
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (a1[i] != a2[i])
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
++
+     return false;
+   }
+ 
+   /**
+-   * Compare two double arrays for equality.
++   * Compare two int arrays for equality.
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a2 is of the same length
+-   *         as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
++   * @returns true if a1 and a2 are both null, or if a2 is of the same length
++   *   as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
+    */
+-  public static boolean equals(double[] a1, double[] a2)
++  public static boolean equals(int[]a1, int[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
+-    // Must use Double.compare to take into account NaN, +-0.
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (Double.compare(a1[i], a2[i]) != 0)
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (a1[i] != a2[i])
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
++
+     return false;
+   }
+ 
+@@ -651,46 +745,54 @@
+    *
+    * @param a1 the first array to compare
+    * @param a2 the second array to compare
+-   * @return true if a1 and a2 are both null, or if a1 is of the same length
+-   *         as a2, and for each 0 <= i < a.length, a1[i] == null ?
+-   *         a2[i] == null : a1[i].equals(a2[i]).
++   * @returns true if a1 and a2 are both null, or if a1 is of the same length
++   *   as a2, and for each 0 <= i < a.length, a1[i] == null ? a2[i] == null :
++   *   a1[i].equals(a2[i]).
+    */
+-  public static boolean equals(Object[] a1, Object[] a2)
++  public static boolean equals(Object[]a1, Object[]a2)
+   {
+     // Quick test which saves comparing elements of the same array, and also
+     // catches the case that both are null.
+     if (a1 == a2)
+-      return true;
+-
++      {
++	return true;
++      }
++      
+     try
+       {
+-        // If they're the same length, test each element
+-        if (a1.length == a2.length)
+-          {
+-            int i = a1.length;
+-            while (--i >= 0)
+-              if (! AbstractCollection.equals(a1[i], a2[i]))
+-                return false;
+-            return true;
+-          }
++	// If they're the same length, test each element
++	if (a1.length == a2.length)
++	  {
++	    for (int i = 0; i < a1.length; i++)
++	      {
++		if (!(a1[i] == null ? a2[i] == null : a1[i].equals(a2[i])))
++		  {
++		    return false;
++		  }
++	      }
++	    return true;
++	  }
++
++	// If a1 == null or a2 == null but not both then we will get a NullPointer
+       }
+     catch (NullPointerException e)
+       {
+-        // If one is null, we get a harmless NullPointerException
+       }
++
+     return false;
+   }
+ 
+-
+-// fill
+   /**
+    * Fill an array with a boolean value.
+    *
+    * @param a the array to fill
+    * @param val the value to fill it with
+    */
+-  public static void fill(boolean[] a, boolean val)
++  public static void fill(boolean[]a, boolean val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+@@ -701,16 +803,13 @@
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+    */
+-  public static void fill(boolean[] a, int fromIndex, int toIndex, boolean val)
++  public static void fill(boolean[]a, int fromIndex, int toIndex, boolean val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+   /**
+@@ -719,8 +818,11 @@
+    * @param a the array to fill
+    * @param val the value to fill it with
+    */
+-  public static void fill(byte[] a, byte val)
++  public static void fill(byte[]a, byte val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+@@ -731,16 +833,13 @@
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+    */
+-  public static void fill(byte[] a, int fromIndex, int toIndex, byte val)
++  public static void fill(byte[]a, int fromIndex, int toIndex, byte val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+   /**
+@@ -749,8 +848,11 @@
+    * @param a the array to fill
+    * @param val the value to fill it with
+    */
+-  public static void fill(char[] a, char val)
++  public static void fill(char[]a, char val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+@@ -761,166 +863,163 @@
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+    */
+-  public static void fill(char[] a, int fromIndex, int toIndex, char val)
++  public static void fill(char[]a, int fromIndex, int toIndex, char val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+   /**
+-   * Fill an array with a short value.
++   * Fill an array with a double value.
+    *
+    * @param a the array to fill
+    * @param val the value to fill it with
+    */
+-  public static void fill(short[] a, short val)
++  public static void fill(double[]a, double val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+   /**
+-   * Fill a range of an array with a short value.
++   * Fill a range of an array with a double value.
+    *
+    * @param a the array to fill
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+    */
+-  public static void fill(short[] a, int fromIndex, int toIndex, short val)
++  public static void fill(double[]a, int fromIndex, int toIndex, double val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+   /**
+-   * Fill an array with an int value.
++   * Fill an array with a float value.
+    *
+    * @param a the array to fill
+    * @param val the value to fill it with
+    */
+-  public static void fill(int[] a, int val)
++  public static void fill(float[]a, float val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+   /**
+-   * Fill a range of an array with an int value.
++   * Fill a range of an array with a float value.
+    *
+    * @param a the array to fill
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+    */
+-  public static void fill(int[] a, int fromIndex, int toIndex, int val)
++  public static void fill(float[]a, int fromIndex, int toIndex, float val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+   /**
+-   * Fill an array with a long value.
++   * Fill an array with an int value.
+    *
+    * @param a the array to fill
+    * @param val the value to fill it with
+    */
+-  public static void fill(long[] a, long val)
++  public static void fill(int[]a, int val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+   /**
+-   * Fill a range of an array with a long value.
++   * Fill a range of an array with an int value.
+    *
+    * @param a the array to fill
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+    */
+-  public static void fill(long[] a, int fromIndex, int toIndex, long val)
++  public static void fill(int[]a, int fromIndex, int toIndex, int val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+   /**
+-   * Fill an array with a float value.
++   * Fill an array with a long value.
+    *
+    * @param a the array to fill
+    * @param val the value to fill it with
+    */
+-  public static void fill(float[] a, float val)
++  public static void fill(long[]a, long val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+   /**
+-   * Fill a range of an array with a float value.
++   * Fill a range of an array with a long value.
+    *
+    * @param a the array to fill
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+    */
+-  public static void fill(float[] a, int fromIndex, int toIndex, float val)
++  public static void fill(long[]a, int fromIndex, int toIndex, long val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+   /**
+-   * Fill an array with a double value.
++   * Fill an array with a short value.
+    *
+    * @param a the array to fill
+    * @param val the value to fill it with
+    */
+-  public static void fill(double[] a, double val)
++  public static void fill(short[]a, short val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+   /**
+-   * Fill a range of an array with a double value.
++   * Fill a range of an array with a short value.
+    *
+    * @param a the array to fill
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+    */
+-  public static void fill(double[] a, int fromIndex, int toIndex, double val)
++  public static void fill(short[]a, int fromIndex, int toIndex, short val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+   /**
+@@ -928,11 +1027,14 @@
+    *
+    * @param a the array to fill
+    * @param val the value to fill it with
+-   * @throws ClassCastException if val is not an instance of the element
+-   *         type of a.
++   * @exception ClassCastException if val is not an instance of the element
++   *   type of a.
+    */
+-  public static void fill(Object[] a, Object val)
++  public static void fill(Object[]a, Object val)
+   {
++    // This implementation is slightly inefficient timewise, but the extra
++    // effort over inlining it is O(1) and small, and I refuse to repeat code
++    // if it can be helped.
+     fill(a, 0, a.length, val);
+   }
+ 
+@@ -943,1191 +1045,926 @@
+    * @param fromIndex the index to fill from, inclusive
+    * @param toIndex the index to fill to, exclusive
+    * @param val the value to fill with
+-   * @throws ClassCastException if val is not an instance of the element
+-   *         type of a.
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
++   * @exception ClassCastException if val is not an instance of the element
++   *   type of a.
+    */
+-  public static void fill(Object[] a, int fromIndex, int toIndex, Object val)
++  public static void fill(Object[]a, int fromIndex, int toIndex, Object val)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+     for (int i = fromIndex; i < toIndex; i++)
+-      a[i] = val;
++      {
++	a[i] = val;
++      }
+   }
+ 
+-
+-// sort
+   // Thanks to Paul Fisher <rao@gnu.org> for finding this quicksort algorithm
+-  // as specified by Sun and porting it to Java. The algorithm is an optimised
+-  // quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
+-  // "Engineering a Sort Function", Software-Practice and Experience, Vol.
+-  // 23(11) P. 1249-1265 (November 1993). This algorithm gives n*log(n)
+-  // performance on many arrays that would take quadratic time with a standard
+-  // quicksort.
++  // as specified by Sun and porting it to Java.
+ 
+   /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
++   * Sort a byte array into ascending order. The sort algorithm is an optimised
++   * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
++   * "Engineering a Sort Function", Software-Practice and Experience, Vol.
++   * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
++   * performance on many arrays that would take quadratic time with a standard
++   * quicksort.
+    *
+-   * @param a the byte array to sort
++   * @param a the array to sort
+    */
+-  public static void sort(byte[] a)
++  public static void sort(byte[]a)
+   {
+     qsort(a, 0, a.length);
+   }
+ 
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the byte array to sort
+-   * @param fromIndex the first index to sort (inclusive)
+-   * @param toIndex the last index to sort (exclusive)
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+-   */
+   public static void sort(byte[] a, int fromIndex, int toIndex)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+-    qsort(a, fromIndex, toIndex - fromIndex);
++    qsort(a, fromIndex, toIndex);
+   }
+ 
+-  /**
+-   * Finds the index of the median of three array elements.
+-   *
+-   * @param a the first index
+-   * @param b the second index
+-   * @param c the third index
+-   * @param d the array
+-   * @return the index (a, b, or c) which has the middle value of the three
+-   */
+-  private static int med3(int a, int b, int c, byte[] d)
++  private static int med3(int a, int b, int c, byte[]d)
+   {
+-    return (d[a] < d[b]
+-            ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
+-            : (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
++    return d[a] < d[b] ? 
++               (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
++	     : (d[b] > d[c] ? b : d[a] > d[c] ? c : a);
+   }
+ 
+-  /**
+-   * Swaps the elements at two locations of an array
+-   *
+-   * @param i the first index
+-   * @param j the second index
+-   * @param a the array
+-   */
+-  private static void swap(int i, int j, byte[] a)
++  private static void swap(int i, int j, byte[]a)
+   {
+     byte c = a[i];
+     a[i] = a[j];
+     a[j] = c;
+   }
+ 
+-  /**
+-   * Swaps two ranges of an array.
+-   *
+-   * @param i the first range start
+-   * @param j the second range start
+-   * @param n the element count
+-   * @param a the array
+-   */
+-  private static void vecswap(int i, int j, int n, byte[] a)
++  private static void qsort(byte[]a, int start, int n)
+   {
+-    for ( ; n > 0; i++, j++, n--)
+-      swap(i, j, a);
++    // use an insertion sort on small arrays
++    if (n <= 7)
++      {
++	for (int i = start + 1; i < start + n; i++)
++	  for (int j = i; j > 0 && a[j - 1] > a[j]; j--)
++	    swap(j, j - 1, a);
++	return;
++      }
++
++    int pm = n / 2;		// small arrays, middle element
++    if (n > 7)
++      {
++	int pl = start;
++	int pn = start + n - 1;
++
++	if (n > 40)
++	  {			// big arrays, pseudomedian of 9
++	    int s = n / 8;
++	    pl = med3(pl, pl + s, pl + 2 * s, a);
++	    pm = med3(pm - s, pm, pm + s, a);
++	    pn = med3(pn - 2 * s, pn - s, pn, a);
++	  }
++	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
++      }
++
++    int pa, pb, pc, pd, pv;
++    int r;
++
++    pv = start;
++    swap(pv, pm, a);
++    pa = pb = start;
++    pc = pd = start + n - 1;
++
++    for (;;)
++      {
++	while (pb <= pc && (r = a[pb] - a[pv]) <= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pa, pb, a);
++		pa++;
++	      }
++	    pb++;
++	  }
++	while (pc >= pb && (r = a[pc] - a[pv]) >= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pc, pd, a);
++		pd--;
++	      }
++	    pc--;
++	  }
++	if (pb > pc)
++	  break;
++	swap(pb, pc, a);
++	pb++;
++	pc--;
++      }
++    int pn = start + n;
++    int s;
++    s = Math.min(pa - start, pb - pa);
++    vecswap(start, pb - s, s, a);
++    s = Math.min(pd - pc, pn - pd - 1);
++    vecswap(pb, pn - s, s, a);
++    if ((s = pb - pa) > 1)
++      qsort(a, start, s);
++    if ((s = pd - pc) > 1)
++      qsort(a, pn - s, s);
+   }
+ 
+-  /**
+-   * Performs a recursive modified quicksort.
+-   *
+-   * @param a the array to sort
+-   * @param from the start index (inclusive)
+-   * @param count the number of elements to sort
+-   */
+-  private static void qsort(byte[] array, int from, int count)
++  private static void vecswap(int i, int j, int n, byte[]a)
+   {
+-    // Use an insertion sort on small arrays.
+-    if (count <= 7)
+-      {
+-        for (int i = from + 1; i < from + count; i++)
+-          for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
+-            swap(j, j - 1, array);
+-        return;
+-      }
+-
+-    // Determine a good median element.
+-    int mid = count / 2;
+-    int lo = from;
+-    int hi = from + count - 1;
+-
+-    if (count > 40)
+-      { // big arrays, pseudomedian of 9
+-        int s = count / 8;
+-        lo = med3(lo, lo + s, lo + s + s, array);
+-        mid = med3(mid - s, mid, mid + s, array);
+-        hi = med3(hi - s - s, hi - s, hi, array);
+-      }
+-    mid = med3(lo, mid, hi, array);
+-
+-    int a, b, c, d;
+-    int comp;
+-
+-    // Pull the median element out of the fray, and use it as a pivot.
+-    swap(from, mid, array);
+-    a = b = from + 1;
+-    c = d = hi;
+-
+-    // Repeatedly move b and c to each other, swapping elements so
+-    // that all elements before index b are less than the pivot, and all
+-    // elements after index c are greater than the pivot. a and b track
+-    // the elements equal to the pivot.
+-    while (true)
+-      {
+-        while (b <= c && (comp = array[b] - array[from]) <= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(a, b, array);
+-                a++;
+-              }
+-            b++;
+-          }
+-        while (c >= b && (comp = array[c] - array[from]) >= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(c, d, array);
+-                d--;
+-              }
+-            c--;
+-          }
+-        if (b > c)
+-          break;
+-        swap(b, c, array);
+-        b++;
+-        c--;
+-      }
+-
+-    // Swap pivot(s) back in place, the recurse on left and right sections.
+-    int span;
+-    span = Math.min(a - from, b - a);
+-    vecswap(from, b - span, span, array);
+-
+-    span = Math.min(d - c, hi - d - 1);
+-    vecswap(b, hi - span + 1, span, array);
+-
+-    span = b - a;
+-    if (span > 1)
+-      qsort(array, from, span);
+-
+-    span = d - c;
+-    if (span > 1)
+-      qsort(array, hi - span + 1, span);
++    for (; n > 0; i++, j++, n--)
++      swap(i, j, a);
+   }
+ 
+   /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
++   * Sort a char array into ascending order. The sort algorithm is an optimised
++   * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
++   * "Engineering a Sort Function", Software-Practice and Experience, Vol.
++   * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
++   * performance on many arrays that would take quadratic time with a standard
++   * quicksort.
+    *
+-   * @param a the char array to sort
++   * @param a the array to sort
+    */
+-  public static void sort(char[] a)
++  public static void sort(char[]a)
+   {
+     qsort(a, 0, a.length);
+   }
+ 
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the char array to sort
+-   * @param fromIndex the first index to sort (inclusive)
+-   * @param toIndex the last index to sort (exclusive)
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+-   */
+   public static void sort(char[] a, int fromIndex, int toIndex)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+-    qsort(a, fromIndex, toIndex - fromIndex);
++    qsort(a, fromIndex, toIndex);
+   }
+ 
+-  /**
+-   * Finds the index of the median of three array elements.
+-   *
+-   * @param a the first index
+-   * @param b the second index
+-   * @param c the third index
+-   * @param d the array
+-   * @return the index (a, b, or c) which has the middle value of the three
+-   */
+-  private static int med3(int a, int b, int c, char[] d)
++  private static int med3(int a, int b, int c, char[]d)
+   {
+-    return (d[a] < d[b]
+-            ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
+-            : (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
++    return d[a] < d[b] ? 
++               (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
++	     : (d[b] > d[c] ? b : d[a] > d[c] ? c : a);
+   }
+ 
+-  /**
+-   * Swaps the elements at two locations of an array
+-   *
+-   * @param i the first index
+-   * @param j the second index
+-   * @param a the array
+-   */
+-  private static void swap(int i, int j, char[] a)
++  private static void swap(int i, int j, char[]a)
+   {
+     char c = a[i];
+     a[i] = a[j];
+     a[j] = c;
+   }
+ 
+-  /**
+-   * Swaps two ranges of an array.
+-   *
+-   * @param i the first range start
+-   * @param j the second range start
+-   * @param n the element count
+-   * @param a the array
+-   */
+-  private static void vecswap(int i, int j, int n, char[] a)
++  private static void qsort(char[]a, int start, int n)
+   {
+-    for ( ; n > 0; i++, j++, n--)
+-      swap(i, j, a);
++    // use an insertion sort on small arrays
++    if (n <= 7)
++      {
++	for (int i = start + 1; i < start + n; i++)
++	  for (int j = i; j > 0 && a[j - 1] > a[j]; j--)
++	    swap(j, j - 1, a);
++	return;
++      }
++
++    int pm = n / 2;		// small arrays, middle element
++    if (n > 7)
++      {
++	int pl = start;
++	int pn = start + n - 1;
++
++	if (n > 40)
++	  {			// big arrays, pseudomedian of 9
++	    int s = n / 8;
++	    pl = med3(pl, pl + s, pl + 2 * s, a);
++	    pm = med3(pm - s, pm, pm + s, a);
++	    pn = med3(pn - 2 * s, pn - s, pn, a);
++	  }
++	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
++      }
++
++    int pa, pb, pc, pd, pv;
++    int r;
++
++    pv = start;
++    swap(pv, pm, a);
++    pa = pb = start;
++    pc = pd = start + n - 1;
++
++    for (;;)
++      {
++	while (pb <= pc && (r = a[pb] - a[pv]) <= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pa, pb, a);
++		pa++;
++	      }
++	    pb++;
++	  }
++	while (pc >= pb && (r = a[pc] - a[pv]) >= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pc, pd, a);
++		pd--;
++	      }
++	    pc--;
++	  }
++	if (pb > pc)
++	  break;
++	swap(pb, pc, a);
++	pb++;
++	pc--;
++      }
++    int pn = start + n;
++    int s;
++    s = Math.min(pa - start, pb - pa);
++    vecswap(start, pb - s, s, a);
++    s = Math.min(pd - pc, pn - pd - 1);
++    vecswap(pb, pn - s, s, a);
++    if ((s = pb - pa) > 1)
++      qsort(a, start, s);
++    if ((s = pd - pc) > 1)
++      qsort(a, pn - s, s);
+   }
+ 
+-  /**
+-   * Performs a recursive modified quicksort.
+-   *
+-   * @param a the array to sort
+-   * @param from the start index (inclusive)
+-   * @param count the number of elements to sort
+-   */
+-  private static void qsort(char[] array, int from, int count)
++  private static void vecswap(int i, int j, int n, char[]a)
+   {
+-    // Use an insertion sort on small arrays.
+-    if (count <= 7)
+-      {
+-        for (int i = from + 1; i < from + count; i++)
+-          for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
+-            swap(j, j - 1, array);
+-        return;
+-      }
+-
+-    // Determine a good median element.
+-    int mid = count / 2;
+-    int lo = from;
+-    int hi = from + count - 1;
+-
+-    if (count > 40)
+-      { // big arrays, pseudomedian of 9
+-        int s = count / 8;
+-        lo = med3(lo, lo + s, lo + s + s, array);
+-        mid = med3(mid - s, mid, mid + s, array);
+-        hi = med3(hi - s - s, hi - s, hi, array);
+-      }
+-    mid = med3(lo, mid, hi, array);
+-
+-    int a, b, c, d;
+-    int comp;
+-
+-    // Pull the median element out of the fray, and use it as a pivot.
+-    swap(from, mid, array);
+-    a = b = from + 1;
+-    c = d = hi;
+-
+-    // Repeatedly move b and c to each other, swapping elements so
+-    // that all elements before index b are less than the pivot, and all
+-    // elements after index c are greater than the pivot. a and b track
+-    // the elements equal to the pivot.
+-    while (true)
+-      {
+-        while (b <= c && (comp = array[b] - array[from]) <= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(a, b, array);
+-                a++;
+-              }
+-            b++;
+-          }
+-        while (c >= b && (comp = array[c] - array[from]) >= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(c, d, array);
+-                d--;
+-              }
+-            c--;
+-          }
+-        if (b > c)
+-          break;
+-        swap(b, c, array);
+-        b++;
+-        c--;
+-      }
+-
+-    // Swap pivot(s) back in place, the recurse on left and right sections.
+-    int span;
+-    span = Math.min(a - from, b - a);
+-    vecswap(from, b - span, span, array);
+-
+-    span = Math.min(d - c, hi - d - 1);
+-    vecswap(b, hi - span + 1, span, array);
+-
+-    span = b - a;
+-    if (span > 1)
+-      qsort(array, from, span);
+-
+-    span = d - c;
+-    if (span > 1)
+-      qsort(array, hi - span + 1, span);
++    for (; n > 0; i++, j++, n--)
++      swap(i, j, a);
+   }
+ 
+   /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
++   * Sort a double array into ascending order. The sort algorithm is an
++   * optimised quicksort, as described in Jon L. Bentley and M. Douglas
++   * McIlroy's "Engineering a Sort Function", Software-Practice and Experience,
++   * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
++   * performance on many arrays that would take quadratic time with a standard
++   * quicksort. Note that this implementation, like Sun's, has undefined
++   * behaviour if the array contains any NaN values.
+    *
+-   * @param a the short array to sort
++   * @param a the array to sort
+    */
+-  public static void sort(short[] a)
++  public static void sort(double[]a)
+   {
+     qsort(a, 0, a.length);
+   }
+ 
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the short array to sort
+-   * @param fromIndex the first index to sort (inclusive)
+-   * @param toIndex the last index to sort (exclusive)
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+-   */
+-  public static void sort(short[] a, int fromIndex, int toIndex)
++  public static void sort(double[] a, int fromIndex, int toIndex)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+-    qsort(a, fromIndex, toIndex - fromIndex);
++    qsort(a, fromIndex, toIndex);
+   }
+ 
+-  /**
+-   * Finds the index of the median of three array elements.
+-   *
+-   * @param a the first index
+-   * @param b the second index
+-   * @param c the third index
+-   * @param d the array
+-   * @return the index (a, b, or c) which has the middle value of the three
+-   */
+-  private static int med3(int a, int b, int c, short[] d)
++  private static int med3(int a, int b, int c, double[]d)
+   {
+-    return (d[a] < d[b]
+-            ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
+-            : (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
++    return d[a] < d[b] ? 
++               (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
++	     : (d[b] > d[c] ? b : d[a] > d[c] ? c : a);
+   }
+ 
+-  /**
+-   * Swaps the elements at two locations of an array
+-   *
+-   * @param i the first index
+-   * @param j the second index
+-   * @param a the array
+-   */
+-  private static void swap(int i, int j, short[] a)
++  private static void swap(int i, int j, double[]a)
+   {
+-    short c = a[i];
++    double c = a[i];
+     a[i] = a[j];
+     a[j] = c;
+   }
+ 
+-  /**
+-   * Swaps two ranges of an array.
+-   *
+-   * @param i the first range start
+-   * @param j the second range start
+-   * @param n the element count
+-   * @param a the array
+-   */
+-  private static void vecswap(int i, int j, int n, short[] a)
++  private static void qsort(double[]a, int start, int n)
+   {
+-    for ( ; n > 0; i++, j++, n--)
+-      swap(i, j, a);
++    // use an insertion sort on small arrays
++    if (n <= 7)
++      {
++	for (int i = start + 1; i < start + n; i++)
++	  for (int j = i; j > 0 && a[j - 1] > a[j]; j--)
++	    swap(j, j - 1, a);
++	return;
++      }
++
++    int pm = n / 2;		// small arrays, middle element
++    if (n > 7)
++      {
++	int pl = start;
++	int pn = start + n - 1;
++
++	if (n > 40)
++	  {			// big arrays, pseudomedian of 9
++	    int s = n / 8;
++	    pl = med3(pl, pl + s, pl + 2 * s, a);
++	    pm = med3(pm - s, pm, pm + s, a);
++	    pn = med3(pn - 2 * s, pn - s, pn, a);
++	  }
++	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
++      }
++
++    int pa, pb, pc, pd, pv;
++    double r;
++
++    pv = start;
++    swap(pv, pm, a);
++    pa = pb = start;
++    pc = pd = start + n - 1;
++
++    for (;;)
++      {
++	while (pb <= pc && (r = a[pb] - a[pv]) <= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pa, pb, a);
++		pa++;
++	      }
++	    pb++;
++	  }
++	while (pc >= pb && (r = a[pc] - a[pv]) >= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pc, pd, a);
++		pd--;
++	      }
++	    pc--;
++	  }
++	if (pb > pc)
++	  break;
++	swap(pb, pc, a);
++	pb++;
++	pc--;
++      }
++    int pn = start + n;
++    int s;
++    s = Math.min(pa - start, pb - pa);
++    vecswap(start, pb - s, s, a);
++    s = Math.min(pd - pc, pn - pd - 1);
++    vecswap(pb, pn - s, s, a);
++    if ((s = pb - pa) > 1)
++      qsort(a, start, s);
++    if ((s = pd - pc) > 1)
++      qsort(a, pn - s, s);
+   }
+ 
+-  /**
+-   * Performs a recursive modified quicksort.
+-   *
+-   * @param a the array to sort
+-   * @param from the start index (inclusive)
+-   * @param count the number of elements to sort
+-   */
+-  private static void qsort(short[] array, int from, int count)
++  private static void vecswap(int i, int j, int n, double[]a)
+   {
+-    // Use an insertion sort on small arrays.
+-    if (count <= 7)
+-      {
+-        for (int i = from + 1; i < from + count; i++)
+-          for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
+-            swap(j, j - 1, array);
+-        return;
+-      }
+-
+-    // Determine a good median element.
+-    int mid = count / 2;
+-    int lo = from;
+-    int hi = from + count - 1;
+-
+-    if (count > 40)
+-      { // big arrays, pseudomedian of 9
+-        int s = count / 8;
+-        lo = med3(lo, lo + s, lo + s + s, array);
+-        mid = med3(mid - s, mid, mid + s, array);
+-        hi = med3(hi - s - s, hi - s, hi, array);
+-      }
+-    mid = med3(lo, mid, hi, array);
+-
+-    int a, b, c, d;
+-    int comp;
+-
+-    // Pull the median element out of the fray, and use it as a pivot.
+-    swap(from, mid, array);
+-    a = b = from + 1;
+-    c = d = hi;
+-
+-    // Repeatedly move b and c to each other, swapping elements so
+-    // that all elements before index b are less than the pivot, and all
+-    // elements after index c are greater than the pivot. a and b track
+-    // the elements equal to the pivot.
+-    while (true)
+-      {
+-        while (b <= c && (comp = array[b] - array[from]) <= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(a, b, array);
+-                a++;
+-              }
+-            b++;
+-          }
+-        while (c >= b && (comp = array[c] - array[from]) >= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(c, d, array);
+-                d--;
+-              }
+-            c--;
+-          }
+-        if (b > c)
+-          break;
+-        swap(b, c, array);
+-        b++;
+-        c--;
+-      }
+-
+-    // Swap pivot(s) back in place, the recurse on left and right sections.
+-    int span;
+-    span = Math.min(a - from, b - a);
+-    vecswap(from, b - span, span, array);
+-
+-    span = Math.min(d - c, hi - d - 1);
+-    vecswap(b, hi - span + 1, span, array);
+-
+-    span = b - a;
+-    if (span > 1)
+-      qsort(array, from, span);
+-
+-    span = d - c;
+-    if (span > 1)
+-      qsort(array, hi - span + 1, span);
++    for (; n > 0; i++, j++, n--)
++      swap(i, j, a);
+   }
+ 
+   /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
++   * Sort a float array into ascending order. The sort algorithm is an
++   * optimised quicksort, as described in Jon L. Bentley and M. Douglas
++   * McIlroy's "Engineering a Sort Function", Software-Practice and Experience,
++   * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
++   * performance on many arrays that would take quadratic time with a standard
++   * quicksort. Note that this implementation, like Sun's, has undefined
++   * behaviour if the array contains any NaN values.
+    *
+-   * @param a the int array to sort
++   * @param a the array to sort
+    */
+-  public static void sort(int[] a)
++  public static void sort(float[]a)
+   {
+     qsort(a, 0, a.length);
+   }
+ 
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the int array to sort
+-   * @param fromIndex the first index to sort (inclusive)
+-   * @param toIndex the last index to sort (exclusive)
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+-   */
+-  public static void sort(int[] a, int fromIndex, int toIndex)
++  public static void sort(float[] a, int fromIndex, int toIndex)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+-    qsort(a, fromIndex, toIndex - fromIndex);
++    qsort(a, fromIndex, toIndex);
+   }
+ 
+-  /**
+-   * Finds the index of the median of three array elements.
+-   *
+-   * @param a the first index
+-   * @param b the second index
+-   * @param c the third index
+-   * @param d the array
+-   * @return the index (a, b, or c) which has the middle value of the three
+-   */
+-  private static int med3(int a, int b, int c, int[] d)
++  private static int med3(int a, int b, int c, float[]d)
+   {
+-    return (d[a] < d[b]
+-            ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
+-            : (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
++    return d[a] < d[b] ? 
++               (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
++	     : (d[b] > d[c] ? b : d[a] > d[c] ? c : a);
+   }
+ 
+-  /**
+-   * Swaps the elements at two locations of an array
+-   *
+-   * @param i the first index
+-   * @param j the second index
+-   * @param a the array
+-   */
+-  private static void swap(int i, int j, int[] a)
++  private static void swap(int i, int j, float[]a)
+   {
+-    int c = a[i];
++    float c = a[i];
+     a[i] = a[j];
+     a[j] = c;
+   }
+ 
+-  /**
+-   * Swaps two ranges of an array.
+-   *
+-   * @param i the first range start
+-   * @param j the second range start
+-   * @param n the element count
+-   * @param a the array
+-   */
+-  private static void vecswap(int i, int j, int n, int[] a)
++  private static void qsort(float[]a, int start, int n)
+   {
+-    for ( ; n > 0; i++, j++, n--)
+-      swap(i, j, a);
++    // use an insertion sort on small arrays
++    if (n <= 7)
++      {
++	for (int i = start + 1; i < start + n; i++)
++	  for (int j = i; j > 0 && a[j - 1] > a[j]; j--)
++	    swap(j, j - 1, a);
++	return;
++      }
++
++    int pm = n / 2;		// small arrays, middle element
++    if (n > 7)
++      {
++	int pl = start;
++	int pn = start + n - 1;
++
++	if (n > 40)
++	  {			// big arrays, pseudomedian of 9
++	    int s = n / 8;
++	    pl = med3(pl, pl + s, pl + 2 * s, a);
++	    pm = med3(pm - s, pm, pm + s, a);
++	    pn = med3(pn - 2 * s, pn - s, pn, a);
++	  }
++	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
++      }
++
++    int pa, pb, pc, pd, pv;
++    float r;
++
++    pv = start;
++    swap(pv, pm, a);
++    pa = pb = start;
++    pc = pd = start + n - 1;
++
++    for (;;)
++      {
++	while (pb <= pc && (r = a[pb] - a[pv]) <= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pa, pb, a);
++		pa++;
++	      }
++	    pb++;
++	  }
++	while (pc >= pb && (r = a[pc] - a[pv]) >= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pc, pd, a);
++		pd--;
++	      }
++	    pc--;
++	  }
++	if (pb > pc)
++	  break;
++	swap(pb, pc, a);
++	pb++;
++	pc--;
++      }
++    int pn = start + n;
++    int s;
++    s = Math.min(pa - start, pb - pa);
++    vecswap(start, pb - s, s, a);
++    s = Math.min(pd - pc, pn - pd - 1);
++    vecswap(pb, pn - s, s, a);
++    if ((s = pb - pa) > 1)
++      qsort(a, start, s);
++    if ((s = pd - pc) > 1)
++      qsort(a, pn - s, s);
+   }
+ 
+-  /**
+-   * Compares two integers in natural order, since a - b is inadequate.
+-   *
+-   * @param a the first int
+-   * @param b the second int
+-   * @return &lt; 0, 0, or &gt; 0 accorting to the comparison
+-   */
+-  private static int compare(int a, int b)
++  private static void vecswap(int i, int j, int n, float[]a)
+   {
+-    return a < b ? -1 : a == b ? 0 : 1;
++    for (; n > 0; i++, j++, n--)
++      swap(i, j, a);
+   }
+ 
+   /**
+-   * Performs a recursive modified quicksort.
++   * Sort an int array into ascending order. The sort algorithm is an optimised
++   * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
++   * "Engineering a Sort Function", Software-Practice and Experience, Vol.
++   * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
++   * performance on many arrays that would take quadratic time with a standard
++   * quicksort.
+    *
+    * @param a the array to sort
+-   * @param from the start index (inclusive)
+-   * @param count the number of elements to sort
+-   */
+-  private static void qsort(int[] array, int from, int count)
+-  {
+-    // Use an insertion sort on small arrays.
+-    if (count <= 7)
+-      {
+-        for (int i = from + 1; i < from + count; i++)
+-          for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
+-            swap(j, j - 1, array);
+-        return;
+-      }
+-
+-    // Determine a good median element.
+-    int mid = count / 2;
+-    int lo = from;
+-    int hi = from + count - 1;
+-
+-    if (count > 40)
+-      { // big arrays, pseudomedian of 9
+-        int s = count / 8;
+-        lo = med3(lo, lo + s, lo + s + s, array);
+-        mid = med3(mid - s, mid, mid + s, array);
+-        hi = med3(hi - s - s, hi - s, hi, array);
+-      }
+-    mid = med3(lo, mid, hi, array);
+-
+-    int a, b, c, d;
+-    int comp;
+-
+-    // Pull the median element out of the fray, and use it as a pivot.
+-    swap(from, mid, array);
+-    a = b = from + 1;
+-    c = d = hi;
+-
+-    // Repeatedly move b and c to each other, swapping elements so
+-    // that all elements before index b are less than the pivot, and all
+-    // elements after index c are greater than the pivot. a and b track
+-    // the elements equal to the pivot.
+-    while (true)
+-      {
+-        while (b <= c && (comp = compare(array[b], array[from])) <= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(a, b, array);
+-                a++;
+-              }
+-            b++;
+-          }
+-        while (c >= b && (comp = compare(array[c], array[from])) >= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(c, d, array);
+-                d--;
+-              }
+-            c--;
+-          }
+-        if (b > c)
+-          break;
+-        swap(b, c, array);
+-        b++;
+-        c--;
+-      }
+-
+-    // Swap pivot(s) back in place, the recurse on left and right sections.
+-    int span;
+-    span = Math.min(a - from, b - a);
+-    vecswap(from, b - span, span, array);
+-
+-    span = Math.min(d - c, hi - d - 1);
+-    vecswap(b, hi - span + 1, span, array);
+-
+-    span = b - a;
+-    if (span > 1)
+-      qsort(array, from, span);
+-
+-    span = d - c;
+-    if (span > 1)
+-      qsort(array, hi - span + 1, span);
+-  }
+-
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the long array to sort
+    */
+-  public static void sort(long[] a)
++  public static void sort(int[]a)
+   {
+     qsort(a, 0, a.length);
+   }
+ 
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the long array to sort
+-   * @param fromIndex the first index to sort (inclusive)
+-   * @param toIndex the last index to sort (exclusive)
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+-   */
+-  public static void sort(long[] a, int fromIndex, int toIndex)
++  public static void sort(int[] a, int fromIndex, int toIndex)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+-    qsort(a, fromIndex, toIndex - fromIndex);
++    qsort(a, fromIndex, toIndex);
+   }
+ 
+-  /**
+-   * Finds the index of the median of three array elements.
+-   *
+-   * @param a the first index
+-   * @param b the second index
+-   * @param c the third index
+-   * @param d the array
+-   * @return the index (a, b, or c) which has the middle value of the three
+-   */
+-  private static int med3(int a, int b, int c, long[] d)
++  private static int med3(int a, int b, int c, int[]d)
+   {
+-    return (d[a] < d[b]
+-            ? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
+-            : (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
++    return d[a] < d[b] ? 
++               (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
++	     : (d[b] > d[c] ? b : d[a] > d[c] ? c : a);
+   }
+ 
+-  /**
+-   * Swaps the elements at two locations of an array
+-   *
+-   * @param i the first index
+-   * @param j the second index
+-   * @param a the array
+-   */
+-  private static void swap(int i, int j, long[] a)
++  private static void swap(int i, int j, int[]a)
+   {
+-    long c = a[i];
++    int c = a[i];
+     a[i] = a[j];
+     a[j] = c;
+   }
+ 
+-  /**
+-   * Swaps two ranges of an array.
+-   *
+-   * @param i the first range start
+-   * @param j the second range start
+-   * @param n the element count
+-   * @param a the array
+-   */
+-  private static void vecswap(int i, int j, int n, long[] a)
++  private static void qsort(int[]a, int start, int n)
+   {
+-    for ( ; n > 0; i++, j++, n--)
+-      swap(i, j, a);
++    // use an insertion sort on small arrays
++    if (n <= 7)
++      {
++	for (int i = start + 1; i < start + n; i++)
++	  for (int j = i; j > 0 && a[j - 1] > a[j]; j--)
++	    swap(j, j - 1, a);
++	return;
++      }
++
++    int pm = n / 2;		// small arrays, middle element
++    if (n > 7)
++      {
++	int pl = start;
++	int pn = start + n - 1;
++
++	if (n > 40)
++	  {			// big arrays, pseudomedian of 9
++	    int s = n / 8;
++	    pl = med3(pl, pl + s, pl + 2 * s, a);
++	    pm = med3(pm - s, pm, pm + s, a);
++	    pn = med3(pn - 2 * s, pn - s, pn, a);
++	  }
++	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
++      }
++
++    int pa, pb, pc, pd, pv;
++    int r;
++
++    pv = start;
++    swap(pv, pm, a);
++    pa = pb = start;
++    pc = pd = start + n - 1;
++
++    for (;;)
++      {
++	while (pb <= pc && (r = a[pb] - a[pv]) <= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pa, pb, a);
++		pa++;
++	      }
++	    pb++;
++	  }
++	while (pc >= pb && (r = a[pc] - a[pv]) >= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pc, pd, a);
++		pd--;
++	      }
++	    pc--;
++	  }
++	if (pb > pc)
++	  break;
++	swap(pb, pc, a);
++	pb++;
++	pc--;
++      }
++    int pn = start + n;
++    int s;
++    s = Math.min(pa - start, pb - pa);
++    vecswap(start, pb - s, s, a);
++    s = Math.min(pd - pc, pn - pd - 1);
++    vecswap(pb, pn - s, s, a);
++    if ((s = pb - pa) > 1)
++      qsort(a, start, s);
++    if ((s = pd - pc) > 1)
++      qsort(a, pn - s, s);
+   }
+ 
+-  /**
+-   * Compares two longs in natural order, since a - b is inadequate.
+-   *
+-   * @param a the first long
+-   * @param b the second long
+-   * @return &lt; 0, 0, or &gt; 0 accorting to the comparison
+-   */
+-  private static int compare(long a, long b)
++  private static void vecswap(int i, int j, int n, int[]a)
+   {
+-    return a < b ? -1 : a == b ? 0 : 1;
++    for (; n > 0; i++, j++, n--)
++      swap(i, j, a);
+   }
+ 
+   /**
+-   * Performs a recursive modified quicksort.
++   * Sort a long array into ascending order. The sort algorithm is an optimised
++   * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
++   * "Engineering a Sort Function", Software-Practice and Experience, Vol.
++   * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
++   * performance on many arrays that would take quadratic time with a standard
++   * quicksort.
+    *
+    * @param a the array to sort
+-   * @param from the start index (inclusive)
+-   * @param count the number of elements to sort
+-   */
+-  private static void qsort(long[] array, int from, int count)
+-  {
+-    // Use an insertion sort on small arrays.
+-    if (count <= 7)
+-      {
+-        for (int i = from + 1; i < from + count; i++)
+-          for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
+-            swap(j, j - 1, array);
+-        return;
+-      }
+-
+-    // Determine a good median element.
+-    int mid = count / 2;
+-    int lo = from;
+-    int hi = from + count - 1;
+-
+-    if (count > 40)
+-      { // big arrays, pseudomedian of 9
+-        int s = count / 8;
+-        lo = med3(lo, lo + s, lo + s + s, array);
+-        mid = med3(mid - s, mid, mid + s, array);
+-        hi = med3(hi - s - s, hi - s, hi, array);
+-      }
+-    mid = med3(lo, mid, hi, array);
+-
+-    int a, b, c, d;
+-    int comp;
+-
+-    // Pull the median element out of the fray, and use it as a pivot.
+-    swap(from, mid, array);
+-    a = b = from + 1;
+-    c = d = hi;
+-
+-    // Repeatedly move b and c to each other, swapping elements so
+-    // that all elements before index b are less than the pivot, and all
+-    // elements after index c are greater than the pivot. a and b track
+-    // the elements equal to the pivot.
+-    while (true)
+-      {
+-        while (b <= c && (comp = compare(array[b], array[from])) <= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(a, b, array);
+-                a++;
+-              }
+-            b++;
+-          }
+-        while (c >= b && (comp = compare(array[c], array[from])) >= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(c, d, array);
+-                d--;
+-              }
+-            c--;
+-          }
+-        if (b > c)
+-          break;
+-        swap(b, c, array);
+-        b++;
+-        c--;
+-      }
+-
+-    // Swap pivot(s) back in place, the recurse on left and right sections.
+-    int span;
+-    span = Math.min(a - from, b - a);
+-    vecswap(from, b - span, span, array);
+-
+-    span = Math.min(d - c, hi - d - 1);
+-    vecswap(b, hi - span + 1, span, array);
+-
+-    span = b - a;
+-    if (span > 1)
+-      qsort(array, from, span);
+-
+-    span = d - c;
+-    if (span > 1)
+-      qsort(array, hi - span + 1, span);
+-  }
+-
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the float array to sort
+    */
+-  public static void sort(float[] a)
++  public static void sort(long[]a)
+   {
+     qsort(a, 0, a.length);
+   }
+ 
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the float array to sort
+-   * @param fromIndex the first index to sort (inclusive)
+-   * @param toIndex the last index to sort (exclusive)
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+-   */
+-  public static void sort(float[] a, int fromIndex, int toIndex)
++  public static void sort(long[] a, int fromIndex, int toIndex)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+-    qsort(a, fromIndex, toIndex - fromIndex);
++    qsort(a, fromIndex, toIndex);
+   }
+ 
+-  /**
+-   * Finds the index of the median of three array elements.
+-   *
+-   * @param a the first index
+-   * @param b the second index
+-   * @param c the third index
+-   * @param d the array
+-   * @return the index (a, b, or c) which has the middle value of the three
+-   */
+-  private static int med3(int a, int b, int c, float[] d)
++  private static int med3(int a, int b, int c, long[]d)
+   {
+-    return (Float.compare(d[a], d[b]) < 0
+-            ? (Float.compare(d[b], d[c]) < 0 ? b
+-               : Float.compare(d[a], d[c]) < 0 ? c : a)
+-            : (Float.compare(d[b], d[c]) > 0 ? b
+-               : Float.compare(d[a], d[c]) > 0 ? c : a));
++    return d[a] < d[b] ? 
++               (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
++	     : (d[b] > d[c] ? b : d[a] > d[c] ? c : a);
+   }
+ 
+-  /**
+-   * Swaps the elements at two locations of an array
+-   *
+-   * @param i the first index
+-   * @param j the second index
+-   * @param a the array
+-   */
+-  private static void swap(int i, int j, float[] a)
++  private static void swap(int i, int j, long[]a)
+   {
+-    float c = a[i];
++    long c = a[i];
+     a[i] = a[j];
+     a[j] = c;
+   }
+ 
+-  /**
+-   * Swaps two ranges of an array.
+-   *
+-   * @param i the first range start
+-   * @param j the second range start
+-   * @param n the element count
+-   * @param a the array
+-   */
+-  private static void vecswap(int i, int j, int n, float[] a)
++  private static void qsort(long[]a, int start, int n)
+   {
+-    for ( ; n > 0; i++, j++, n--)
+-      swap(i, j, a);
++    // use an insertion sort on small arrays
++    if (n <= 7)
++      {
++	for (int i = start + 1; i < start + n; i++)
++	  for (int j = i; j > 0 && a[j - 1] > a[j]; j--)
++	    swap(j, j - 1, a);
++	return;
++      }
++
++    int pm = n / 2;		// small arrays, middle element
++    if (n > 7)
++      {
++	int pl = start;
++	int pn = start + n - 1;
++
++	if (n > 40)
++	  {			// big arrays, pseudomedian of 9
++	    int s = n / 8;
++	    pl = med3(pl, pl + s, pl + 2 * s, a);
++	    pm = med3(pm - s, pm, pm + s, a);
++	    pn = med3(pn - 2 * s, pn - s, pn, a);
++	  }
++	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
++      }
++
++    int pa, pb, pc, pd, pv;
++    long r;
++
++    pv = start;
++    swap(pv, pm, a);
++    pa = pb = start;
++    pc = pd = start + n - 1;
++
++    for (;;)
++      {
++	while (pb <= pc && (r = a[pb] - a[pv]) <= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pa, pb, a);
++		pa++;
++	      }
++	    pb++;
++	  }
++	while (pc >= pb && (r = a[pc] - a[pv]) >= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pc, pd, a);
++		pd--;
++	      }
++	    pc--;
++	  }
++	if (pb > pc)
++	  break;
++	swap(pb, pc, a);
++	pb++;
++	pc--;
++      }
++    int pn = start + n;
++    int s;
++    s = Math.min(pa - start, pb - pa);
++    vecswap(start, pb - s, s, a);
++    s = Math.min(pd - pc, pn - pd - 1);
++    vecswap(pb, pn - s, s, a);
++    if ((s = pb - pa) > 1)
++      qsort(a, start, s);
++    if ((s = pd - pc) > 1)
++      qsort(a, pn - s, s);
+   }
+ 
+-  /**
+-   * Performs a recursive modified quicksort.
+-   *
+-   * @param a the array to sort
+-   * @param from the start index (inclusive)
+-   * @param count the number of elements to sort
+-   */
+-  private static void qsort(float[] array, int from, int count)
++  private static void vecswap(int i, int j, int n, long[]a)
+   {
+-    // Use an insertion sort on small arrays.
+-    if (count <= 7)
+-      {
+-        for (int i = from + 1; i < from + count; i++)
+-          for (int j = i;
+-               j > 0 && Float.compare(array[j - 1], array[j]) > 0;
+-               j--)
+-            {
+-              swap(j, j - 1, array);
+-            }
+-        return;
+-      }
+-
+-    // Determine a good median element.
+-    int mid = count / 2;
+-    int lo = from;
+-    int hi = from + count - 1;
+-
+-    if (count > 40)
+-      { // big arrays, pseudomedian of 9
+-        int s = count / 8;
+-        lo = med3(lo, lo + s, lo + s + s, array);
+-        mid = med3(mid - s, mid, mid + s, array);
+-        hi = med3(hi - s - s, hi - s, hi, array);
+-      }
+-    mid = med3(lo, mid, hi, array);
+-
+-    int a, b, c, d;
+-    int comp;
+-
+-    // Pull the median element out of the fray, and use it as a pivot.
+-    swap(from, mid, array);
+-    a = b = from + 1;
+-    c = d = hi;
+-
+-    // Repeatedly move b and c to each other, swapping elements so
+-    // that all elements before index b are less than the pivot, and all
+-    // elements after index c are greater than the pivot. a and b track
+-    // the elements equal to the pivot.
+-    while (true)
+-      {
+-        while (b <= c && (comp = Float.compare(array[b], array[from])) <= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(a, b, array);
+-                a++;
+-              }
+-            b++;
+-          }
+-        while (c >= b && (comp = Float.compare(array[c], array[from])) >= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(c, d, array);
+-                d--;
+-              }
+-            c--;
+-          }
+-        if (b > c)
+-          break;
+-        swap(b, c, array);
+-        b++;
+-        c--;
+-      }
+-
+-    // Swap pivot(s) back in place, the recurse on left and right sections.
+-    int span;
+-    span = Math.min(a - from, b - a);
+-    vecswap(from, b - span, span, array);
+-
+-    span = Math.min(d - c, hi - d - 1);
+-    vecswap(b, hi - span + 1, span, array);
+-
+-    span = b - a;
+-    if (span > 1)
+-      qsort(array, from, span);
+-
+-    span = d - c;
+-    if (span > 1)
+-      qsort(array, hi - span + 1, span);
++    for (; n > 0; i++, j++, n--)
++      swap(i, j, a);
+   }
+ 
+   /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
++   * Sort a short array into ascending order. The sort algorithm is an
++   * optimised quicksort, as described in Jon L. Bentley and M. Douglas
++   * McIlroy's "Engineering a Sort Function", Software-Practice and Experience,
++   * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n)
++   * performance on many arrays that would take quadratic time with a standard
++   * quicksort.
+    *
+-   * @param a the double array to sort
++   * @param a the array to sort
+    */
+-  public static void sort(double[] a)
++  public static void sort(short[]a)
+   {
+     qsort(a, 0, a.length);
+   }
+ 
+-  /**
+-   * Performs a stable sort on the elements, arranging them according to their
+-   * natural order.
+-   *
+-   * @param a the double array to sort
+-   * @param fromIndex the first index to sort (inclusive)
+-   * @param toIndex the last index to sort (exclusive)
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; a.length
+-   */
+-  public static void sort(double[] a, int fromIndex, int toIndex)
++  public static void sort(short[] a, int fromIndex, int toIndex)
+   {
+-    if (fromIndex > toIndex)
+-      throw new IllegalArgumentException();
+-    qsort(a, fromIndex, toIndex - fromIndex);
++    qsort(a, fromIndex, toIndex);
+   }
+ 
+-  /**
+-   * Finds the index of the median of three array elements.
+-   *
+-   * @param a the first index
+-   * @param b the second index
+-   * @param c the third index
+-   * @param d the array
+-   * @return the index (a, b, or c) which has the middle value of the three
+-   */
+-  private static int med3(int a, int b, int c, double[] d)
++  private static int med3(int a, int b, int c, short[]d)
+   {
+-    return (Double.compare(d[a], d[b]) < 0
+-            ? (Double.compare(d[b], d[c]) < 0 ? b
+-               : Double.compare(d[a], d[c]) < 0 ? c : a)
+-            : (Double.compare(d[b], d[c]) > 0 ? b
+-               : Double.compare(d[a], d[c]) > 0 ? c : a));
++    return d[a] < d[b] ? 
++               (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
++	     : (d[b] > d[c] ? b : d[a] > d[c] ? c : a);
+   }
+ 
+-  /**
+-   * Swaps the elements at two locations of an array
+-   *
+-   * @param i the first index
+-   * @param j the second index
+-   * @param a the array
+-   */
+-  private static void swap(int i, int j, double[] a)
++  private static void swap(int i, int j, short[]a)
+   {
+-    double c = a[i];
++    short c = a[i];
+     a[i] = a[j];
+     a[j] = c;
+   }
+ 
+-  /**
+-   * Swaps two ranges of an array.
+-   *
+-   * @param i the first range start
+-   * @param j the second range start
+-   * @param n the element count
+-   * @param a the array
+-   */
+-  private static void vecswap(int i, int j, int n, double[] a)
++  private static void qsort(short[]a, int start, int n)
++  {
++    // use an insertion sort on small arrays
++    if (n <= 7)
++      {
++	for (int i = start + 1; i < start + n; i++)
++	  for (int j = i; j > 0 && a[j - 1] > a[j]; j--)
++	    swap(j, j - 1, a);
++	return;
++      }
++
++    int pm = n / 2;		// small arrays, middle element
++    if (n > 7)
++      {
++	int pl = start;
++	int pn = start + n - 1;
++
++	if (n > 40)
++	  {			// big arrays, pseudomedian of 9
++	    int s = n / 8;
++	    pl = med3(pl, pl + s, pl + 2 * s, a);
++	    pm = med3(pm - s, pm, pm + s, a);
++	    pn = med3(pn - 2 * s, pn - s, pn, a);
++	  }
++	pm = med3(pl, pm, pn, a);	// mid-size, med of 3
++      }
++
++    int pa, pb, pc, pd, pv;
++    int r;
++
++    pv = start;
++    swap(pv, pm, a);
++    pa = pb = start;
++    pc = pd = start + n - 1;
++
++    for (;;)
++      {
++	while (pb <= pc && (r = a[pb] - a[pv]) <= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pa, pb, a);
++		pa++;
++	      }
++	    pb++;
++	  }
++	while (pc >= pb && (r = a[pc] - a[pv]) >= 0)
++	  {
++	    if (r == 0)
++	      {
++		swap(pc, pd, a);
++		pd--;
++	      }
++	    pc--;
++	  }
++	if (pb > pc)
++	  break;
++	swap(pb, pc, a);
++	pb++;
++	pc--;
++      }
++    int pn = start + n;
++    int s;
++    s = Math.min(pa - start, pb - pa);
++    vecswap(start, pb - s, s, a);
++    s = Math.min(pd - pc, pn - pd - 1);
++    vecswap(pb, pn - s, s, a);
++    if ((s = pb - pa) > 1)
++      qsort(a, start, s);
++    if ((s = pd - pc) > 1)
++      qsort(a, pn - s, s);
++  }
++
++  private static void vecswap(int i, int j, int n, short[]a)
+   {
+-    for ( ; n > 0; i++, j++, n--)
++    for (; n > 0; i++, j++, n--)
+       swap(i, j, a);
+   }
+ 
+   /**
+-   * Performs a recursive modified quicksort.
+-   *
+-   * @param a the array to sort
+-   * @param from the start index (inclusive)
+-   * @param count the number of elements to sort
+-   */
+-  private static void qsort(double[] array, int from, int count)
+-  {
+-    // Use an insertion sort on small arrays.
+-    if (count <= 7)
++   * The bulk of the work for the object sort routines.  In general,
++   * the code attempts to be simple rather than fast, the idea being
++   * that a good optimising JIT will be able to optimise it better
++   * than I can, and if I try it will make it more confusing for the
++   * JIT.  
++   */
++  private static void mergeSort(Object[]a, int from, int to, Comparator c)
++  {
++    // First presort the array in chunks of length 6 with insertion sort. 
++    // mergesort would give too much overhead for this length.
++    for (int chunk = from; chunk < to; chunk += 6)
++      {
++	int end = Math.min(chunk + 6, to);
++	for (int i = chunk + 1; i < end; i++)
++	  {
++	    if (c.compare(a[i - 1], a[i]) > 0)
++	      {
++		// not already sorted
++		int j = i;
++		Object elem = a[j];
++		do
++		  {
++		    a[j] = a[j - 1];
++		    j--;
++		  }
++		while (j > chunk && c.compare(a[j - 1], elem) > 0);
++		a[j] = elem;
++	      }
++	  }
++      }
++
++    int len = to - from;
++    // If length is smaller or equal 6 we are done.
++    if (len <= 6)
++      return;
++
++    Object[]src = a;
++    Object[]dest = new Object[len];
++    Object[]t = null;		// t is used for swapping src and dest
++
++    // The difference of the fromIndex of the src and dest array.
++    int srcDestDiff = -from;
++
++    // The merges are done in this loop
++    for (int size = 6; size < len; size <<= 1)
++      {
++	for (int start = from; start < to; start += size << 1)
++	  {
++	    // mid ist the start of the second sublist;
++	    // end the start of the next sublist (or end of array).
++	    int mid = start + size;
++	    int end = Math.min(to, mid + size);
++
++	    // The second list is empty or the elements are already in
++	    // order - no need to merge
++	    if (mid >= end || c.compare(src[mid - 1], src[mid]) <= 0)
++	      {
++		System.arraycopy(src, start,
++				 dest, start + srcDestDiff, end - start);
++
++		// The two halves just need swapping - no need to merge
++	      }
++	    else if (c.compare(src[start], src[end - 1]) > 0)
++	      {
++		System.arraycopy(src, start,
++				 dest, end - size + srcDestDiff, size);
++		System.arraycopy(src, mid,
++				 dest, start + srcDestDiff, end - mid);
++
++	      }
++	    else
++	      {
++		// Declare a lot of variables to save repeating
++		// calculations.  Hopefully a decent JIT will put these
++		// in registers and make this fast
++		int p1 = start;
++		int p2 = mid;
++		int i = start + srcDestDiff;
++
++		// The main merge loop; terminates as soon as either
++		// half is ended
++		while (p1 < mid && p2 < end)
++		  {
++		    dest[i++] =
++		      src[c.compare(src[p1], src[p2]) <= 0 ? p1++ : p2++];
++		  }
++
++		// Finish up by copying the remainder of whichever half
++		// wasn't finished.
++		if (p1 < mid)
++		  System.arraycopy(src, p1, dest, i, mid - p1);
++		else
++		  System.arraycopy(src, p2, dest, i, end - p2);
++	      }
++	  }
++	// swap src and dest ready for the next merge
++	t = src;
++	src = dest;
++	dest = t;
++	from += srcDestDiff;
++	to += srcDestDiff;
++	srcDestDiff = -srcDestDiff;
++      }
++
++    // make sure the result ends up back in the right place.  Note
++    // that src and dest may have been swapped above, so src 
++    // contains the sorted array.
++    if (src != a)
+       {
+-        for (int i = from + 1; i < from + count; i++)
+-          for (int j = i;
+-               j > 0 && Double.compare(array[j - 1], array[j]) > 0;
+-               j--)
+-            {
+-              swap(j, j - 1, array);
+-            }
+-        return;
+-      }
+-
+-    // Determine a good median element.
+-    int mid = count / 2;
+-    int lo = from;
+-    int hi = from + count - 1;
+-
+-    if (count > 40)
+-      { // big arrays, pseudomedian of 9
+-        int s = count / 8;
+-        lo = med3(lo, lo + s, lo + s + s, array);
+-        mid = med3(mid - s, mid, mid + s, array);
+-        hi = med3(hi - s - s, hi - s, hi, array);
+-      }
+-    mid = med3(lo, mid, hi, array);
+-
+-    int a, b, c, d;
+-    int comp;
+-
+-    // Pull the median element out of the fray, and use it as a pivot.
+-    swap(from, mid, array);
+-    a = b = from + 1;
+-    c = d = hi;
+-
+-    // Repeatedly move b and c to each other, swapping elements so
+-    // that all elements before index b are less than the pivot, and all
+-    // elements after index c are greater than the pivot. a and b track
+-    // the elements equal to the pivot.
+-    while (true)
+-      {
+-        while (b <= c && (comp = Double.compare(array[b], array[from])) <= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(a, b, array);
+-                a++;
+-              }
+-            b++;
+-          }
+-        while (c >= b && (comp = Double.compare(array[c], array[from])) >= 0)
+-          {
+-            if (comp == 0)
+-              {
+-                swap(c, d, array);
+-                d--;
+-              }
+-            c--;
+-          }
+-        if (b > c)
+-          break;
+-        swap(b, c, array);
+-        b++;
+-        c--;
+-      }
+-
+-    // Swap pivot(s) back in place, the recurse on left and right sections.
+-    int span;
+-    span = Math.min(a - from, b - a);
+-    vecswap(from, b - span, span, array);
+-
+-    span = Math.min(d - c, hi - d - 1);
+-    vecswap(b, hi - span + 1, span, array);
+-
+-    span = b - a;
+-    if (span > 1)
+-      qsort(array, from, span);
+-
+-    span = d - c;
+-    if (span > 1)
+-      qsort(array, hi - span + 1, span);
++	// Note that from == 0.
++	System.arraycopy(src, 0, a, srcDestDiff, to);
++      }
+   }
+ 
+   /**
+@@ -2135,19 +1972,18 @@
+    * guaranteed to be stable, that is, equal elements will not be reordered.
+    * The sort algorithm is a mergesort with the merge omitted if the last
+    * element of one half comes before the first element of the other half. This
+-   * algorithm gives guaranteed O(n*log(n)) time, at the expense of making a
++   * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a
+    * copy of the array.
+    *
+    * @param a the array to be sorted
+-   * @throws ClassCastException if any two elements are not mutually
+-   *         comparable
+-   * @throws NullPointerException if an element is null (since
+-   *         null.compareTo cannot work)
+-   * @see Comparable
++   * @exception ClassCastException if any two elements are not mutually
++   *   comparable
++   * @exception NullPointerException if an element is null (since
++   *   null.compareTo cannot work)
+    */
+-  public static void sort(Object[] a)
++  public static void sort(Object[]a)
+   {
+-    sort(a, 0, a.length, null);
++    mergeSort(a, 0, a.length, defaultComparator);
+   }
+ 
+   /**
+@@ -2155,20 +1991,17 @@
+    * guaranteed to be stable, that is, equal elements will not be reordered.
+    * The sort algorithm is a mergesort with the merge omitted if the last
+    * element of one half comes before the first element of the other half. This
+-   * algorithm gives guaranteed O(n*log(n)) time, at the expense of making a
++   * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a
+    * copy of the array.
+    *
+    * @param a the array to be sorted
+-   * @param c a Comparator to use in sorting the array; or null to indicate
+-   *        the elements' natural order
+-   * @throws ClassCastException if any two elements are not mutually
+-   *         comparable by the Comparator provided
+-   * @throws NullPointerException if a null element is compared with natural
+-   *         ordering (only possible when c is null)
++   * @param c a Comparator to use in sorting the array
++   * @exception ClassCastException if any two elements are not mutually
++   *   comparable by the Comparator provided
+    */
+-  public static void sort(Object[] a, Comparator c)
++  public static void sort(Object[]a, Comparator c)
+   {
+-    sort(a, 0, a.length, c);
++    mergeSort(a, 0, a.length, c);
+   }
+ 
+   /**
+@@ -2176,23 +2009,24 @@
+    * guaranteed to be stable, that is, equal elements will not be reordered.
+    * The sort algorithm is a mergesort with the merge omitted if the last
+    * element of one half comes before the first element of the other half. This
+-   * algorithm gives guaranteed O(n*log(n)) time, at the expense of making a
++   * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a
+    * copy of the array.
+    *
+    * @param a the array to be sorted
+-   * @param fromIndex the index of the first element to be sorted
+-   * @param toIndex the index of the last element to be sorted plus one
+-   * @throws ClassCastException if any two elements are not mutually
+-   *         comparable
+-   * @throws NullPointerException if an element is null (since
+-   *         null.compareTo cannot work)
+-   * @throws ArrayIndexOutOfBoundsException, if fromIndex and toIndex
+-   *         are not in range.
+-   * @throws IllegalArgumentException if fromIndex > toIndex
++   * @param fromIndex the index of the first element to be sorted.
++   * @param toIndex the index of the last element to be sorted plus one.
++   * @exception ClassCastException if any two elements are not mutually
++   *   comparable by the Comparator provided
++   * @exception ArrayIndexOutOfBoundsException, if fromIndex and toIndex
++   *   are not in range.
++   * @exception IllegalArgumentException if fromIndex > toIndex
+    */
+-  public static void sort(Object[] a, int fromIndex, int toIndex)
++  public static void sort(Object[]a, int fromIndex, int toIndex)
+   {
+-    sort(a, fromIndex, toIndex, null);
++    if (fromIndex > toIndex)
++      throw new IllegalArgumentException("fromIndex " + fromIndex
++					 + " > toIndex " + toIndex);
++    mergeSort(a, fromIndex, toIndex, defaultComparator);
+   }
+ 
+   /**
+@@ -2200,197 +2034,56 @@
+    * guaranteed to be stable, that is, equal elements will not be reordered.
+    * The sort algorithm is a mergesort with the merge omitted if the last
+    * element of one half comes before the first element of the other half. This
+-   * algorithm gives guaranteed O(n*log(n)) time, at the expense of making a
++   * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a
+    * copy of the array.
+    *
+    * @param a the array to be sorted
+-   * @param fromIndex the index of the first element to be sorted
+-   * @param toIndex the index of the last element to be sorted plus one
+-   * @param c a Comparator to use in sorting the array; or null to indicate
+-   *        the elements' natural order
+-   * @throws ClassCastException if any two elements are not mutually
+-   *         comparable by the Comparator provided
+-   * @throws ArrayIndexOutOfBoundsException, if fromIndex and toIndex
+-   *         are not in range.
+-   * @throws IllegalArgumentException if fromIndex > toIndex
+-   * @throws NullPointerException if a null element is compared with natural
+-   *         ordering (only possible when c is null)
++   * @param fromIndex the index of the first element to be sorted.
++   * @param toIndex the index of the last element to be sorted plus one.
++   * @param c a Comparator to use in sorting the array
++   * @exception ClassCastException if any two elements are not mutually
++   *   comparable by the Comparator provided
++   * @exception ArrayIndexOutOfBoundsException, if fromIndex and toIndex
++   *   are not in range.
++   * @exception IllegalArgumentException if fromIndex > toIndex
+    */
+-  public static void sort(Object[] a, int fromIndex, int toIndex, Comparator c)
++  public static void sort(Object[]a, int fromIndex, int toIndex, Comparator c)
+   {
+     if (fromIndex > toIndex)
+       throw new IllegalArgumentException("fromIndex " + fromIndex
+-                                         + " > toIndex " + toIndex);
+-
+-    // In general, the code attempts to be simple rather than fast, the
+-    // idea being that a good optimising JIT will be able to optimise it
+-    // better than I can, and if I try it will make it more confusing for
+-    // the JIT. First presort the array in chunks of length 6 with insertion
+-    // sort. A mergesort would give too much overhead for this length.
+-    for (int chunk = fromIndex; chunk < toIndex; chunk += 6)
+-      {
+-        int end = Math.min(chunk + 6, toIndex);
+-        for (int i = chunk + 1; i < end; i++)
+-          {
+-            if (Collections.compare(a[i - 1], a[i], c) > 0)
+-              {
+-                // not already sorted
+-                int j = i;
+-                Object elem = a[j];
+-                do
+-                  {
+-                    a[j] = a[j - 1];
+-                    j--;
+-                  }
+-                while (j > chunk
+-                       && Collections.compare(a[j - 1], elem, c) > 0);
+-                a[j] = elem;
+-              }
+-          }
+-      }
+-
+-    int len = toIndex - fromIndex;
+-    // If length is smaller or equal 6 we are done.
+-    if (len <= 6)
+-      return;
+-
+-    Object[] src = a;
+-    Object[] dest = new Object[len];
+-    Object[] t = null; // t is used for swapping src and dest
+-
+-    // The difference of the fromIndex of the src and dest array.
+-    int srcDestDiff = -fromIndex;
+-
+-    // The merges are done in this loop
+-    for (int size = 6; size < len; size <<= 1)
+-      {
+-        for (int start = fromIndex; start < toIndex; start += size << 1)
+-          {
+-            // mid is the start of the second sublist;
+-            // end the start of the next sublist (or end of array).
+-            int mid = start + size;
+-            int end = Math.min(toIndex, mid + size);
+-
+-            // The second list is empty or the elements are already in
+-            // order - no need to merge
+-            if (mid >= end
+-                || Collections.compare(src[mid - 1], src[mid], c) <= 0)
+-              {
+-                System.arraycopy(src, start,
+-                                 dest, start + srcDestDiff, end - start);
+-
+-                // The two halves just need swapping - no need to merge
+-              }
+-            else if (Collections.compare(src[start], src[end - 1], c) > 0)
+-              {
+-                System.arraycopy(src, start,
+-                                 dest, end - size + srcDestDiff, size);
+-                System.arraycopy(src, mid,
+-                                 dest, start + srcDestDiff, end - mid);
+-
+-              }
+-            else
+-              {
+-                // Declare a lot of variables to save repeating
+-                // calculations.  Hopefully a decent JIT will put these
+-                // in registers and make this fast
+-                int p1 = start;
+-                int p2 = mid;
+-                int i = start + srcDestDiff;
+-
+-                // The main merge loop; terminates as soon as either
+-                // half is ended
+-                while (p1 < mid && p2 < end)
+-                  {
+-                    dest[i++] =
+-                      src[(Collections.compare(src[p1], src[p2], c) <= 0
+-                           ? p1++ : p2++)];
+-                  }
+-
+-                // Finish up by copying the remainder of whichever half
+-                // wasn't finished.
+-                if (p1 < mid)
+-                  System.arraycopy(src, p1, dest, i, mid - p1);
+-                else
+-                  System.arraycopy(src, p2, dest, i, end - p2);
+-              }
+-          }
+-        // swap src and dest ready for the next merge
+-        t = src;
+-        src = dest;
+-        dest = t;
+-        fromIndex += srcDestDiff;
+-        toIndex += srcDestDiff;
+-        srcDestDiff = -srcDestDiff;
+-      }
+-
+-    // make sure the result ends up back in the right place.  Note
+-    // that src and dest may have been swapped above, so src
+-    // contains the sorted array.
+-    if (src != a)
+-      {
+-        // Note that fromIndex == 0.
+-        System.arraycopy(src, 0, a, srcDestDiff, toIndex);
+-      }
++					 + " > toIndex " + toIndex);
++    mergeSort(a, fromIndex, toIndex, c);
+   }
+ 
+-
+-// asList
+   /**
+    * Returns a list "view" of the specified array. This method is intended to
+    * make it easy to use the Collections API with existing array-based APIs and
+-   * programs. Changes in the list or the array show up in both places. The
+-   * list does not support element addition or removal, but does permit
+-   * value modification. The returned list implements both Serializable and
+-   * RandomAccess.
++   * programs.
+    *
+    * @param a the array to return a view of
+-   * @return a fixed-size list, changes to which "write through" to the array
+-   * @see Serializable
+-   * @see RandomAccess
+-   * @see Arrays.ArrayList
++   * @returns a fixed-size list, changes to which "write through" to the array
+    */
+-  public static List asList(final Object[] a)
++  public static List asList(final Object[]a)
+   {
+-    return new Arrays.ArrayList(a);
++    if (a == null)
++      {
++	throw new NullPointerException();
++      }
++
++    return new ListImpl(a);
+   }
+ 
++
+   /**
+-   * Inner class used by {@link #asList(Object[])} to provide a list interface
+-   * to an array. The name, though it clashes with java.util.ArrayList, is
+-   * Sun's choice for Serialization purposes. Element addition and removal
+-   * is prohibited, but values can be modified.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   * @status updated to 1.4
++   * Inner class used by asList(Object[]) to provide a list interface
++   * to an array. The methods are all simple enough to be self documenting.
++   * Note: When Sun fully specify serialized forms, this class will have to
++   * be renamed.
+    */
+-  private static final class ArrayList extends AbstractList
+-    implements Serializable, RandomAccess
++  private static class ListImpl extends AbstractList
+   {
+-    // We override the necessary methods, plus others which will be much
+-    // more efficient with direct iteration rather than relying on iterator().
+-
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -2764017481108945198L;
+-
+-    /**
+-     * The array we are viewing.
+-     * @serial the array
+-     */
+-    private final Object[] a;
+-
+-    /**
+-     * Construct a list view of the array.
+-     * @param a the array to view
+-     * @throws NullPointerException if a is null
+-     */
+-    ArrayList(Object[] a)
++    ListImpl(Object[]a)
+     {
+-      // We have to explicitly check.
+-      if (a == null)
+-        throw new NullPointerException();
+       this.a = a;
+     }
+ 
+@@ -2411,45 +2104,6 @@
+       return old;
+     }
+ 
+-    public boolean contains(Object o)
+-    {
+-      return lastIndexOf(o) >= 0;
+-    }
+-
+-    public int indexOf(Object o)
+-    {
+-      int size = a.length;
+-      for (int i = 0; i < size; i++)
+-        if (equals(o, a[i]))
+-          return i;
+-      return -1;
+-    }
+-
+-    public int lastIndexOf(Object o)
+-    {
+-      int i = a.length;
+-      while (--i >= 0)
+-        if (equals(o, a[i]))
+-          return i;
+-      return -1;
+-    }
+-
+-    public Object[] toArray()
+-    {
+-      return (Object[]) a.clone();
+-    }
+-
+-    public Object[] toArray(Object[] array)
+-    {
+-      int size = a.length;
+-      if (array.length < size)
+-        array = (Object[])
+-          Array.newInstance(array.getClass().getComponentType(), size);
+-      else if (array.length > size)
+-        array[size] = null;
+-
+-      System.arraycopy(a, 0, array, 0, size);
+-      return array;
+-    }
++    private Object[] a;
+   }
+ }
Index: compare/java.util.BasicMapEntry.diff
===================================================================
RCS file: java.util.BasicMapEntry.diff
diff -N java.util.BasicMapEntry.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.BasicMapEntry.diff Tue Nov 6 17:21:29 2001
@@ -0,0 +1,150 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/BasicMapEntry.java	Fri Oct 19 18:43:44 2001
++++ java/util/BasicMapEntry.java	Tue Oct 16 09:14:34 2001
+@@ -1,6 +1,6 @@
+ /* BasicMapEntry.java -- a class providing a plain-vanilla implementation of
+    the Map.Entry interface; could be used anywhere in java.util
+-   Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -29,113 +29,52 @@
+ package java.util;
+ 
+ /**
+- * A class which implements Map.Entry. It is shared by HashMap, TreeMap,
+- * Hashtable, and Collections. It is not specified by the JDK, but makes
+- * life much easier.
++ * A class which implements Map.Entry. It is shared by HashMap, TreeMap, and
++ * Hashtable.
+  *
+- * @author Jon Zeppieri
+- * @author Eric Blake <ebb9@email.byu.edu>
++ * @author      Jon Zeppieri
+  */
+ class BasicMapEntry implements Map.Entry
+ {
+-  /**
+-   * The key. Package visible for direct manipulation.
+-   */
+   Object key;
+-
+-  /**
+-   * The value. Package visible for direct manipulation.
+-   */
+   Object value;
+ 
+-  /**
+-   * Basic constructor initializes the fields.
+-   * @param newKey the key
+-   * @param newValue the value
+-   */
+   BasicMapEntry(Object newKey, Object newValue)
+   {
+     key = newKey;
+     value = newValue;
+   }
+ 
+-  /**
+-   * Compares the specified object with this entry. Returns true only if
+-   * the object is a mapping of identical key and value. In other words,
+-   * this must be:
+-   * <pre>
+-   * (o instanceof Map.Entry) &&
+-   * (getKey() == null ? ((HashMap) o).getKey() == null
+-   *                   : getKey().equals(((HashMap) o).getKey())) &&
+-   * (getValue() == null ? ((HashMap) o).getValue() == null
+-   *                   : getValue().equals(((HashMap) o).getValue()))
+-   * </pre>
+-   *
+-   * @param o the object to compare
+-   * @return true if it is equal
+-   */
+   public final boolean equals(Object o)
+   {
+-    if (! (o instanceof Map.Entry))
++    if (!(o instanceof Map.Entry))
+       return false;
+-    // Optimize for our own entries.
+-    if (o instanceof BasicMapEntry)
+-      {
+-        BasicMapEntry e = (BasicMapEntry) o;
+-        return (AbstractCollection.equals(key, e.key)
+-                && AbstractCollection.equals(value, e.value));
+-      }
+     Map.Entry e = (Map.Entry) o;
+-    return (AbstractCollection.equals(key, e.getKey())
+-            && AbstractCollection.equals(value, e.getValue()));
++    return (key == null ? e.getKey() == null : key.equals(e.getKey())
++            && value == null ? e.getValue() == null 
++			     : value.equals(e.getValue()));
+   }
+ 
+-  /**
+-   * Get the key corresponding to this entry.
+-   *
+-   * @return the key
+-   */
+   public final Object getKey()
+   {
+     return key;
+   }
+ 
+-  /**
+-   * Get the value corresponding to this entry. If you already called
+-   * Iterator.remove(), the behavior undefined, but in this case it works.
+-   *
+-   * @return the value
+-   */
+   public final Object getValue()
+   {
+     return value;
+   }
+ 
+-  /**
+-   * Returns the hash code of the entry.  This is defined as the exclusive-or
+-   * of the hashcodes of the key and value (using 0 for null). In other
+-   * words, this must be:
+-   * <pre>
+-   *  (getKey() == null ? 0 : getKey().hashCode()) ^
+-   *  (getValue() == null ? 0 : getValue().hashCode())
+-   * </pre>
+-   *
+-   * @return the hash code
+-   */
+   public final int hashCode()
+   {
+-    return (AbstractCollection.hashCode(key)
+-            ^ AbstractCollection.hashCode(value));
++    int kc = (key == null ? 0 : key.hashCode());
++    int vc = (value == null ? 0 : value.hashCode());
++    return kc ^ vc;
+   }
+ 
+-  /**
+-   * Replaces the value with the specified object. This writes through
+-   * to the map, unless you have already called Iterator.remove(). It
+-   * may be overridden to restrict a null value.
+-   *
+-   * @param newVal the new value to store
+-   * @return the old value
+-   * @throws NullPointerException if the map forbids null values
++  /** 
++   * sets the value of this Map.Entry. Note that this is overriden by 
++   * Hashtable.Entry, which does not permit a null value.
+    */
+   public Object setValue(Object newVal)
+   {
+@@ -144,12 +83,6 @@
+     return r;
+   }
+ 
+-  /**
+-   * This provides a string representation of the entry. It is of the form
+-   * "key=value", where string concatenation is used on key and value.
+-   *
+-   * @return the string representation
+-   */
+   public final String toString()
+   {
+     return key + "=" + value;
Index: compare/java.util.BitSet.diff
===================================================================
RCS file: java.util.BitSet.diff
diff -N java.util.BitSet.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.BitSet.diff Tue Nov 6 17:21:30 2001
@@ -0,0 +1,762 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/BitSet.java	Fri Oct 19 18:43:44 2001
++++ java/util/BitSet.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,6 @@
+-/* BitSet.java -- A vector of bits.
+-   Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation, Inc.
++// BitSet - A vector of bits.
++
++/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -49,32 +50,22 @@
+  * while another thread is simultaneously modifying it, the results are
+  * undefined.
+  *
++ * @specnote Historically, there has been some confusion as to whether or not 
++ *           this class should be synchronized. From an efficiency perspective,
++ *           it is very undesirable to synchronize it because multiple locks 
++ *           and explicit lock ordering are required to safely synchronize some
++ *           methods. The JCL 1.2 supplement book specifies that as of JDK 
++ *           1.2, the class is no longer synchronized.
++ *
+  * @author Jochen Hoenicke
+  * @author Tom Tromey <tromey@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @status updated to 1.4
++ * @date October 23, 1998.
++ * @status API complete to JDK 1.3.
+  */
+ public class BitSet implements Cloneable, Serializable
+ {
+   /**
+-   * Compatible with JDK 1.0.
+-   */
+-  private static final long serialVersionUID = 7997698588986878753L;
+-
+-  /**
+-   * A common mask.
+-   */
+-  private static final int LONG_MASK = 0x3f;
+-
+-  /**
+-   * The actual bits.
+-   * @serial the i'th bit is in bits[i/64] at position i%64 (where position
+-   *         0 is the least significant).
+-   */
+-  private long[] bits;
+-
+-  /**
+-   * Create a new empty bit set. All bits are initially false.
++   * Create a new empty bit set.
+    */
+   public BitSet()
+   {
+@@ -84,15 +75,18 @@
+   /**
+    * Create a new empty bit set, with a given size.  This
+    * constructor reserves enough space to represent the integers
+-   * from <code>0</code> to <code>nbits-1</code>.
+-   *
+-   * @param nbits the initial size of the bit set
+-   * @throws NegativeArraySizeException if nbits &lt; 0
++   * from <code>0</code> to <code>nbits-1</code>.  
++   * @param nbits the initial size of the bit set.
++   * @throws NegativeArraySizeException if the specified initial
++   * size is negative.  
++   * @require nbits >= 0
+    */
+   public BitSet(int nbits)
+   {
+-    int length = nbits >>> 6;
+-    if ((nbits & LONG_MASK) != 0)
++    if (nbits < 0)
++      throw new NegativeArraySizeException();
++    int length = nbits / 64;
++    if (nbits % 64 != 0)
+       ++length;
+     bits = new long[length];
+   }
+@@ -101,9 +95,8 @@
+    * Performs the logical AND operation on this bit set and the
+    * given <code>set</code>.  This means it builds the intersection
+    * of the two sets.  The result is stored into this bit set.
+-   *
+-   * @param set the second bit set
+-   * @throws NullPointerException if set is null
++   * @param set the second bit set.
++   * @require set != null
+    */
+   public void and(BitSet bs)
+   {
+@@ -111,7 +104,7 @@
+     int i;
+     for (i = 0; i < max; ++i)
+       bits[i] &= bs.bits[i];
+-    while (++i < bits.length)
++    for (; i < bits.length; ++i)
+       bits[i] = 0;
+   }
+ 
+@@ -119,135 +112,55 @@
+    * Performs the logical AND operation on this bit set and the
+    * complement of the given <code>set</code>.  This means it
+    * selects every element in the first set, that isn't in the
+-   * second set.  The result is stored into this bit set.
+-   *
+-   * @param set the second bit set
+-   * @throws NullPointerException if set is null
+-   * @since 1.2
++   * second set.  The result is stored into this bit set.  
++   * @param set the second bit set.  
++   * @require set != null
++   * @since JDK1.2
+    */
+   public void andNot(BitSet bs)
+   {
+-    int i = Math.min(bits.length, bs.bits.length);
+-    while (--i > 0)
++    int max = Math.min(bits.length, bs.bits.length);
++    int i;
++    for (i = 0; i < max; ++i)
+       bits[i] &= ~bs.bits[i];
+   }
+ 
+   /**
+-   * Returns the number of bits set to true.
+-   *
+-   * @return the number of true bits
+-   * @since 1.4
+-   */
+-  public int cardinality()
+-  {
+-    int card = 0;
+-    for (int i = bits.length - 1; i >= 0; i--)
+-      {
+-        long a = bits[i];
+-        // Take care of common cases.
+-        if (a == 0)
+-          continue;
+-        if (a == -1)
+-          {
+-            card += 64;
+-            continue;
+-          }
+-
+-        // Successively collapse alternating bit groups into a sum.
+-        a = ((a >> 1) & 0x5555555555555555L) + (a & 0x5555555555555555L);
+-        a = ((a >> 2) & 0x3333333333333333L) + (a & 0x3333333333333333L);
+-        int b = (int) ((a >>> 32) + a);
+-        b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f);
+-        b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff);
+-        card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff);
+-      }
+-    return card;
+-  }
+-
+-  /**
+-   * Sets all bits in the set to false.
+-   *
+-   * @since 1.4
+-   */
+-  public void clear()
+-  {
+-    Arrays.fill(bits, 0);
+-  }
+-
+-  /**
+    * Removes the integer <code>bitIndex</code> from this set. That is
+    * the corresponding bit is cleared.  If the index is not in the set,
+    * this method does nothing.
+-   *
+-   * @param bitIndex a non-negative integer
+-   * @throws IndexOutOfBoundsException if bitIndex &lt; 0
++   * @param bitIndex a non-negative integer.
++   * @exception ArrayIndexOutOfBoundsException if the specified bit index
++   * is negative.
++   * @require bitIndex >= 0
+    */
+   public void clear(int pos)
+   {
+-    int offset = pos >>> 6;
+-    ensure(offset);
+-    // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
+-    // so we'll just let that be our exception.
+-    bits[offset] &= ~(1L << pos);
+-  }
+-
+-  /**
+-   * Sets the bits between from (inclusive) and to (exclusive) to false.
+-   *
+-   * @param from the start range (inclusive)
+-   * @param to the end range (exclusive)
+-   * @throws IndexOutOfBoundsException if from &lt; 0 || from &gt; to
+-   * @since 1.4
+-   */
+-  public void clear(int from, int to)
+-  {
+-    if (from < 0 || from > to)
++    if (pos < 0)
+       throw new IndexOutOfBoundsException();
+-    if (from == to)
+-      return;
+-    int lo_offset = from >>> 6;
+-    int hi_offset = to >>> 6;
+-    ensure(hi_offset);
+-    if (lo_offset == hi_offset)
+-      {
+-        bits[hi_offset] &= ((1L << from) - 1) | (-1L << to);
+-        return;
+-      }
+-
+-    bits[lo_offset] &= (1L << from) - 1;
+-    bits[hi_offset] &= -1L << to;
+-    for (int i = lo_offset + 1; i < hi_offset; i++)
+-      bits[i] = 0;
++    int bit = pos % 64;
++    int offset = pos / 64;
++    ensure(offset);
++    bits[offset] &= ~(1L << bit);
+   }
+ 
+   /**
+    * Create a clone of this bit set, that is an instance of the same
+    * class and contains the same elements.  But it doesn't change when
+    * this bit set changes.
+-   *
+    * @return the clone of this object.
+    */
+   public Object clone()
+   {
+-    try
+-      {
+-        BitSet bs = (BitSet) super.clone();
+-        bs.bits = (long[]) bits.clone();
+-        return bs;
+-      }
+-    catch (CloneNotSupportedException e)
+-      {
+-        // Impossible to get here.
+-        return null;
+-      }
++    BitSet bs = new BitSet(bits.length * 64);
++    System.arraycopy(bits, 0, bs.bits, 0, bits.length);
++    return bs;
+   }
+ 
+   /**
+    * Returns true if the <code>obj</code> is a bit set that contains
+    * exactly the same elements as this bit set, otherwise false.
+-   *
+-   * @param obj the object to compare to
+-   * @return true if obj equals this bit set
++   * @return true if obj equals this bit set.
+    */
+   public boolean equals(Object obj)
+   {
+@@ -258,124 +171,42 @@
+     int i;
+     for (i = 0; i < max; ++i)
+       if (bits[i] != bs.bits[i])
+-        return false;
++	return false;
+     // If one is larger, check to make sure all extra bits are 0.
+     for (int j = i; j < bits.length; ++j)
+       if (bits[j] != 0)
+-        return false;
++	return false;
+     for (int j = i; j < bs.bits.length; ++j)
+       if (bs.bits[j] != 0)
+-        return false;
++	return false;
+     return true;
+   }
+ 
+   /**
+-   * Sets the bit at the index to the opposite value.
+-   *
+-   * @param index the index of the bit
+-   * @throws IndexOutOfBoundsException if index is negative
+-   * @since 1.4
+-   */
+-  public void flip(int index)
+-  {
+-    int offset = index >>> 6;
+-    ensure(offset);
+-    // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
+-    // so we'll just let that be our exception.
+-    bits[offset] ^= 1L << index;
+-  }
+-
+-  /**
+-   * Sets a range of bits to the opposite value.
+-   *
+-   * @param from the low index (inclusive)
+-   * @param to the high index (exclusive)
+-   * @throws IndexOutOfBoundsException if from &gt; to || from &lt; 0
+-   * @since 1.4
+-   */
+-  public void flip(int from, int to)
+-  {
+-    if (from < 0 || from > to)
+-      throw new IndexOutOfBoundsException();
+-    if (from == to)
+-      return;
+-    int lo_offset = from >>> 6;
+-    int hi_offset = to >>> 6;
+-    ensure(hi_offset);
+-    if (lo_offset == hi_offset)
+-      {
+-        bits[hi_offset] ^= (-1L << from) & ((1L << to) - 1);
+-        return;
+-      }
+-
+-    bits[lo_offset] ^= -1L << from;
+-    bits[hi_offset] ^= (1L << to) - 1;
+-    for (int i = lo_offset + 1; i < hi_offset; i++)
+-      bits[i] ^= -1;
+-  }
+-
+-  /**
+    * Returns true if the integer <code>bitIndex</code> is in this bit
+    * set, otherwise false.
+-   *
+-   * @param pos a non-negative integer
+-   * @return the value of the bit at the specified index
+-   * @throws IndexOutOfBoundsException if the index is negative
++   * @param bitIndex a non-negative integer
++   * @return the value of the bit at the specified index.
++   * @exception ArrayIndexOutOfBoundsException if the specified bit index
++   * is negative.
++   * @require bitIndex >= 0
+    */
+   public boolean get(int pos)
+   {
+-    int offset = pos >>> 6;
++    if (pos < 0)
++      throw new IndexOutOfBoundsException();
++
++    int bit = pos % 64;
++    int offset = pos / 64;
++
+     if (offset >= bits.length)
+       return false;
+-    // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
+-    // so we'll just let that be our exception.
+-    return (bits[offset] & (1L << pos)) != 0;
+-  }
+-
+-  /**
+-   * Returns a new <code>BitSet</code> composed of a range of bits from
+-   * this one.
+-   *
+-   * @param from the low index (inclusive)
+-   * @param to the high index (exclusive)
+-   * @throws IndexOutOfBoundsException if from &gt; to || from &lt; 0
+-   * @since 1.4
+-   */
+-  public BitSet get(int from, int to)
+-  {
+-    if (from < 0 || from > to)
+-      throw new IndexOutOfBoundsException();
+-    BitSet bs = new BitSet(to - from);
+-    int lo_offset = from >>> 6;
+-    if (lo_offset >= bits.length)
+-      return bs;
+-
+-    int lo_bit = from & LONG_MASK;
+-    int hi_offset = to >>> 6;
+-    if (lo_bit == 0)
+-      {
+-        int len = Math.min(hi_offset - lo_offset + 1, bits.length - lo_offset);
+-        System.arraycopy(bits, lo_offset, bs.bits, 0, len);
+-        if (hi_offset < bits.length)
+-          bs.bits[hi_offset - lo_offset] &= (1L << to) - 1;
+-        return bs;
+-      }
+ 
+-    int len = Math.min(hi_offset, bits.length - 1);
+-    int reverse = ~lo_bit;
+-    int i;
+-    for (i = 0; lo_offset < len; lo_offset++, i++)
+-      bs.bits[i] = ((bits[lo_offset] >>> lo_bit)
+-                    | (bits[lo_offset + 1] << reverse));
+-    if ((to & LONG_MASK) > lo_bit)
+-      bs.bits[i++] = bits[lo_offset] >>> lo_bit;
+-    if (hi_offset < bits.length)
+-      bs.bits[i - 1] &= (1L << (to - from)) - 1;
+-    return bs;
++    return (bits[offset] & (1L << bit)) == 0 ? false : true;
+   }
+ 
+   /**
+-   * Returns a hash code value for this bit set.  The hash code of
++   * Returns a hash code value for this bit set.  The hash code of 
+    * two bit sets containing the same integers is identical.  The algorithm
+    * used to compute it is as follows:
+    *
+@@ -402,55 +233,21 @@
+    * </pre>
+    *
+    * Note that the hash code values changes, if the set is changed.
+-   *
+    * @return the hash code value for this bit set.
+    */
+   public int hashCode()
+   {
+     long h = 1234;
+-    for (int i = bits.length; i > 0; )
+-      h ^= i * bits[--i];
++    for (int i = bits.length - 1; i >= 0; --i)
++      h ^= bits[i] * (i + 1);
+     return (int) ((h >> 32) ^ h);
+   }
+ 
+   /**
+-   * Returns true if the specified BitSet and this one share at least one
+-   * common true bit.
+-   *
+-   * @param set the set to check for intersection
+-   * @return true if the sets intersect
+-   * @throws NullPointerException if set is null
+-   * @since 1.4
+-   */
+-  public boolean intersects(BitSet set)
+-  {
+-    int i = Math.min(bits.length, set.bits.length);
+-    while (--i >= 0)
+-      if ((bits[i] & set.bits[i]) != 0)
+-        return true;
+-    return false;
+-  }
+-
+-  /**
+-   * Returns true if this set contains no true bits.
+-   *
+-   * @return true if all bits are false
+-   * @since 1.4
+-   */
+-  public boolean isEmpty()
+-  {
+-    for (int i = bits.length - 1; i >= 0; i--)
+-      if (bits[i] != 0)
+-        return false;
+-    return true;
+-  }
+-
+-  /**
+    * Returns the logical number of bits actually used by this bit
+    * set.  It returns the index of the highest set bit plus one.
+    * Note that this method doesn't return the number of set bits.
+-   *
+-   * @return the index of the highest set bit plus one.
++   * @return the index of the highest set bit plus one.  
+    */
+   public int length()
+   {
+@@ -469,188 +266,54 @@
+     // b >= 0 checks if the highest bit is zero.
+     while (b >= 0)
+       {
+-        --len;
+-        b <<= 1;
++	--len;
++	b <<= 1;
+       }
+ 
+     return len;
+   }
+ 
+   /**
+-   * Returns the index of the next false bit, from the specified bit
+-   * (inclusive).
+-   *
+-   * @param from the start location
+-   * @return the first false bit
+-   * @throws IndexOutOfBoundsException if from is negative
+-   * @since 1.4
+-   */
+-  public int nextClearBit(int from)
+-  {
+-    int offset = from >>> 6;
+-    long mask = 1L << from;
+-    while (offset < bits.length)
+-      {
+-        // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
+-        // so we'll just let that be our exception.
+-        long h = bits[offset];
+-        do
+-          {
+-            if ((h & mask) == 0)
+-              return from;
+-            mask <<= 1;
+-            from++;
+-          }
+-        while (mask != 0);
+-        mask = 1;
+-        offset++;
+-      }
+-    return from;
+-  }
+-
+-  /**
+-   * Returns the index of the next true bit, from the specified bit
+-   * (inclusive). If there is none, -1 is returned. You can iterate over
+-   * all true bits with this loop:<br>
+-   * <pre>
+-   * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
+-   *   { // operate on i here }
+-   * </pre>
+-   *
+-   * @param from the start location
+-   * @return the first true bit, or -1
+-   * @throws IndexOutOfBoundsException if from is negative
+-   * @since 1.4
+-   */
+-  public int nextSetBit(int from)
+-  {
+-    int offset = from >>> 6;
+-    long mask = 1L << from;
+-    while (offset < bits.length)
+-      {
+-        // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
+-        // so we'll just let that be our exception.
+-        long h = bits[offset];
+-        do
+-          {
+-            if ((h & mask) != 0)
+-              return from;
+-            mask <<= 1;
+-            from++;
+-          }
+-        while (mask != 0);
+-        mask = 1;
+-        offset++;
+-      }
+-    return -1;
+-  }
+-
+-  /**
+    * Performs the logical OR operation on this bit set and the
+    * given <code>set</code>.  This means it builds the union
+    * of the two sets.  The result is stored into this bit set, which
+    * grows as necessary.
+-   *
+-   * @param bs the second bit set
+-   * @throws NullPointerException if bs is null
++   * @param set the second bit set.
++   * @exception OutOfMemoryError if the current set can't grow.
++   * @require set != null
+    */
+   public void or(BitSet bs)
+   {
+     ensure(bs.bits.length - 1);
+-    for (int i = bs.bits.length - 1; i >= 0; i--)
++    int i;
++    for (i = 0; i < bs.bits.length; ++i)
+       bits[i] |= bs.bits[i];
+   }
+ 
+   /**
+-   * Add the integer <code>bitIndex</code> to this set.  That is
++   * Add the integer <code>bitIndex</code> to this set.  That is 
+    * the corresponding bit is set to true.  If the index was already in
+    * the set, this method does nothing.  The size of this structure
+    * is automatically increased as necessary.
+-   *
+-   * @param pos a non-negative integer.
+-   * @throws IndexOutOfBoundsException if pos is negative
++   * @param bitIndex a non-negative integer.
++   * @exception ArrayIndexOutOfBoundsException if the specified bit index
++   * is negative.
++   * @require bitIndex >= 0
+    */
+   public void set(int pos)
+   {
+-    int offset = pos >>> 6;
+-    ensure(offset);
+-    // ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
+-    // so we'll just let that be our exception.
+-    bits[offset] |= 1L << pos;
+-  }
+-
+-  /**
+-   * Sets the bit at the given index to the specified value. The size of
+-   * this structure is automatically increased as necessary.
+-   *
+-   * @param index the position to set
+-   * @param value the value to set it to
+-   * @throws IndexOutOfBoundsException if index is negative
+-   * @since 1.4
+-   */
+-  public void set(int index, boolean value)
+-  {
+-    // Too bad you can't use ?: with void statements!
+-    if (value)
+-      set(index);
+-    else
+-      clear(index);
+-  }
+-
+-  /**
+-   * Sets the bits between from (inclusive) and to (exclusive) to true.
+-   *
+-   * @param from the start range (inclusive)
+-   * @param to the end range (exclusive)
+-   * @throws IndexOutOfBoundsException if from &lt; 0 || from &gt; to
+-   * @since 1.4
+-   */
+-  public void set(int from, int to)
+-  {
+-    if (from < 0 || from > to)
++    if (pos < 0)
+       throw new IndexOutOfBoundsException();
+-    if (from == to)
+-      return;
+-    int lo_offset = from >>> 6;
+-    int hi_offset = to >>> 6;
+-    ensure(hi_offset);
+-    if (lo_offset == hi_offset)
+-      {
+-        bits[hi_offset] |= (-1L << from) & ((1L << to) - 1);
+-        return;
+-      }
+-
+-    bits[lo_offset] |= -1L << from;
+-    bits[hi_offset] |= (1L << to) - 1;
+-    for (int i = lo_offset + 1; i < hi_offset; i++)
+-      bits[i] = -1;
+-  }
+-
+-  /**
+-   * Sets the bits between from (inclusive) and to (exclusive) to the
+-   * specified value.
+-   *
+-   * @param from the start range (inclusive)
+-   * @param to the end range (exclusive)
+-   * @param value the value to set it to
+-   * @throws IndexOutOfBoundsException if from &lt; 0 || from &gt; to
+-   * @since 1.4
+-   */
+-  public void set(int from, int to, boolean value)
+-  {
+-    // Too bad you can't use ?: with void statements!
+-    if (value)
+-      set(from, to);
+-    else
+-      clear(from, to);
++    int bit = pos % 64;
++    int offset = pos / 64;
++    ensure(offset);
++    bits[offset] |= 1L << bit;
+   }
+ 
+   /**
+    * Returns the number of bits actually used by this bit set.  Note
+-   * that this method doesn't return the number of set bits, and that
+-   * future requests for larger bits will make this automatically grow.
+-   *
+-   * @return the number of bits currently used.
++   * that this method doesn't return the number of set bits.
++   * @returns the number of bits currently used.  
+    */
+   public int size()
+   {
+@@ -661,32 +324,32 @@
+    * Returns the string representation of this bit set.  This
+    * consists of a comma separated list of the integers in this set
+    * surrounded by curly braces.  There is a space after each comma.
+-   * A sample string is thus "{1, 3, 53}".
+    * @return the string representation.
+    */
+   public String toString()
+   {
+-    StringBuffer r = new StringBuffer("{");
++    String r = "{";
+     boolean first = true;
+     for (int i = 0; i < bits.length; ++i)
+       {
+-        long bit = 1;
+-        long word = bits[i];
+-        if (word == 0)
+-          continue;
+-        for (int j = 0; j < 64; ++j)
+-          {
+-            if ((word & bit) != 0)
+-              {
+-                if (! first)
+-                  r.append(", ");
+-                r.append(64 * i + j);
+-                first = false;
+-              }
+-            bit <<= 1;
+-          }
++	long bit = 1;
++	long word = bits[i];
++	if (word == 0)
++	  continue;
++	for (int j = 0; j < 64; ++j)
++	  {
++	    if ((word & bit) != 0)
++	      {
++		if (!first)
++		  r += ", ";
++		r += Integer.toString(64 * i + j);
++		first = false;
++	      }
++	    bit <<= 1;
++	  }
+       }
+-    return r.append("}").toString();
++
++    return r += "}";
+   }
+ 
+   /**
+@@ -694,30 +357,32 @@
+    * given <code>set</code>.  This means it builds the symmetric
+    * remainder of the two sets (the elements that are in one set,
+    * but not in the other).  The result is stored into this bit set,
+-   * which grows as necessary.
+-   *
+-   * @param bs the second bit set
+-   * @throws NullPointerException if bs is null
++   * which grows as necessary.  
++   * @param set the second bit set.
++   * @exception OutOfMemoryError if the current set can't grow.  
++   * @require set != null
+    */
+   public void xor(BitSet bs)
+   {
+     ensure(bs.bits.length - 1);
+-    for (int i = bs.bits.length - 1; i > 0; i--)
++    int i;
++    for (i = 0; i < bs.bits.length; ++i)
+       bits[i] ^= bs.bits[i];
+   }
+ 
+-  /**
+-   * Make sure the vector is big enough.
+-   *
+-   * @param lastElt the size needed for the bits array
+-   */
++  // Make sure the vector is big enough.
+   private final void ensure(int lastElt)
+   {
+-    if (lastElt >= bits.length)
++    if (lastElt + 1 > bits.length)
+       {
+-        long[] nd = new long[lastElt + 1];
+-        System.arraycopy(bits, 0, nd, 0, bits.length);
+-        bits = nd;
++	long[] nd = new long[lastElt + 1];
++	System.arraycopy(bits, 0, nd, 0, bits.length);
++	bits = nd;
+       }
+   }
++
++  // The actual bits.
++  long[] bits;
++
++  private static final long serialVersionUID = 7997698588986878753L;
+ }
Index: compare/java.util.Calendar.diff
===================================================================
RCS file: java.util.Calendar.diff
diff -N java.util.Calendar.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Calendar.diff Tue Nov 6 17:21:30 2001
@@ -0,0 +1,38 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Calendar.java	Mon Jul 30 11:15:08 2001
++++ java/util/Calendar.java	Fri Nov  2 21:44:51 2001
+@@ -445,7 +445,7 @@
+   }
+ 
+   /**
+-   * Gets the set of locales for which a Calendar is availiable.
++   * Gets the set of locales for which a Calendar is available.
+    * @exception MissingResourceException if locale data couldn't be found.
+    * @return the set of locales.
+    */
+@@ -682,7 +682,7 @@
+    * Compares the given calendar with this.  
+    * @param o the object to that we should compare.
+    * @return true, if the given object is a calendar, that represents
+-   * the same time (but doesn't neccessary have the same fields).
++   * the same time (but doesn't necessary have the same fields).
+    */
+   public boolean equals(Object o)
+   {
+@@ -892,7 +892,7 @@
+ 
+   /**
+    * Gets the actual minimum value that is allowed for the specified field.
+-   * This value is dependant on the values of the other fields.
++   * This value is dependent on the values of the other fields.
+    * @param field the time field. One of the time field constants.
+    * @return the actual minimum value.
+    * @since jdk1.2
+@@ -902,7 +902,7 @@
+ 
+   /**
+    * Gets the actual maximum value that is allowed for the specified field.
+-   * This value is dependant on the values of the other fields.
++   * This value is dependent on the values of the other fields.
+    * @param field the time field. One of the time field constants.
+    * @return the actual maximum value.  
+    * @since jdk1.2
Index: compare/java.util.Collections.diff
===================================================================
RCS file: java.util.Collections.diff
diff -N java.util.Collections.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Collections.diff Tue Nov 6 17:21:32 2001
@@ -0,0 +1,4679 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Collections.java	Fri Nov  2 09:28:56 2001
++++ java/util/Collections.java	Fri Nov  2 21:44:51 2001
+@@ -25,6 +25,10 @@
+ executable file might be covered by the GNU General Public License. */
+ 
+ 
++// TO DO:
++// ~ Serialization is very much broken. Blame Sun for not specifying it.
++// ~ The synchronized* and unmodifiable* methods don't have doc-comments.
++
+ package java.util;
+ 
+ import java.io.Serializable;
+@@ -36,54 +40,10 @@
+  * are unaware of collections, a method to return a list which consists of
+  * multiple copies of one element, and methods which "wrap" collections to give
+  * them extra properties, such as thread-safety and unmodifiability.
+- * <p>
+- *
+- * All methods which take a collection throw a {@link NullPointerException} if
+- * that collection is null. Algorithms which can change a collection may, but
+- * are not required, to throw the {@link UnsupportedOperationException} that
+- * the underlying collection would throw during an attempt at modification.
+- * For example,
+- * <code>Collections.singleton("").addAll(Collections.EMPTY_SET)<code>
+- * does not throw a exception, even though addAll is an unsupported operation
+- * on a singleton; the reason for this is that addAll did not attempt to
+- * modify the set.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see Set
+- * @see List
+- * @see Map
+- * @see Arrays
+- * @since 1.2
+- * @status updated to 1.4
+  */
+ public class Collections
+ {
+   /**
+-   * Constant used to decide cutoff for when a non-RandomAccess list should
+-   * be treated as sequential-access. Basically, quadratic behavior is
+-   * acceptible for small lists when the overhead is so small in the first
+-   * place. I arbitrarily set it to 16, so it may need some tuning.
+-   */
+-  private static final int LARGE_LIST_SIZE = 16;
+-
+-  /**
+-   * Determines if a list should be treated as a sequential-access one.
+-   * Rather than the old method of JDK 1.3 of assuming only instanceof
+-   * AbstractSequentialList should be sequential, this uses the new method
+-   * of JDK 1.4 of assuming anything that does NOT implement RandomAccess
+-   * and exceeds a large (unspecified) size should be sequential.
+-   *
+-   * @param l the list to check
+-   * @return true if it should be treated as sequential-access
+-   */
+-  private static boolean isSequential(List l)
+-  {
+-    return ! (l instanceof RandomAccess) && l.size() > LARGE_LIST_SIZE;
+-  }
+-
+-  /**
+    * This class is non-instantiable.
+    */
+   private Collections()
+@@ -91,513 +51,200 @@
+   }
+ 
+   /**
+-   * An immutable, serializable, empty Set.
+-   * @see Serializable
+-   */
+-  public static final Set EMPTY_SET = new EmptySet();
+-
+-  /**
+-   * The implementation of {@link #EMPTY_SET}. This class name is required
+-   * for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++   * An immutable, empty Set.
++   * Note: This implementation isn't Serializable, although it should be by the
++   * spec.
+    */
+-  private static final class EmptySet extends AbstractSet
+-    implements Serializable
++  public static final Set EMPTY_SET = new AbstractSet()
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 1582296315990362920L;
+-
+-    /**
+-     * A private constructor adds overhead.
+-     */
+-    EmptySet()
+-    {
+-    }
+-
+-    /**
+-     * The size: always 0!
+-     */
+     public int size()
+     {
+       return 0;
+     }
+ 
+-    /**
+-     * Returns an iterator that does not iterate.
+-     */
+-    // This is really cheating! I think it's perfectly valid, though.
++    // This is really cheating! I think it's perfectly valid, though - the
++    // more conventional code is here, commented out, in case anyone disagrees.
+     public Iterator iterator()
+     {
+       return EMPTY_LIST.iterator();
+     }
+ 
+-    // The remaining methods are optional, but provide a performance
+-    // advantage by not allocating unnecessary iterators in AbstractSet.
+-    /**
+-     * The empty set never contains anything.
+-     */
+-    public boolean contains(Object o)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * This is true only if the given collection is also empty.
+-     */
+-    public boolean containsAll(Collection c)
+-    {
+-      return c.isEmpty();
+-    }
+-
+-    /**
+-     * Equal only if the other set is empty.
+-     */
+-    public boolean equals(Object o)
+-    {
+-      return o instanceof Set && ((Set) o).isEmpty();
+-    }
+-
+-    /**
+-     * The hashcode is always 0.
+-     */
+-    public int hashCode()
+-    {
+-      return 0;
+-    }
+-
+-    /**
+-     * Always succeeds with false result.
+-     */
+-    public boolean remove(Object o)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * Always succeeds with false result.
+-     */
+-    public boolean removeAll(Collection c)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * Always succeeds with false result.
+-     */
+-    public boolean retainAll(Collection c)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * The array is always empty.
+-     */
+-    public Object[] toArray()
+-    {
+-      return new Object[0];
+-    }
+-
+-    /**
+-     * We don't even need to use reflection!
+-     */
+-    public Object[] toArray(Object[] a)
+-    {
+-      if (a.length > 0)
+-        a[0] = null;
+-      return a;
+-    }
+-
+-    /**
+-     * The string never changes.
+-     */
+-    public String toString()
+-    {
+-      return "[]";
+-    }
+-  } // class EmptySet
+-
+-  /**
+-   * An immutable, serializable, empty List, which implements RandomAccess.
+-   * @see Serializable
+-   * @see RandomAccess
+-   */
+-  public static final List EMPTY_LIST = new EmptyList();
+-
+-  /**
+-   * The implementation of {@link #EMPTY_LIST}. This class name is required
+-   * for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++    // public Iterator iterator() {
++    //   return new Iterator() {
++    // 
++    //     public boolean hasNext() {
++    //       return false;
++    //     }
++    // 
++    //     public Object next() {
++    //       throw new NoSuchElementException();
++    //     }
++    // 
++    //     public void remove() {
++    //       throw new UnsupportedOperationException();
++    //     }
++    //   };
++    // }
++
++  };
++
++  /**
++   * An immutable, empty List.
++   * Note: This implementation isn't serializable, although it should be by the
++   * spec.
+    */
+-  private static final class EmptyList extends AbstractList
+-    implements Serializable, RandomAccess
++  public static final List EMPTY_LIST = new AbstractList()
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 8842843931221139166L;
+-
+-    /**
+-     * A private constructor adds overhead.
+-     */
+-    EmptyList()
+-    {
+-    }
+-
+-    /**
+-     * The size is always 0.
+-     */
+     public int size()
+     {
+       return 0;
+     }
+ 
+-    /**
+-     * No matter the index, it is out of bounds.
+-     */
+     public Object get(int index)
+     {
+       throw new IndexOutOfBoundsException();
+     }
+-
+-    // The remaining methods are optional, but provide a performance
+-    // advantage by not allocating unnecessary iterators in AbstractList.
+-    /**
+-     * Never contains anything.
+-     */
+-    public boolean contains(Object o)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * This is true only if the given collection is also empty.
+-     */
+-    public boolean containsAll(Collection c)
+-    {
+-      return c.isEmpty();
+-    }
+-
+-    /**
+-     * Equal only if the other set is empty.
+-     */
+-    public boolean equals(Object o)
+-    {
+-      return o instanceof List && ((List) o).isEmpty();
+-    }
+-
+-    /**
+-     * The hashcode is always 1.
+-     */
+-    public int hashCode()
+-    {
+-      return 1;
+-    }
+-
+-    /**
+-     * Returns -1.
+-     */
+-    public int indexOf(Object o)
+-    {
+-      return -1;
+-    }
+-
+-    /**
+-     * Returns -1.
+-     */
+-    public int lastIndexOf(Object o)
+-    {
+-      return -1;
+-    }
+-
+-    /**
+-     * Always succeeds with false result.
+-     */
+-    public boolean remove(Object o)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * Always succeeds with false result.
+-     */
+-    public boolean removeAll(Collection c)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * Always succeeds with false result.
+-     */
+-    public boolean retainAll(Collection c)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * The array is always empty.
+-     */
+-    public Object[] toArray()
+-    {
+-      return new Object[0];
+-    }
+-
+-    /**
+-     * We don't even need to use reflection!
+-     */
+-    public Object[] toArray(Object[] a)
+-    {
+-      if (a.length > 0)
+-        a[0] = null;
+-      return a;
+-    }
+-
+-    /**
+-     * The string never changes.
+-     */
+-    public String toString()
+-    {
+-      return "[]";
+-    }
+-  } // class EmptyList
+-
+-  /**
+-   * An immutable, serializable, empty Map.
+-   * @see Serializable
+-   */
+-  public static final Map EMPTY_MAP = new EmptyMap();
++  };
+ 
+   /**
+-   * The implementation of {@link #EMPTY_MAP}. This class name is required
+-   * for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++   * An immutable, empty Map.
++   * Note: This implementation isn't serializable, although it should be by the
++   * spec.
+    */
+-  private static final class EmptyMap extends AbstractMap
+-    implements Serializable
++  public static final Map EMPTY_MAP = new AbstractMap()
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 6428348081105594320L;
+-
+-    /**
+-     * A private constructor adds overhead.
+-     */
+-    EmptyMap()
+-    {
+-    }
+-
+-    /**
+-     * There are no entries.
+-     */
+     public Set entrySet()
+     {
+       return EMPTY_SET;
+     }
++  };
+ 
+-    // The remaining methods are optional, but provide a performance
+-    // advantage by not allocating unnecessary iterators in AbstractMap.
+-    /**
+-     * No entries!
+-     */
+-    public boolean containsKey(Object key)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * No entries!
+-     */
+-    public boolean containsValue(Object value)
+-    {
+-      return false;
+-    }
+-
+-    /**
+-     * Equal to all empty maps.
+-     */
+-    public boolean equals(Object o)
+-    {
+-      return o instanceof Map && ((Map) o).isEmpty();
+-    }
+-
+-    /**
+-     * No mappings, so this returns null.
+-     */
+-    public Object get(Object o)
+-    {
+-      return null;
+-    }
+-
+-    /**
+-     * The hashcode is always 0.
+-     */
+-    public int hashCode()
+-    {
+-      return 0;
+-    }
+-
+-    /**
+-     * No entries.
+-     */
+-    public Set keySet()
+-    {
+-      return EMPTY_SET;
+-    }
+-
+-    /**
+-     * Remove always succeeds, with null result.
+-     */
+-    public Object remove(Object o)
+-    {
+-      return null;
+-    }
+-
+-    /**
+-     * Size is always 0.
+-     */
+-    public int size()
+-    {
+-      return 0;
+-    }
+-
+-    /**
+-     * No entries. Technically, EMPTY_SET, while more specific than a general
+-     * Collection, will work. Besides, that's what the JDK uses!
+-     */
+-    public Collection values()
+-    {
+-      return EMPTY_SET;
+-    }
+-
+-    /**
+-     * The string never changes.
+-     */
+-    public String toString()
+-    {
+-      return "[]";
+-    }
+-  } // class EmptyMap
+-
+-
+   /**
+    * Compare two objects with or without a Comparator. If c is null, uses the
+    * natural ordering. Slightly slower than doing it inline if the JVM isn't
+    * clever, but worth it for removing a duplicate of the search code.
+-   * Note: This code is also used in Arrays (for sort as well as search).
++   * Note: This same code is used in Arrays (for sort as well as search)
++   */
++  private static int compare(Object o1, Object o2, Comparator c)
++  {
++    if (c == null)
++      {
++	return ((Comparable) o1).compareTo(o2);
++      }
++    else
++      {
++	return c.compare(o1, o2);
++      }
++  }
++
++  /**
++   * The hard work for the search routines. If the Comparator given is null,
++   * uses the natural ordering of the elements.
+    */
+-  static final int compare(Object o1, Object o2, Comparator c)
++  private static int search(List l, Object key, final Comparator c)
+   {
+-    return c == null ? ((Comparable) o1).compareTo(o2) : c.compare(o1, o2);
++    int pos = 0;
++
++    // We use a linear search using an iterator if we can guess that the list
++    // is sequential-access.
++    if (l instanceof AbstractSequentialList)
++      {
++	ListIterator itr = l.listIterator();
++    	for (int i = l.size() - 1; i >= 0; --i)
++	  {
++	    final int d = compare(key, itr.next(), c);
++	    if (d == 0)
++	      {
++		return pos;
++	      }
++	    else if (d < 0)
++	      {
++		return -pos - 1;
++	      }
++	    pos++;
++	  }
++
++	// We assume the list is random-access, and use a binary search
++      }
++    else
++      {
++	int low = 0;
++	int hi = l.size() - 1;
++	while (low <= hi)
++	  {
++	    pos = (low + hi) >> 1;
++	    final int d = compare(key, l.get(pos), c);
++	    if (d == 0)
++	      {
++		return pos;
++	      }
++	    else if (d < 0)
++	      {
++		hi = pos - 1;
++	      }
++	    else
++	      {
++		low = ++pos;	// This gets the insertion point right on the last loop
++	      }
++	  }
++      }
++
++    // If we failed to find it, we do the same whichever search we did.
++    return -pos - 1;
+   }
+ 
+   /**
+    * Perform a binary search of a List for a key, using the natural ordering of
+    * the elements. The list must be sorted (as by the sort() method) - if it is
+-   * not, the behavior of this method is undefined, and may be an infinite
++   * not, the behaviour of this method is undefined, and may be an infinite
+    * loop. Further, the key must be comparable with every item in the list. If
+-   * the list contains the key more than once, any one of them may be found.
+-   * <p>
+-   *
+-   * This algorithm behaves in log(n) time for {@link RandomAccess} lists,
+-   * and uses a linear search with O(n) link traversals and log(n) comparisons
+-   * with {@link AbstractSequentialList} lists. Note: although the
++   * the list contains the key more than once, any one of them may be found. To
++   * avoid pathological behaviour on sequential-access lists, a linear search
++   * is used if (l instanceof AbstractSequentialList). Note: although the
+    * specification allows for an infinite loop if the list is unsorted, it will
+    * not happen in this (Classpath) implementation.
+    *
+    * @param l the list to search (must be sorted)
+    * @param key the value to search for
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value
+-   * @throws ClassCastException if key could not be compared with one of the
+-   *         elements of l
+-   * @throws NullPointerException if a null element has compareTo called
+-   * @see #sort(List)
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
++   * @exception ClassCastException if key could not be compared with one of the
++   *   elements of l
++   * @exception NullPointerException if a null element has compareTo called
+    */
+   public static int binarySearch(List l, Object key)
+   {
+-    return binarySearch(l, key, null);
++    return search(l, key, null);
+   }
+ 
+   /**
+    * Perform a binary search of a List for a key, using a supplied Comparator.
+    * The list must be sorted (as by the sort() method with the same Comparator)
+-   * - if it is not, the behavior of this method is undefined, and may be an
++   * - if it is not, the behaviour of this method is undefined, and may be an
+    * infinite loop. Further, the key must be comparable with every item in the
+    * list. If the list contains the key more than once, any one of them may be
+-   * found. If the comparator is null, the elements' natural ordering is used.
+-   * <p>
+-   *
+-   * This algorithm behaves in log(n) time for {@link RandomAccess} lists,
+-   * and uses a linear search with O(n) link traversals and log(n) comparisons
+-   * with {@link AbstractSequentialList} lists. Note: although the
+-   * specification allows for an infinite loop if the list is unsorted, it will
+-   * not happen in this (Classpath) implementation.
++   * found. To avoid pathological behaviour on sequential-access lists, a
++   * linear search is used if (l instanceof AbstractSequentialList). Note:
++   * although the specification allows for an infinite loop if the list is
++   * unsorted, it will not happen in this (Classpath) implementation.
+    *
+    * @param l the list to search (must be sorted)
+    * @param key the value to search for
+    * @param c the comparator by which the list is sorted
+-   * @return the index at which the key was found, or -n-1 if it was not
+-   *         found, where n is the index of the first value higher than key or
+-   *         a.length if there is no such value
+-   * @throws ClassCastException if key could not be compared with one of the
+-   *         elements of l
+-   * @throws NullPointerException if a null element is compared with natural
+-   *         ordering (only possible when c is null)
+-   * @see #sort(List, Comparator)
++   * @returns the index at which the key was found, or -n-1 if it was not
++   *   found, where n is the index of the first value higher than key or
++   *   a.length if there is no such value.
++   * @exception ClassCastException if key could not be compared with one of the
++   *   elements of l
+    */
+   public static int binarySearch(List l, Object key, Comparator c)
+   {
+-    int pos = 0;
+-    int low = 0;
+-    int hi = l.size() - 1;
+-
+-    // We use a linear search with log(n) comparisons using an iterator
+-    // if the list is sequential-access.
+-    if (isSequential(l))
+-      {
+-	ListIterator itr = l.listIterator();
+-        int i = 0;
+-        while (low <= hi)
+-          {
+-            pos = (low + hi) >> 1;
+-            if (i < pos)
+-              for ( ; i != pos; i++, itr.next());
+-            else
+-              for ( ; i != pos; i--, itr.previous());
+-	    final int d = compare(key, itr.next(), c);
+-	    if (d == 0)
+-              return pos;
+-	    else if (d < 0)
+-              hi = pos - 1;
+-	    else
+-              // This gets the insertion point right on the last loop
+-              low = ++pos;
+-          }
+-      }
+-    else
++    if (c == null)
+       {
+-	while (low <= hi)
+-	  {
+-	    pos = (low + hi) >> 1;
+-	    final int d = compare(key, l.get(pos), c);
+-	    if (d == 0)
+-              return pos;
+-	    else if (d < 0)
+-              hi = pos - 1;
+-	    else
+-              // This gets the insertion point right on the last loop
+-              low = ++pos;
+-	  }
++	throw new NullPointerException();
+       }
+-
+-    // If we failed to find it, we do the same whichever search we did.
+-    return -pos - 1;
++    return search(l, key, c);
+   }
+ 
+   /**
+@@ -605,26 +252,30 @@
+    * source list, the remaining elements are unaffected. This method runs in
+    * linear time.
+    *
+-   * @param dest the destination list
+-   * @param source the source list
+-   * @throws IndexOutOfBoundsException if the destination list is shorter
+-   *         than the source list (the destination will be unmodified)
+-   * @throws UnsupportedOperationException if dest.listIterator() does not
+-   *         support the set operation
++   * @param dest the destination list.
++   * @param source the source list.
++   * @exception IndexOutOfBoundsException if the destination list is shorter
++   *   than the source list (the elements that can be copied will be, prior to
++   *   the exception being thrown).
++   * @exception UnsupportedOperationException if dest.listIterator() does not
++   *   support the set operation.
+    */
+   public static void copy(List dest, List source)
+   {
+-    int pos = source.size();
+-    if (dest.size() < pos)
+-      throw new IndexOutOfBoundsException("Source does not fit in dest");
+-
+     Iterator i1 = source.iterator();
+     ListIterator i2 = dest.listIterator();
+ 
+-    while (--pos >= 0)
++    try
++      {
++	for (int i = source.size() - 1; i >= 0; --i)
++	  {
++	    i2.next();
++	    i2.set(i1.next());
++	  }
++      }
++    catch (NoSuchElementException x)
+       {
+-        i2.next();
+-        i2.set(i1.next());
++	throw new IndexOutOfBoundsException("Source doesn't fit in dest.");      
+       }
+   }
+ 
+@@ -633,7 +284,7 @@
+    * with legacy APIs that require an Enumeration as input.
+    *
+    * @param c the Collection to iterate over
+-   * @return an Enumeration backed by an Iterator over c
++   * @returns an Enumeration backed by an Iterator over c
+    */
+   public static Enumeration enumeration(Collection c)
+   {
+@@ -657,8 +308,8 @@
+    *
+    * @param l the list to fill.
+    * @param val the object to vill the list with.
+-   * @throws UnsupportedOperationException if l.listIterator() does not
+-   *         support the set operation.
++   * @exception UnsupportedOperationException if l.listIterator() does not
++   *   support the set operation.
+    */
+   public static void fill(List l, Object val)
+   {
+@@ -671,81 +322,30 @@
+   }
+ 
+   /**
+-   * Returns the starting index where the specified sublist first occurs
+-   * in a larger list, or -1 if there is no matching position. If
+-   * <code>target.size() &gt; source.size()</code>, this returns -1,
+-   * otherwise this implementation uses brute force, checking for
+-   * <code>source.sublist(i, i + target.size()).equals(target)</code>
+-   * for all possible i.
+-   *
+-   * @param source the list to search
+-   * @param target the sublist to search for
+-   * @return the index where found, or -1
+-   * @since 1.4
+-   */
+-  public static int indexOfSubList(List source, List target)
+-  {
+-    int ssize = source.size();
+-    for (int i = 0, j = target.size(); j <= ssize; i++, j++)
+-      if (source.subList(i, j).equals(target))
+-        return i;
+-    return -1;
+-  }
+-
+-  /**
+-   * Returns the starting index where the specified sublist last occurs
+-   * in a larger list, or -1 if there is no matching position. If
+-   * <code>target.size() &gt; source.size()</code>, this returns -1,
+-   * otherwise this implementation uses brute force, checking for
+-   * <code>source.sublist(i, i + target.size()).equals(target)</code>
+-   * for all possible i.
+-   *
+-   * @param source the list to search
+-   * @param target the sublist to search for
+-   * @return the index where found, or -1
+-   * @since 1.4
+-   */
+-  public static int lastIndexOfSubList(List source, List target)
+-  {
+-    int ssize = source.size();
+-    for (int i = ssize - target.size(), j = ssize; i >= 0; i--, j--)
+-      if (source.subList(i, j).equals(target))
+-        return i;
+-    return -1;
+-  }
+-
+-  /**
+-   * Returns an array list holding the elements visited by a given
+-   * Enumeration. This method exists for interoperability between legacy
+-   * APIs and the new Collection API.
+-   *
+-   * @param e the enumeration to put in a list
+-   * @return a list containing the enumeration elements
+-   * @see ArrayList
+-   * @since 1.4
+-   */
+-  public static List list(Enumeration e)
+-  {
+-    List l = new ArrayList();
+-    while (e.hasMoreElements())
+-      l.add(e.nextElement());
+-    return l;
+-  }
+-
+-  /**
+    * Find the maximum element in a Collection, according to the natural
+    * ordering of the elements. This implementation iterates over the
+    * Collection, so it works in linear time.
+    *
+    * @param c the Collection to find the maximum element of
+-   * @return the maximum element of c
++   * @returns the maximum element of c
+    * @exception NoSuchElementException if c is empty
+    * @exception ClassCastException if elements in c are not mutually comparable
+    * @exception NullPointerException if null.compareTo is called
+    */
+   public static Object max(Collection c)
+   {
+-    return max(c, null);
++    Iterator itr = c.iterator();
++    Comparable max = (Comparable) itr.next();	// throws NoSuchElementException
++    int csize = c.size();
++    for (int i = 1; i < csize; i++)
++      {
++	Object o = itr.next();
++	if (max.compareTo(o) < 0)
++	  {
++	    max = (Comparable) o;
++	  }
++      }
++    return max;
+   }
+ 
+   /**
+@@ -754,23 +354,20 @@
+    * works in linear time.
+    *
+    * @param c the Collection to find the maximum element of
+-   * @param order the Comparator to order the elements by, or null for natural
+-   *        ordering
+-   * @return the maximum element of c
+-   * @throws NoSuchElementException if c is empty
+-   * @throws ClassCastException if elements in c are not mutually comparable
+-   * @throws NullPointerException if null is compared by natural ordering
+-   *        (only possible when order is null)
++   * @param order the Comparator to order the elements by
++   * @returns the maximum element of c
++   * @exception NoSuchElementException if c is empty
++   * @exception ClassCastException if elements in c are not mutually comparable
+    */
+   public static Object max(Collection c, Comparator order)
+   {
+     Iterator itr = c.iterator();
+-    Object max = itr.next(); // throws NoSuchElementException
++    Object max = itr.next();	// throws NoSuchElementException
+     int csize = c.size();
+     for (int i = 1; i < csize; i++)
+       {
+ 	Object o = itr.next();
+-	if (compare(max, o, order) < 0)
++	if (order.compare(max, o) < 0)
+ 	  max = o;
+       }
+     return max;
+@@ -782,14 +379,23 @@
+    * Collection, so it works in linear time.
+    *
+    * @param c the Collection to find the minimum element of
+-   * @return the minimum element of c
+-   * @throws NoSuchElementException if c is empty
+-   * @throws ClassCastException if elements in c are not mutually comparable
+-   * @throws NullPointerException if null.compareTo is called
++   * @returns the minimum element of c
++   * @exception NoSuchElementException if c is empty
++   * @exception ClassCastException if elements in c are not mutually comparable
++   * @exception NullPointerException if null.compareTo is called
+    */
+   public static Object min(Collection c)
+   {
+-    return min(c, null);
++    Iterator itr = c.iterator();
++    Comparable min = (Comparable) itr.next();	// throws NoSuchElementException
++    int csize = c.size();
++    for (int i = 1; i < csize; i++)
++      {
++	Object o = itr.next();
++	if (min.compareTo(o) > 0)
++	  min = (Comparable) o;
++      }
++    return min;
+   }
+ 
+   /**
+@@ -798,13 +404,10 @@
+    * works in linear time.
+    *
+    * @param c the Collection to find the minimum element of
+-   * @param order the Comparator to order the elements by, or null for natural
+-   *        ordering
+-   * @return the minimum element of c
+-   * @throws NoSuchElementException if c is empty
+-   * @throws ClassCastException if elements in c are not mutually comparable
+-   * @throws NullPointerException if null is compared by natural ordering
+-   *        (only possible when order is null)
++   * @param order the Comparator to order the elements by
++   * @returns the minimum element of c
++   * @exception NoSuchElementException if c is empty
++   * @exception ClassCastException if elements in c are not mutually comparable
+    */
+   public static Object min(Collection c, Comparator order)
+   {
+@@ -814,7 +417,7 @@
+     for (int i = 1; i < csize; i++)
+       {
+ 	Object o = itr.next();
+-	if (compare(min, o, order) > 0)
++	if (order.compare(min, o) > 0)
+ 	  min = o;
+       }
+     return min;
+@@ -823,182 +426,54 @@
+   /**
+    * Creates an immutable list consisting of the same object repeated n times.
+    * The returned object is tiny, consisting of only a single reference to the
+-   * object and a count of the number of elements. It is Serializable, and
+-   * implements RandomAccess. You can use it in tandem with List.addAll for
+-   * fast list construction.
++   * object and a count of the number of elements. It is Serializable.
+    *
+    * @param n the number of times to repeat the object
+    * @param o the object to repeat
+-   * @return a List consisting of n copies of o
+-   * @throws IllegalArgumentException if n &lt; 0
+-   * @see List#addAll(Collection)
+-   * @see Serializable
+-   * @see RandomAccess
++   * @returns a List consisting of n copies of o
++   * @throws IllegalArgumentException if n < 0
+    */
++  // It's not Serializable, because the serialized form is unspecced.
++  // Also I'm only assuming that it should be because I don't think it's
++  // stated - I just would be amazed if it isn't...
+   public static List nCopies(final int n, final Object o)
+   {
+-    return new CopiesList(n, o);
+-  }
+-
+-  /**
+-   * The implementation of {@link #nCopies(int, Object)}. This class name
+-   * is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static final class CopiesList extends AbstractList
+-    implements Serializable, RandomAccess
+-  {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 2739099268398711800L;
+-
+-    /**
+-     * The count of elements in this list.
+-     * @serial the list size
+-     */
+-    private final int n;
+-
+-    /**
+-     * The repeated list element.
+-     * @serial the list contents
+-     */
+-    private final Object element;
+-
+-    /**
+-     * Constructs the list.
+-     *
+-     * @param n the count
+-     * @param o the object
+-     * @throws IllegalArgumentException if n &lt; 0
+-     */
+-    CopiesList(int n, Object o)
+-    {
+-      if (n < 0)
++    // Check for insane arguments
++    if (n < 0)
++      {
+ 	throw new IllegalArgumentException();
+-      this.n = n;
+-      element = o;
+-    }
+-
+-    /**
+-     * The size is fixed.
+-     */
+-    public int size()
+-    {
+-      return n;
+-    }
+-
+-    /**
+-     * The same element is returned.
+-     */
+-    public Object get(int index)
+-    {
+-      if (index < 0 || index >= n)
+-        throw new IndexOutOfBoundsException();
+-      return element;
+-    }
+-
+-    // The remaining methods are optional, but provide a performance
+-    // advantage by not allocating unnecessary iterators in AbstractList.
+-    /**
+-     * This list only contains one element.
+-     */
+-    public boolean contains(Object o)
+-    {
+-      return n > 0 && equals(o, element);
+-    }
+-
+-    /**
+-     * The index is either 0 or -1.
+-     */
+-    public int indexOf(Object o)
+-    {
+-      return (n > 0 && equals(o, element)) ? 0 : -1;
+-    }
+-
+-    /**
+-     * The index is either n-1 or -1.
+-     */
+-    public int lastIndexOf(Object o)
+-    {
+-      return equals(o, element) ? n - 1 : -1;
+-    }
+-
+-    /**
+-     * A subList is just another CopiesList.
+-     */
+-    public List subList(int from, int to)
+-    {
+-      if (from < 0 || to > n)
+-        throw new IndexOutOfBoundsException();
+-      return new CopiesList(to - from, element);
+-    }
+-
+-    /**
+-     * The array is easy.
+-     */
+-    public Object[] toArray()
+-    {
+-      Object[] a = new Object[n];
+-      Arrays.fill(a, element);
+-      return a;
+-    }
++      }
+ 
+-    /**
+-     * The string is easy to generate.
+-     */
+-    public String toString()
++    // Create a minimal implementation of List
++    return new AbstractList()
+     {
+-      StringBuffer r = new StringBuffer("{");
+-      for (int i = n - 1; --i > 0; )
+-        r.append(element).append(", ");
+-      r.append(element).append("}");
+-      return r.toString();
+-    }
+-  } // class CopiesList
++      public int size()
++      {
++	return n;
++      }
+ 
+-  /**
+-   * Replace all instances of one object with another in the specified list.
+-   * The list does not change size. An element e is replaced if
+-   * <code>oldval == null ? e == null : oldval.equals(e)</code>.
+-   *
+-   * @param list the list to iterate over
+-   * @param oldval the element to replace
+-   * @param newval the new value for the element
+-   * @return true if a replacement occurred
+-   * @throws UnsupportedOperationException if the list iterator does not allow
+-   *         for the set operation
+-   * @throws ClassCastException newval is of a type which cannot be added
+-   *         to the list
+-   * @throws IllegalArgumentException some other aspect of newval stops
+-   *         it being added to the list
+-   * @since 1.4
+-   */
+-  public static boolean replaceAll(List list, Object oldval, Object newval)
+-  {
+-    ListIterator itr = list.listIterator();
+-    boolean replace_occured = false;
+-    for (int i = list.size(); --i >= 0; )
+-      if (AbstractCollection.equals(oldval, itr.next()))
+-        {
+-          itr.set(newval);
+-          replace_occured = true;
+-        }
+-    return replace_occured;
++      public Object get(int index)
++      {
++	if (index < 0 || index >= n)
++	  {
++	    throw new IndexOutOfBoundsException();
++	  }
++	return o;
++      }
++    };
+   }
+ 
+   /**
+    * Reverse a given list. This method works in linear time.
+    *
+-   * @param l the list to reverse
+-   * @throws UnsupportedOperationException if l.listIterator() does not
+-   *         support the set operation
++   * @param l the list to reverse.
++   * @exception UnsupportedOperationException if l.listIterator() does not
++   *   support the set operation.
+    */
+   public static void reverse(List l)
+   {
+     ListIterator i1 = l.listIterator();
+-    int pos1 = 1;
++    int pos1 = 0;
+     int pos2 = l.size();
+     ListIterator i2 = l.listIterator(pos2);
+     while (pos1 < pos2)
+@@ -1011,152 +486,42 @@
+       }
+   }
+ 
+-  /**
+-   * Get a comparator that implements the reverse of natural ordering. In
+-   * other words, this sorts Comparable objects opposite of how their
+-   * compareTo method would sort. This makes it easy to sort into reverse
+-   * order, by simply passing Collections.reverseOrder() to the sort method.
+-   * The return value of this method is Serializable.
+-   *
+-   * @return a comparator that imposes reverse natural ordering
+-   * @see Comparable
+-   * @see Serializable
+-   */
+-  public static Comparator reverseOrder()
+-  {
+-    return rcInstance;
+-  }
+-
+-  /**
+-   * The object for {@link #reverseOrder()}.
+-   */
+-  static private final ReverseComparator rcInstance = new ReverseComparator();
+-
+-  /**
+-   * The implementation of {@link #reverseOrder()}. This class name
+-   * is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static final class ReverseComparator
+-    implements Comparator, Serializable
++  static class ReverseComparator implements Comparator, Serializable
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    static private final long serialVersionUID = 7207038068494060240L;
+-
+-    /**
+-     * A private constructor adds overhead.
+-     */
+-    ReverseComparator()
+-    {
+-    }
+-
+-    /**
+-     * Compare two objects in reverse natural order.
+-     *
+-     * @param a the first object
+-     * @param b the second object
+-     * @return &lt;, ==, or &gt; 0 according to b.compareTo(a)
+-     */
+     public int compare(Object a, Object b)
+     {
+-      return ((Comparable) b).compareTo(a);
++      return -((Comparable) a).compareTo(b);
+     }
+   }
+-
++  
++  static ReverseComparator rcInstance = new ReverseComparator();
++  
+   /**
+-   * Rotate the elements in a list by a specified distance. After calling this
+-   * method, the element now at index <code>i</code> was formerly at index
+-   * <code>(i - distance) mod list.size()</code>. The list size is unchanged.
+-   * <p>
+-   *
+-   * For example, suppose a list contains <code>[t, a, n, k, s]</code>. After
+-   * either <code>Collections.rotate(l, 4)</code> or
+-   * <code>Collections.rotate(l, -1)</code>, the new contents are
+-   * <code>[s, t, a, n, k]</code>. This can be applied to sublists to rotate
+-   * just a portion of the list. For example, to move element <code>a</code>
+-   * forward two positions in the original example, use
+-   * <code>Collections.rotate(l.subList(1, 3+1), -1)</code>, which will
+-   * result in <code>[t, n, k, a, s]</code>.
+-   * <p>
+-   *
+-   * If the list is small or implements {@link RandomAccess}, the
+-   * implementation exchanges the first element to its destination, then the
+-   * displaced element, and so on until a circuit has been completed. The
+-   * process is repeated if needed on the second element, and so forth, until
+-   * all elements have been swapped.  For large non-random lists, the
+-   * implementation breaks the list into two sublists at index
+-   * <code>-distance mod size</code>, calls {@link #reverse(List)} on the
+-   * pieces, then reverses the overall list.
+-   *
+-   * @param list the list to rotate
+-   * @param distance the distance to rotate by; unrestricted in value
+-   * @throws UnsupportedOperationException if the list does not support set
+-   * @since 1.4
+-   */
+-  public static void rotate(List list, int distance)
+-  {
+-    int size = list.size();
+-    distance %= size;
+-    if (distance == 0)
+-      return;
+-    if (distance < 0)
+-      distance += size;
+-
+-    if (isSequential(list))
+-      {
+-        reverse(list);
+-        reverse(list.subList(0, distance));
+-        reverse(list.subList(distance, size));
+-      }
+-    else
+-      {
+-        // Determine the least common multiple of distance and size, as there
+-        // are (distance / LCM) loops to cycle through.
+-        int a = size;
+-        int lcm = distance;
+-        int b = a % lcm;
+-        while (b != 0)
+-          {
+-            a = lcm;
+-            lcm = b;
+-            b = a % lcm;
+-          }
+-
+-        // Now, make the swaps. We must take the remainder every time through
+-        // the inner loop so that we don't overflow i to negative values.
+-        while (--lcm >= 0)
+-          {
+-            Object o = list.get(lcm);
+-            for (int i = lcm + distance; i != lcm; i = (i + distance) % size)
+-              o = list.set(i, o);
+-            list.set(lcm, o);
+-          }
+-      }
++   * Get a comparator that implements the reverse of natural ordering. This is
++   * intended to make it easy to sort into reverse order, by simply passing
++   * Collections.reverseOrder() to the sort method. The return value of this
++   * method is Serializable.
++   */
++  public static Comparator reverseOrder()
++  {
++    return rcInstance;
+   }
+ 
+   /**
+    * Shuffle a list according to a default source of randomness. The algorithm
+-   * used iterates backwards over the list, swapping each element with an
+-   * element randomly selected from the elements in positions less than or
+-   * equal to it (using r.nextInt(int)).
+-   * <p>
+-   *
+-   * This algorithm would result in a perfectly fair shuffle (that is, each
+-   * element would have an equal chance of ending up in any position) if r were
+-   * a perfect source of randomness. In practice the results are merely very
+-   * close to perfect.
++   * used would result in a perfectly fair shuffle (that is, each element would
++   * have an equal chance of ending up in any position) with a perfect source
++   * of randomness; in practice the results are merely very close to perfect.
+    * <p>
+-   *
+-   * This method operates in linear time. To do this on large lists which do
+-   * not implement {@link RandomAccess}, a temporary array is used to acheive
+-   * this speed, since it would be quadratic access otherwise.
+-   *
+-   * @param l the list to shuffle
+-   * @throws UnsupportedOperationException if l.listIterator() does not
+-   *         support the set operation
++   * This method operates in linear time on a random-access list, but may take
++   * quadratic time on a sequential-access list.
++   * Note: this (classpath) implementation will never take quadratic time, but
++   * it does make a copy of the list. This is in line with the behaviour of the
++   * sort methods and seems preferable.
++   *
++   * @param l the list to shuffle.
++   * @exception UnsupportedOperationException if l.listIterator() does not
++   *   support the set operation.
+    */
+   public static void shuffle(List l)
+   {
+@@ -1171,12 +536,11 @@
+     shuffle(l, defaultRandom);
+   }
+ 
+-  /**
+-   * Cache a single Random object for use by shuffle(List). This improves
+-   * performance as well as ensuring that sequential calls to shuffle() will
+-   * not result in the same shuffle order occurring: the resolution of
+-   * System.currentTimeMillis() is not sufficient to guarantee a unique seed.
+-   */
++  /** Cache a single Random object for use by shuffle(List). This improves
++    * performance as well as ensuring that sequential calls to shuffle() will
++    * not result in the same shuffle order occurring: the resolution of 
++    * System.currentTimeMillis() is not sufficient to guarantee a unique seed.
++    */
+   private static Random defaultRandom = null;
+ 
+   /**
+@@ -1185,468 +549,147 @@
+    * element randomly selected from the elements in positions less than or
+    * equal to it (using r.nextInt(int)).
+    * <p>
+-   *
+    * This algorithm would result in a perfectly fair shuffle (that is, each
+    * element would have an equal chance of ending up in any position) if r were
+    * a perfect source of randomness. In practise (eg if r = new Random()) the
+    * results are merely very close to perfect.
+    * <p>
+-   *
+-   * This method operates in linear time. To do this on large lists which do
+-   * not implement {@link RandomAccess}, a temporary array is used to acheive
+-   * this speed, since it would be quadratic access otherwise.
+-   *
+-   * @param l the list to shuffle
+-   * @param r the source of randomness to use for the shuffle
+-   * @throws UnsupportedOperationException if l.listIterator() does not
+-   *         support the set operation
++   * This method operates in linear time on a random-access list, but may take
++   * quadratic time on a sequential-access list.
++   * Note: this (classpath) implementation will never take quadratic time, but
++   * it does make a copy of the list. This is in line with the behaviour of the
++   * sort methods and seems preferable.
++   *
++   * @param l the list to shuffle.
++   * @param r the source of randomness to use for the shuffle.
++   * @exception UnsupportedOperationException if l.listIterator() does not
++   *   support the set operation.
+    */
+   public static void shuffle(List l, Random r)
+   {
++    Object[] a = l.toArray();	// Dump l into an array
+     int lsize = l.size();
+     ListIterator i = l.listIterator(lsize);
+-    boolean sequential = isSequential(l);
+-    Object[] a = null; // stores a copy of the list for the sequential case
+-
+-    if (sequential)
+-      a = l.toArray();
+ 
+-    for (int pos = lsize - 1; pos > 0; --pos)
++    // Iterate backwards over l
++    for (int pos = lsize - 1; pos >= 0; --pos)
+       {
+ 	// Obtain a random position to swap with. pos + 1 is used so that the
+ 	// range of the random number includes the current position.
+ 	int swap = r.nextInt(pos + 1);
+ 
+-	// Swap the desired element.
+-	Object o;
+-        if (sequential)
+-          {
+-            o = a[swap];
+-            a[swap] = i.previous();
+-          }
+-        else
+-          o = l.set(swap, i.previous());
++	// Swap the swapth element of the array with the next element of the
++	// list.
++	Object o = a[swap];
++	a[swap] = a[pos];
++	a[pos] = o;
+ 
++	// Set the element in the original list accordingly.
++	i.previous();
+ 	i.set(o);
+       }
+   }
+ 
+-
+   /**
+    * Obtain an immutable Set consisting of a single element. The return value
+    * of this method is Serializable.
+    *
+-   * @param o the single element
+-   * @return an immutable Set containing only o
+-   * @see Serializable
+-   */
+-  public static Set singleton(Object o)
+-  {
+-    return new SingletonSet(o);
+-  }
+-
+-  /**
+-   * The implementation of {@link #singleton(Object)}. This class name
+-   * is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++   * @param o the single element.
++   * @return an immutable Set containing only o.
+    */
+-  private static final class SingletonSet extends AbstractSet
+-    implements Serializable
++  // It's not serializable because the spec is broken.
++  public static Set singleton(final Object o)
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 3193687207550431679L;
+-
+-
+-    /**
+-     * The single element; package visible for use in nested class.
+-     * @serial the singleton
+-     */
+-    final Object element;
+-
+-    /**
+-     * Construct a singleton.
+-     * @param o the element
+-     */
+-    SingletonSet(Object o)
+-    {
+-      element = o;
+-    }
+-
+-    /**
+-     * The size: always 1!
+-     */
+-    public int size()
++    return new AbstractSet()
+     {
+-      return 1;
+-    }
+-
+-    /**
+-     * Returns an iterator over the lone element.
+-     */
+-    public Iterator iterator()
+-    {
+-      return new Iterator()
++      public int size()
+       {
+-        private boolean hasNext = true;
+-
+-        public boolean hasNext()
+-        {
+-          return hasNext;
+-        }
+-
+-        public Object next()
+-        {
+-          if (hasNext)
+-          {
+-            hasNext = false;
+-            return element;
+-          }
+-          else
+-            throw new NoSuchElementException();
+-        }
+-
+-        public void remove()
+-        {
+-          throw new UnsupportedOperationException();
+-        }
+-      };
+-    }
+-
+-    // The remaining methods are optional, but provide a performance
+-    // advantage by not allocating unnecessary iterators in AbstractSet.
+-    /**
+-     * The set only contains one element.
+-     */
+-    public boolean contains(Object o)
+-    {
+-      return equals(o, element);
+-    }
+-
+-    /**
+-     * This is true if the other collection only contains the element.
+-     */
+-    public boolean containsAll(Collection c)
+-    {
+-      Iterator i = c.iterator();
+-      int pos = c.size();
+-      while (--pos >= 0)
+-        if (! equals(i.next(), element))
+-          return false;
+-      return true;
+-    }
++	return 1;
++      }
+ 
+-    /**
+-     * The hash is just that of the element.
+-     */
+-    public int hashCode()
+-    {
+-      return hashCode(element);
+-    }
++      public Iterator iterator()
++      {
++	return new Iterator()
++	{
++	  private boolean hasNext = true;
+ 
+-    /**
+-     * Returning an array is simple.
+-     */
+-    public Object[] toArray()
+-    {
+-      return new Object[] {element};
+-    }
++	  public boolean hasNext()
++	  {
++	    return hasNext;
++	  }
+ 
+-    /**
+-     * Obvious string.
+-     */
+-    public String toString()
+-    {
+-      return "[" + element + "]";
+-    }
+-  } // class SingletonSet
++	  public Object next()
++	  {
++	    if (hasNext)
++	      {
++		hasNext = false;
++		return o;
++	      }
++	    else
++	      {
++		throw new NoSuchElementException();
++	      }
++	  }
+ 
+-  /**
+-   * Obtain an immutable List consisting of a single element. The return value
+-   * of this method is Serializable, and implements RandomAccess.
+-   *
+-   * @param o the single element
+-   * @return an immutable List containing only o
+-   * @see Serializable
+-   * @see RandomAccess
+-   * @since 1.3
+-   */
+-  public static List singletonList(Object o)
+-  {
+-    return new SingletonList(o);
++	  public void remove()
++	  {
++	    throw new UnsupportedOperationException();
++	  }
++	};
++      }
++    };
+   }
+ 
+   /**
+-   * The implementation of {@link #singletonList(Object)}. This class name
+-   * is required for compatibility with Sun's JDK serializability.
++   * Obtain an immutable List consisting of a single element. The return value
++   * of this method is Serializable.
+    *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++   * @param o the single element.
++   * @return an immutable List containing only o.
+    */
+-  private static final class SingletonList extends AbstractList
+-    implements Serializable, RandomAccess
++  // It's not serializable because the spec is broken.
++  public static List singletonList(final Object o)
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 3093736618740652951L;
+-
+-    /**
+-     * The single element.
+-     * @serial the singleton
+-     */
+-    private final Object element;
+-
+-    /**
+-     * Construct a singleton.
+-     * @param o the element
+-     */
+-    SingletonList(Object o)
+-    {
+-      element = o;
+-    }
+-
+-    /**
+-     * The size: always 1!
+-     */
+-    public int size()
+-    {
+-      return 1;
+-    }
+-
+-    /**
+-     * Only index 0 is valid.
+-     */
+-    public Object get(int index)
+-    {
+-      if (index == 0)
+-        return element;
+-      throw new IndexOutOfBoundsException();
+-    }
+-
+-    // The remaining methods are optional, but provide a performance
+-    // advantage by not allocating unnecessary iterators in AbstractList.
+-    /**
+-     * The set only contains one element.
+-     */
+-    public boolean contains(Object o)
+-    {
+-      return equals(o, element);
+-    }
+-
+-    /**
+-     * This is true if the other collection only contains the element.
+-     */
+-    public boolean containsAll(Collection c)
+-    {
+-      Iterator i = c.iterator();
+-      int pos = c.size();
+-      while (--pos >= 0)
+-        if (! equals(i.next(), element))
+-          return false;
+-      return true;
+-    }
+-
+-    /**
+-     * Speed up the hashcode computation.
+-     */
+-    public int hashCode()
+-    {
+-      return 31 + hashCode(element);
+-    }
+-
+-    /**
+-     * Either the list has it or not.
+-     */
+-    public int indexOf(Object o)
+-    {
+-      return equals(o, element) ? 0 : -1;
+-    }
+-
+-    /**
+-     * Either the list has it or not.
+-     */
+-    public int lastIndexOf(Object o)
+-    {
+-      return equals(o, element) ? 0 : -1;
+-    }
+-
+-    /**
+-     * Sublists are limited in scope.
+-     */
+-    public List subList(int from, int to)
+-    {
+-      if (from == to && (to == 0 || to == 1))
+-        return EMPTY_LIST;
+-      if (from == 0 && to == 1)
+-        return this;
+-      if (from > to)
+-        throw new IllegalArgumentException();
+-      throw new IndexOutOfBoundsException();
+-    }
+-
+-    /**
+-     * Returning an array is simple.
+-     */
+-    public Object[] toArray()
+-    {
+-      return new Object[] {element};
+-    }
+-
+-    /**
+-     * Obvious string.
+-     */
+-    public String toString()
++    return new AbstractList()
+     {
+-      return "[" + element + "]";
+-    }
+-  } // class SingletonList
++      public int size()
++      {
++	return 1;
++      }
+ 
+-  /**
+-   * Obtain an immutable Map consisting of a single key-value pair.
+-   * The return value of this method is Serializable.
+-   *
+-   * @param key the single key
+-   * @param value the single value
+-   * @return an immutable Map containing only the single key-value pair
+-   * @see Serializable
+-   * @since 1.3
+-   */
+-  public static Map singletonMap(Object key, Object value)
+-  {
+-    return new SingletonMap(key, value);
++      public Object get(int index)
++      {
++	if (index == 0)
++	  {
++	    throw new IndexOutOfBoundsException();
++	  }
++	else
++	  {
++	    return o;
++	  }
++      }
++    };
+   }
+ 
+   /**
+-   * The implementation of {@link #singletonMap(Object)}. This class name
+-   * is required for compatibility with Sun's JDK serializability.
++   * Obtain an immutable Map consisting of a single key value pair.
++   * The return value of this method is Serializable.
+    *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++   * @param key the single key.
++   * @param value the single value.
++   * @return an immutable Map containing only the single key value pair.
+    */
+-  private static final class SingletonMap extends AbstractMap
+-    implements Serializable
++  // It's not serializable because the spec is broken.
++  public static Map singletonMap(final Object key, final Object value)
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -6979724477215052911L;
+-
+-    /**
+-     * The single key.
+-     * @serial the singleton key
+-     */
+-    private final Object k;
+-
+-    /**
+-     * The corresponding value.
+-     * @serial the singleton value
+-     */
+-    private final Object v;
+-
+-    /**
+-     * Cache the entry set.
+-     */
+-    private transient Set entries;
+-
+-    /**
+-     * Construct a singleton.
+-     * @param key the key
+-     * @param value the value
+-     */
+-    SingletonMap(Object key, Object value)
+-    {
+-      k = key;
+-      v = value;
+-    }
+-
+-    /**
+-     * There is a single immutable entry.
+-     */
+-    public Set entrySet()
+-    {
+-      if (entries == null)
+-        entries = singleton(new BasicMapEntry(k, v)
+-        {
+-          public Object setValue(Object o)
+-          {
+-            throw new UnsupportedOperationException();
+-          }
+-        });
+-      return entries;
+-    }
+-
+-    // The remaining methods are optional, but provide a performance
+-    // advantage by not allocating unnecessary iterators in AbstractMap.
+-    /**
+-     * Single entry.
+-     */
+-    public boolean containsKey(Object key)
+-    {
+-      return equals(key, k);
+-    }
+-
+-    /**
+-     * Single entry.
+-     */
+-    public boolean containsValue(Object value)
+-    {
+-      return equals(value, v);
+-    }
+-
+-    /**
+-     * Single entry.
+-     */
+-    public Object get(Object key)
+-    {
+-      return equals(key, k) ? v : null;
+-    }
+-
+-    /**
+-     * Calculate the hashcode directly.
+-     */
+-    public int hashCode()
+-    {
+-      return hashCode(k) ^ hashCode(v);
+-    }
+-
+-    /**
+-     * Return the keyset.
+-     */
+-    public Set keySet()
+-    {
+-      if (keys == null)
+-        keys = singleton(k);
+-      return keys;
+-    }
+-
+-    /**
+-     * The size: always 1!
+-     */
+-    public int size()
+-    {
+-      return 1;
+-    }
+-
+-    /**
+-     * Return the values. Technically, a singleton, while more specific than
+-     * a general Collection, will work. Besides, that's what the JDK uses!
+-     */
+-    public Collection values()
+-    {
+-      if (values == null)
+-        values = singleton(v);
+-      return values;
+-    }
+-
+-    /**
+-     * Obvious string.
+-     */
+-    public String toString()
++    return new AbstractMap()
+     {
+-      return "{" + k + "=" + v + "}";
+-    }
+-  } // class SingletonMap
++      public Set entrySet()
++      {
++	return singleton(new BasicMapEntry(key, value));
++      }
++    };
++  }
+ 
+   /**
+    * Sort a list according to the natural ordering of its elements. The list
+@@ -1657,14 +700,19 @@
+    * the array.
+    *
+    * @param l the List to sort
+-   * @throws ClassCastException if some items are not mutually comparable
+-   * @throws UnsupportedOperationException if the List is not modifiable
+-   * @throws NullPointerException if some element is null
+-   * @see Arrays#sort(Object[])
++   * @exception ClassCastException if some items are not mutually comparable
++   * @exception UnsupportedOperationException if the List is not modifiable
+    */
+   public static void sort(List l)
+   {
+-    sort(l, null);
++    Object[] a = l.toArray();
++    Arrays.sort(a);
++    ListIterator i = l.listIterator();
++    for (int pos = 0; pos < a.length; pos++)
++      {
++	i.next();
++	i.set(a[pos]);
++      }
+   }
+ 
+   /**
+@@ -1676,1899 +724,1102 @@
+    * the array.
+    *
+    * @param l the List to sort
+-   * @param c the Comparator specifying the ordering for the elements, or
+-   *        null for natural ordering
+-   * @throws ClassCastException if c will not compare some pair of items
+-   * @throws UnsupportedOperationException if the List is not modifiable
+-   * @throws NullPointerException if null is compared by natural ordering
+-   *        (only possible when c is null)
+-   * @see Arrays#sort(Object[], Comparator)
++   * @param c the Comparator specifying the ordering for the elements
++   * @exception ClassCastException if c will not compare some pair of items
++   * @exception UnsupportedOperationException if the List is not modifiable
+    */
+   public static void sort(List l, Comparator c)
+   {
+     Object[] a = l.toArray();
+     Arrays.sort(a, c);
+-    ListIterator i = l.listIterator(a.length);
+-    for (int pos = a.length; --pos >= 0; )
++    ListIterator i = l.listIterator();
++    for (int pos = 0; pos < a.length; pos++)
+       {
+-	i.previous();
++	i.next();
+ 	i.set(a[pos]);
+       }
+   }
+ 
+-  /**
+-   * Swaps the elements at the specified positions within the list. Equal
+-   * positions have no effect.
+-   *
+-   * @param l the list to work on
+-   * @param i the first index to swap
+-   * @param j the second index
+-   * @throws UnsupportedOperationException if list.set is not supported
+-   * @throws IndexOutOfBoundsException if either i or j is &lt; 0 or &gt;=
+-   *         list.size()
+-   * @since 1.4
+-   */
+-  public static void swap(List l, int i, int j)
+-  {
+-    l.set(i, l.set(j, l.get(i)));
+-  }
+-
+-
+-  /**
+-   * Returns a synchronized (thread-safe) collection wrapper backed by the
+-   * given collection. Notice that element access through the iterators
+-   * is thread-safe, but if the collection can be structurally modified
+-   * (adding or removing elements) then you should synchronize around the
+-   * iteration to avoid non-deterministic behavior:<br>
+-   * <pre>
+-   * Collection c = Collections.synchronizedCollection(new Collection(...));
+-   * ...
+-   * synchronized (c)
+-   *   {
+-   *     Iterator i = c.iterator();
+-   *     while (i.hasNext())
+-   *       foo(i.next());
+-   *   }
+-   * </pre><p>
+-   *
+-   * Since the collection might be a List or a Set, and those have incompatible
+-   * equals and hashCode requirements, this relies on Object's implementation
+-   * rather than passing those calls on to the wrapped collection. The returned
+-   * Collection implements Serializable, but can only be serialized if
+-   * the collection it wraps is likewise Serializable.
+-   *
+-   * @param c the collection to wrap
+-   * @return a synchronized view of the collection
+-   * @see Serializable
+-   */
++  // All the methods from here on in require doc-comments.
++
+   public static Collection synchronizedCollection(Collection c)
+   {
+     return new SynchronizedCollection(c);
+   }
++  public static List synchronizedList(List l)
++  {
++    return new SynchronizedList(l);
++  }
++  public static Map synchronizedMap(Map m)
++  {
++    return new SynchronizedMap(m);
++  }
++  public static Set synchronizedSet(Set s)
++  {
++    return new SynchronizedSet(s);
++  }
++  public static SortedMap synchronizedSortedMap(SortedMap m)
++  {
++    return new SynchronizedSortedMap(m);
++  }
++  public static SortedSet synchronizedSortedSet(SortedSet s)
++  {
++    return new SynchronizedSortedSet(s);
++  }
++  public static Collection unmodifiableCollection(Collection c)
++  {
++    return new UnmodifiableCollection(c);
++  }
++  public static List unmodifiableList(List l)
++  {
++    return new UnmodifiableList(l);
++  }
++  public static Map unmodifiableMap(Map m)
++  {
++    return new UnmodifiableMap(m);
++  }
++  public static Set unmodifiableSet(Set s)
++  {
++    return new UnmodifiableSet(s);
++  }
++  public static SortedMap unmodifiableSortedMap(SortedMap m)
++  {
++    return new UnmodifiableSortedMap(m);
++  }
++  public static SortedSet unmodifiableSortedSet(SortedSet s)
++  {
++    return new UnmodifiableSortedSet(s);
++  }
+ 
+-  /**
+-   * The implementation of {@link #synchronizedCollection(Collection)}. This
+-   * class name is required for compatibility with Sun's JDK serializability.
+-   * Package visible, so that collections such as the one for
+-   * Hashtable.values() can specify which object to synchronize on.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  static class SynchronizedCollection
+-    implements Collection, Serializable
++  // Sun's spec will need to be checked for the precise names of these
++  // classes, for serializability's sake. However, from what I understand,
++  // serialization is broken for these classes anyway.
++
++  // Note: although this code is largely uncommented, it is all very
++  // mechanical and there's nothing really worth commenting.
++  // When serialization of these classes works, we'll need doc-comments on
++  // them to document the serialized form.
++
++  private static class UnmodifiableIterator implements Iterator
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 3053995032091335093L;
+-
+-    /**
+-     * The wrapped collection. Package visible for use by subclasses.
+-     * @serial the real collection
+-     */
+-    final Collection c;
+-
+-    /**
+-     * The object to synchronize on.  When an instance is created via public
+-     * methods, it will be this; but other uses like SynchronizedMap.values()
+-     * must specify another mutex. Package visible for use by subclasses.
+-     * @serial the lock
+-     */
+-    final Object mutex;
+-
+-    /**
+-     * Wrap a given collection.
+-     * @param c the collection to wrap
+-     * @throws NullPointerException if c is null
+-     */
+-    SynchronizedCollection(Collection c)
++    private Iterator i;
++
++    public UnmodifiableIterator(Iterator i)
+     {
+-      this.c = c;
+-      mutex = this;
+-      if (c == null)
+-        throw new NullPointerException();
++      this.i = i;
+     }
+ 
+-    /**
+-     * Called only by trusted code to specify the mutex as well as the
+-     * collection.
+-     * @param sync the mutex
+-     * @param c the collection
+-     */
+-    SynchronizedCollection(Object sync, Collection c)
++    public Object next()
+     {
+-      this.c = c;
+-      mutex = sync;
++      return i.next();
+     }
++    public boolean hasNext()
++    {
++      return i.hasNext();
++    }
++    public void remove()
++    {
++      throw new UnsupportedOperationException();
++    }
++  }
+ 
+-    public boolean add(Object o)
++  private static class UnmodifiableListIterator extends UnmodifiableIterator
++    implements ListIterator
++  {
++    // This is stored both here and in the superclass, to avoid excessive
++    // casting.
++    private ListIterator li;
++
++    public UnmodifiableListIterator(ListIterator li)
+     {
+-      synchronized (mutex)
+-        {
+-          return c.add(o);
+-        }
++      super(li);
++      this.li = li;
+     }
+ 
+-    public boolean addAll(Collection col)
++    public boolean hasPrevious()
++    {
++      return li.hasPrevious();
++    }
++    public Object previous()
++    {
++      return li.previous();
++    }
++    public int nextIndex()
++    {
++      return li.nextIndex();
++    }
++    public int previousIndex()
++    {
++      return li.previousIndex();
++    }
++    public void add(Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return c.addAll(col);
+-        }
++      throw new UnsupportedOperationException();
++    }
++    public void set(Object o)
++    {
++      throw new UnsupportedOperationException();
+     }
++  }
+ 
+-    public void clear()
++  private static class UnmodifiableCollection implements Collection,
++    Serializable
++  {
++    Collection c;
++
++    public UnmodifiableCollection(Collection c)
+     {
+-      synchronized (mutex)
+-        {
+-          c.clear();
+-        }
++      this.c = c;
+     }
+ 
++    public boolean add(Object o)
++    {
++      throw new UnsupportedOperationException();
++    }
++    public boolean addAll(Collection c)
++    {
++      throw new UnsupportedOperationException();
++    }
++    public void clear()
++    {
++      throw new UnsupportedOperationException();
++    }
+     public boolean contains(Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return c.contains(o);
+-        }
++      return c.contains(o);
+     }
+-
+     public boolean containsAll(Collection c1)
+     {
+-      synchronized (mutex)
+-        {
+-          return c.containsAll(c1);
+-        }
++      return c.containsAll(c1);
+     }
+-
+     public boolean isEmpty()
+     {
+-      synchronized (mutex)
+-        {
+-          return c.isEmpty();
+-        }
++      return c.isEmpty();
+     }
+-
+     public Iterator iterator()
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedIterator(mutex, c.iterator());
+-        }
++      return new UnmodifiableIterator(c.iterator());
+     }
+-
+     public boolean remove(Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return c.remove(o);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+-    public boolean removeAll(Collection col)
++    public boolean removeAll(Collection c)
+     {
+-      synchronized (mutex)
+-        {
+-          return c.removeAll(col);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+-    public boolean retainAll(Collection col)
++    public boolean retainAll(Collection c)
+     {
+-      synchronized (mutex)
+-        {
+-          return c.retainAll(col);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+     public int size()
+     {
+-      synchronized (mutex)
+-        {
+-          return c.size();
+-        }
++      return c.size();
+     }
+-
+     public Object[] toArray()
+     {
+-      synchronized (mutex)
+-        {
+-          return c.toArray();
+-        }
+-    }
+-
+-    public Object[] toArray(Object[] a)
+-    {
+-      synchronized (mutex)
+-        {
+-          return c.toArray(a);
+-        }
+-    }
+-
+-    public String toString()
+-    {
+-      synchronized (mutex)
+-        {
+-          return c.toString();
+-        }
+-    }
+-  } // class SynchronizedCollection
+-
+-  /**
+-   * The implementation of the various iterator methods in the
+-   * synchronized classes. These iterators must "sync" on the same object
+-   * as the collection they iterate over.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static class SynchronizedIterator implements Iterator
+-  {
+-    /**
+-     * The object to synchronize on. Package visible for use by subclass.
+-     */
+-    final Object mutex;
+-
+-    /**
+-     * The wrapped iterator.
+-     */
+-    private final Iterator i;
+-
+-    /**
+-     * Only trusted code creates a wrapper, with the specified sync.
+-     * @param sync the mutex
+-     * @param i the wrapped iterator
+-     */
+-    SynchronizedIterator(Object sync, Iterator i)
+-    {
+-      this.i = i;
+-      mutex = sync;
++      return c.toArray();
+     }
+-
+-    public Object next()
++    public Object[] toArray(Object[]a)
+     {
+-      synchronized (mutex)
+-        {
+-          return i.next();
+-        }
++      return c.toArray(a);
+     }
+-
+-    public boolean hasNext()
++    public String toString()
+     {
+-      synchronized (mutex)
+-        {
+-          return i.hasNext();
+-        }
++      return c.toString();
+     }
+-
+-    public void remove()
+-    {
+-      synchronized (mutex)
+-        {
+-          i.remove();
+-        }
+-    }
+-  } // class SynchronizedIterator
+-
+-  /**
+-   * Returns a synchronized (thread-safe) list wrapper backed by the
+-   * given list. Notice that element access through the iterators
+-   * is thread-safe, but if the list can be structurally modified
+-   * (adding or removing elements) then you should synchronize around the
+-   * iteration to avoid non-deterministic behavior:<br>
+-   * <pre>
+-   * List l = Collections.synchronizedList(new List(...));
+-   * ...
+-   * synchronized (l)
+-   *   {
+-   *     Iterator i = l.iterator();
+-   *     while (i.hasNext())
+-   *       foo(i.next());
+-   *   }
+-   * </pre><p>
+-   *
+-   * The returned List implements Serializable, but can only be serialized if
+-   * the list it wraps is likewise Serializable. In addition, if the wrapped
+-   * list implements RandomAccess, this does too.
+-   *
+-   * @param l the list to wrap
+-   * @return a synchronized view of the list
+-   * @see Serializable
+-   * @see RandomAccess
+-   */
+-  public static List synchronizedList(List l)
+-  {
+-    if (l instanceof RandomAccess)
+-      return new SynchronizedRandomAccessList(l);
+-    return new SynchronizedList(l);
+   }
+ 
+-  /**
+-   * The implementation of {@link #synchronizedList(List)} for sequential
+-   * lists. This class name is required for compatibility with Sun's JDK
+-   * serializability. Package visible, so that lists such as Vector.subList()
+-   * can specify which object to synchronize on.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  static class SynchronizedList extends SynchronizedCollection
++  private static class UnmodifiableList extends UnmodifiableCollection
+     implements List
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -7754090372962971524L;
+-
+-    /**
+-     * The wrapped list; stored both here and in the superclass to avoid
+-     * excessive casting. Package visible for use by subclass.
+-     * @serial the wrapped list
+-     */
+-    final List list;
+-
+-    /**
+-     * Wrap a given list.
+-     * @param l the list to wrap
+-     * @throws NullPointerException if l is null
+-     */
+-    SynchronizedList(List l)
+-    {
+-      super(l);
+-      list = l;
+-    }
++    // This is stored both here and in the superclass, to avoid excessive
++    // casting.
++    List l;
+ 
+-    /**
+-     * Called only by trusted code to specify the mutex as well as the list.
+-     * @param sync the mutex
+-     * @param l the list
+-     */
+-    SynchronizedList(Object sync, List l)
++    public UnmodifiableList(List l)
+     {
+-      super(sync, l);
+-      list = l;
++      super(l);
++      this.l = l;
+     }
+ 
+     public void add(int index, Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          list.add(index, o);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+     public boolean addAll(int index, Collection c)
+     {
+-      synchronized (mutex)
+-        {
+-          return list.addAll(index, c);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+     public boolean equals(Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return list.equals(o);
+-        }
++      return l.equals(o);
+     }
+-
+     public Object get(int index)
+     {
+-      synchronized (mutex)
+-        {
+-          return list.get(index);
+-        }
++      return l.get(index);
+     }
+-
+     public int hashCode()
+     {
+-      synchronized (mutex)
+-        {
+-          return list.hashCode();
+-        }
++      return l.hashCode();
+     }
+-
+     public int indexOf(Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return list.indexOf(o);
+-        }
++      return l.indexOf(o);
+     }
+-
+     public int lastIndexOf(Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return list.lastIndexOf(o);
+-        }
++      return l.lastIndexOf(o);
+     }
+-
+     public ListIterator listIterator()
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedListIterator(mutex, list.listIterator());
+-        }
++      return new UnmodifiableListIterator(l.listIterator());
+     }
+-
+     public ListIterator listIterator(int index)
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedListIterator(mutex, list.listIterator(index));
+-        }
++      return new UnmodifiableListIterator(l.listIterator(index));
+     }
+-
+     public Object remove(int index)
+     {
+-      synchronized (mutex)
+-        {
+-          return list.remove(index);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+     public Object set(int index, Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return list.set(index, o);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+     public List subList(int fromIndex, int toIndex)
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedList(mutex, list.subList(fromIndex, toIndex));
+-        }
++      return new UnmodifiableList(l.subList(fromIndex, toIndex));
+     }
+-  } // class SynchronizedList
++  }
+ 
+-  /**
+-   * The implementation of {@link #synchronizedList(List)} for random-access
+-   * lists. This class name is required for compatibility with Sun's JDK
+-   * serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static final class SynchronizedRandomAccessList
+-    extends SynchronizedList implements RandomAccess
++  private static class UnmodifiableSet extends UnmodifiableCollection
++    implements Set
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 1530674583602358482L;
+-
+-    /**
+-     * Wrap a given list.
+-     * @param l the list to wrap
+-     * @throws NullPointerException if l is null
+-     */
+-    SynchronizedRandomAccessList(List l)
++    public UnmodifiableSet(Set s)
+     {
+-      super(l);
++      super(s);
+     }
+-
+-    /**
+-     * Called only by trusted code to specify the mutex as well as the
+-     * collection.
+-     * @param sync the mutex
+-     * @param l the list
+-     */
+-    SynchronizedRandomAccessList(Object sync, List l)
++    public boolean equals(Object o)
+     {
+-      super(sync, l);
++      return c.equals(o);
+     }
+-
+-    public List subList(int fromIndex, int toIndex)
++    public int hashCode()
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedRandomAccessList(mutex,
+-                                                  list.subList(fromIndex,
+-                                                               toIndex));
+-        }
++      return c.hashCode();
+     }
+-  } // class SynchronizedRandomAccessList
++  }
+ 
+-  /**
+-   * The implementation of {@link SynchronizedList#listIterator()}. This
+-   * iterator must "sync" on the same object as the list it iterates over.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static final class SynchronizedListIterator
+-    extends SynchronizedIterator implements ListIterator
++  private static class UnmodifiableSortedSet extends UnmodifiableSet
++    implements SortedSet
+   {
+-    /**
+-     * The wrapped iterator, stored both here and in the superclass to
+-     * avoid excessive casting.
+-     */
+-    private final ListIterator li;
+-
+-    /**
+-     * Only trusted code creates a wrapper, with the specified sync.
+-     * @param sync the mutex
+-     * @param li the wrapped iterator
+-     */
+-    SynchronizedListIterator(Object sync, ListIterator li)
++    // This is stored both here and in the superclass, to avoid excessive
++    // casting.
++    private SortedSet ss;
++
++    public UnmodifiableSortedSet(SortedSet ss)
+     {
+-      super(sync, li);
+-      this.li = li;
++      super(ss);
++      this.ss = ss;
+     }
+ 
+-    public void add(Object o)
++    public Comparator comparator()
+     {
+-      synchronized (mutex)
+-        {
+-          li.add(o);
+-        }
++      return ss.comparator();
+     }
+-    public boolean hasPrevious()
++    public Object first()
+     {
+-      synchronized (mutex)
+-        {
+-          return li.hasPrevious();
+-        }
++      return ss.first();
+     }
+-
+-    public int nextIndex()
++    public Object last()
+     {
+-      synchronized (mutex)
+-        {
+-          return li.nextIndex();
+-        }
++      return ss.last();
+     }
+-
+-    public Object previous()
++    public SortedSet headSet(Object toElement)
+     {
+-      synchronized (mutex)
+-        {
+-          return li.previous();
+-        }
++      return new UnmodifiableSortedSet(ss.headSet(toElement));
+     }
+-
+-    public int previousIndex()
++    public SortedSet tailSet(Object fromElement)
+     {
+-      synchronized (mutex)
+-        {
+-          return li.previousIndex();
+-        }
++      return new UnmodifiableSortedSet(ss.tailSet(fromElement));
+     }
+-
+-    public void set(Object o)
++    public SortedSet subSet(Object fromElement, Object toElement)
+     {
+-      synchronized (mutex)
+-        {
+-          li.set(o);
+-        }
+-    }
+-  } // class SynchronizedListIterator
+-
+-  /**
+-   * Returns a synchronized (thread-safe) map wrapper backed by the given
+-   * map. Notice that element access through the collection views and their
+-   * iterators are thread-safe, but if the map can be structurally modified
+-   * (adding or removing elements) then you should synchronize around the
+-   * iteration to avoid non-deterministic behavior:<br>
+-   * <pre>
+-   * Map m = Collections.synchronizedMap(new Map(...));
+-   * ...
+-   * Set s = m.keySet(); // safe outside a synchronized block
+-   * synchronized (m) // synch on m, not s
+-   *   {
+-   *     Iterator i = s.iterator();
+-   *     while (i.hasNext())
+-   *       foo(i.next());
+-   *   }
+-   * </pre><p>
+-   *
+-   * The returned Map implements Serializable, but can only be serialized if
+-   * the map it wraps is likewise Serializable.
+-   *
+-   * @param m the map to wrap
+-   * @return a synchronized view of the map
+-   * @see Serializable
+-   */
+-  public static Map synchronizedMap(Map m)
+-  {
+-    return new SynchronizedMap(m);
++      return new UnmodifiableSortedSet(ss.subSet(fromElement, toElement));
++    }
+   }
+ 
+-  /**
+-   * The implementation of {@link #synchronizedMap(Map)}. This
+-   * class name is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static class SynchronizedMap implements Map, Serializable
++  private static class UnmodifiableMap implements Map, Serializable
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 1978198479659022715L;
+-
+-    /**
+-     * The wrapped map.
+-     * @serial the real map
+-     */
+-    private final Map m;
+-
+-    /**
+-     * The object to synchronize on.  When an instance is created via public
+-     * methods, it will be this; but other uses like
+-     * SynchronizedSortedMap.subMap() must specify another mutex. Package
+-     * visible for use by subclass.
+-     * @serial the lock
+-     */
+-    final Object mutex;
+-
+-    /**
+-     * Cache the entry set.
+-     */
+-    private transient Set entries;
+-
+-    /**
+-     * Cache the key set.
+-     */
+-    private transient Set keys;
+-
+-    /**
+-     * Cache the value collection.
+-     */
+-    private transient Collection values;
+-
+-    /**
+-     * Wrap a given map.
+-     * @param m the map to wrap
+-     * @throws NullPointerException if m is null
+-     */
+-    SynchronizedMap(Map m)
+-    {
+-      this.m = m;
+-      mutex = this;
+-      if (m == null)
+-        throw new NullPointerException();
+-    }
++    Map m;
+ 
+-    /**
+-     * Called only by trusted code to specify the mutex as well as the map.
+-     * @param sync the mutex
+-     * @param m the map
+-     */
+-    SynchronizedMap(Object sync, Map m)
++    public UnmodifiableMap(Map m)
+     {
+       this.m = m;
+-      mutex = sync;
+     }
+ 
+     public void clear()
+     {
+-      synchronized (mutex)
+-        {
+-          m.clear();
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+     public boolean containsKey(Object key)
+     {
+-      synchronized (mutex)
+-        {
+-          return m.containsKey(key);
+-        }
++      return m.containsKey(key);
+     }
+-
+     public boolean containsValue(Object value)
+     {
+-      synchronized (mutex)
+-        {
+-          return m.containsValue(value);
+-        }
++      return m.containsValue(value);
+     }
+ 
+     // This is one of the ickiest cases of nesting I've ever seen. It just
+-    // means "return a SynchronizedSet, except that the iterator() method
+-    // returns an SynchronizedIterator whose next() method returns a
+-    // synchronized wrapper around its normal return value".
++    // means "return an UnmodifiableSet, except that the iterator() method
++    // returns an UnmodifiableIterator whos next() method returns an
++    // unmodifiable wrapper around its normal return value".
+     public Set entrySet()
+     {
+-      // Define this here to spare some nesting.
+-      class SynchronizedMapEntry implements Map.Entry
++      return new UnmodifiableSet(m.entrySet())
+       {
+-        final Map.Entry e;
+-        SynchronizedMapEntry(Object o)
+-        {
+-          e = (Map.Entry) o;
+-        }
+-        public boolean equals(Object o)
+-        {
+-          synchronized (mutex)
+-            {
+-              return e.equals(o);
+-            }
+-        }
+-        public Object getKey()
+-        {
+-          synchronized (mutex)
+-            {
+-              return e.getKey();
+-            }
+-        }
+-        public Object getValue()
+-        {
+-          synchronized (mutex)
+-            {
+-              return e.getValue();
+-            }
+-        }
+-        public int hashCode()
+-        {
+-          synchronized (mutex)
+-            {
+-              return e.hashCode();
+-            }
+-        }
+-        public Object setValue(Object value)
+-        {
+-          synchronized (mutex)
+-            {
+-              return e.setValue(value);
+-            }
+-        }
+-        public String toString()
+-        {
+-          synchronized (mutex)
+-            {
+-              return e.toString();
+-            }
+-        }
+-      } // class SynchronizedMapEntry
+-
+-      // Now the actual code.
+-      if (entries == null)
+-        synchronized (mutex)
+-          {
+-            entries = new SynchronizedSet(mutex, m.entrySet())
+-            {
+-              public Iterator iterator()
+-              {
+-                synchronized (super.mutex)
+-                  {
+-                    return new SynchronizedIterator(super.mutex, c.iterator())
+-                    {
+-                      public Object next()
+-                      {
+-                        synchronized (super.mutex)
+-                          {
+-                            return new SynchronizedMapEntry(super.next());
+-                          }
+-                      }
+-                    };
+-                  }
+-              }
+-            };
+-          }
+-      return entries;
++	public Iterator iterator()
++	{
++	  return new UnmodifiableIterator(c.iterator())
++	  {
++	    public Object next()
++	    {
++	      final Map.Entry e = (Map.Entry) super.next();
++	      return new Map.Entry()
++	      {
++		public Object getKey()
++		{
++		  return e.getKey();
++		}
++		public Object getValue()
++		{
++		  return e.getValue();
++		}
++		public Object setValue(Object value)
++		{
++		  throw new UnsupportedOperationException();
++		}
++		public int hashCode()
++		{
++		  return e.hashCode();
++		}
++		public boolean equals(Object o)
++		{
++		  return e.equals(o);
++		}
++	      };
++	    }
++	  };
++	}
++      };
+     }
+-
+     public boolean equals(Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return m.equals(o);
+-        }
++      return m.equals(o);
+     }
+-
+     public Object get(Object key)
+     {
+-      synchronized (mutex)
+-        {
+-          return m.get(key);
+-        }
++      return m.get(key);
++    }
++    public Object put(Object key, Object value)
++    {
++      throw new UnsupportedOperationException();
+     }
+-
+     public int hashCode()
+     {
+-      synchronized (mutex)
+-        {
+-          return m.hashCode();
+-        }
++      return m.hashCode();
+     }
+-
+     public boolean isEmpty()
+     {
+-      synchronized (mutex)
+-        {
+-          return m.isEmpty();
+-        }
++      return m.isEmpty();
+     }
+-
+     public Set keySet()
+     {
+-      if (keys == null)
+-        synchronized (mutex)
+-          {
+-            keys = new SynchronizedSet(mutex, m.keySet());
+-          }
+-      return keys;
+-    }
+-
+-    public Object put(Object key, Object value)
+-    {
+-      synchronized (mutex)
+-        {
+-          return m.put(key, value);
+-        }
++      return new UnmodifiableSet(m.keySet());
+     }
+-
+-    public void putAll(Map map)
++    public void putAll(Map m)
+     {
+-      synchronized (mutex)
+-        {
+-          m.putAll(map);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+     public Object remove(Object o)
+     {
+-      synchronized (mutex)
+-        {
+-          return m.remove(o);
+-        }
++      throw new UnsupportedOperationException();
+     }
+-
+     public int size()
+     {
+-      synchronized (mutex)
+-        {
+-          return m.size();
+-        }
+-    }
+-
+-    public String toString()
+-    {
+-      synchronized (mutex)
+-        {
+-          return m.toString();
+-        }
++      return m.size();
+     }
+-
+     public Collection values()
+     {
+-      if (values == null)
+-        synchronized (mutex)
+-          {
+-            values = new SynchronizedCollection(mutex, m.values());
+-          }
+-      return values;
+-    }
+-  } // class SynchronizedMap
+-
+-  /**
+-   * Returns a synchronized (thread-safe) set wrapper backed by the given
+-   * set. Notice that element access through the iterator is thread-safe, but
+-   * if the set can be structurally modified (adding or removing elements)
+-   * then you should synchronize around the iteration to avoid
+-   * non-deterministic behavior:<br>
+-   * <pre>
+-   * Set s = Collections.synchronizedSet(new Set(...));
+-   * ...
+-   * synchronized (s)
+-   *   {
+-   *     Iterator i = s.iterator();
+-   *     while (i.hasNext())
+-   *       foo(i.next());
+-   *   }
+-   * </pre><p>
+-   *
+-   * The returned Set implements Serializable, but can only be serialized if
+-   * the set it wraps is likewise Serializable.
+-   *
+-   * @param s the set to wrap
+-   * @return a synchronized view of the set
+-   * @see Serializable
+-   */
+-  public static Set synchronizedSet(Set s)
+-  {
+-    return new SynchronizedSet(s);
+-  }
+-
+-  /**
+-   * The implementation of {@link #synchronizedSet(Set)}. This class
+-   * name is required for compatibility with Sun's JDK serializability.
+-   * Package visible, so that sets such as Hashtable.keySet()
+-   * can specify which object to synchronize on.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  static class SynchronizedSet extends SynchronizedCollection
+-    implements Set
+-  {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 487447009682186044L;
+-
+-    /**
+-     * Wrap a given set.
+-     * @param s the set to wrap
+-     * @throws NullPointerException if s is null
+-     */
+-    SynchronizedSet(Set s)
+-    {
+-      super(s);
+-    }
+-
+-    /**
+-     * Called only by trusted code to specify the mutex as well as the set.
+-     * @param sync the mutex
+-     * @param s the set
+-     */
+-    SynchronizedSet(Object sync, Set s)
+-    {
+-      super(sync, s);
++      return new UnmodifiableCollection(m.values());
+     }
+-
+-    public boolean equals(Object o)
++    public String toString()
+     {
+-      synchronized (mutex)
+-        {
+-          return c.equals(o);
+-        }
++      return m.toString();
+     }
+-
+-    public int hashCode()
+-    {
+-      synchronized (mutex)
+-        {
+-          return c.hashCode();
+-        }
+-    }
+-  } // class SynchronizedSet
+-
+-  /**
+-   * Returns a synchronized (thread-safe) sorted map wrapper backed by the
+-   * given map. Notice that element access through the collection views,
+-   * subviews, and their iterators are thread-safe, but if the map can be
+-   * structurally modified (adding or removing elements) then you should
+-   * synchronize around the iteration to avoid non-deterministic behavior:<br>
+-   * <pre>
+-   * SortedMap m = Collections.synchronizedSortedMap(new SortedMap(...));
+-   * ...
+-   * Set s = m.keySet(); // safe outside a synchronized block
+-   * SortedMap m2 = m.headMap(foo); // safe outside a synchronized block
+-   * Set s2 = m2.keySet(); // safe outside a synchronized block
+-   * synchronized (m) // synch on m, not m2, s or s2
+-   *   {
+-   *     Iterator i = s.iterator();
+-   *     while (i.hasNext())
+-   *       foo(i.next());
+-   *     i = s2.iterator();
+-   *     while (i.hasNext())
+-   *       bar(i.next());
+-   *   }
+-   * </pre><p>
+-   *
+-   * The returned SortedMap implements Serializable, but can only be
+-   * serialized if the map it wraps is likewise Serializable.
+-   *
+-   * @param m the sorted map to wrap
+-   * @return a synchronized view of the sorted map
+-   * @see Serializable
+-   */
+-  public static SortedMap synchronizedSortedMap(SortedMap m)
+-  {
+-    return new SynchronizedSortedMap(m);
+   }
+ 
+-  /**
+-   * The implementation of {@link #synchronizedSortedMap(SortedMap)}. This
+-   * class name is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static final class SynchronizedSortedMap extends SynchronizedMap
++  private static class UnmodifiableSortedMap extends UnmodifiableMap
+     implements SortedMap
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -8798146769416483793L;
+-
+-    /**
+-     * The wrapped map; stored both here and in the superclass to avoid
+-     * excessive casting.
+-     * @serial the wrapped map
+-     */
+-    private final SortedMap sm;
+-
+-    /**
+-     * Wrap a given map.
+-     * @param sm the map to wrap
+-     * @throws NullPointerException if sm is null
+-     */
+-    SynchronizedSortedMap(SortedMap sm)
+-    {
+-      super(sm);
+-      this.sm = sm;
+-    }
++    // This is stored both here and in the superclass, to avoid excessive
++    // casting.
++    private SortedMap sm;
+ 
+-    /**
+-     * Called only by trusted code to specify the mutex as well as the map.
+-     * @param sync the mutex
+-     * @param sm the map
+-     */
+-    SynchronizedSortedMap(Object sync, SortedMap sm)
++    public UnmodifiableSortedMap(SortedMap sm)
+     {
+-      super(sync, sm);
++      super(sm);
+       this.sm = sm;
+     }
+ 
+     public Comparator comparator()
+     {
+-      synchronized (mutex)
+-        {
+-          return sm.comparator();
+-        }
++      return sm.comparator();
+     }
+-
+     public Object firstKey()
+     {
+-      synchronized (mutex)
+-        {
+-          return sm.firstKey();
+-        }
++      return sm.firstKey();
++    }
++    public Object lastKey()
++    {
++      return sm.lastKey();
+     }
+-
+     public SortedMap headMap(Object toKey)
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedSortedMap(mutex, sm.headMap(toKey));
+-        }
++      return new UnmodifiableSortedMap(sm.headMap(toKey));
+     }
+-
+-    public Object lastKey()
++    public SortedMap tailMap(Object fromKey)
+     {
+-      synchronized (mutex)
+-        {
+-          return sm.lastKey();
+-        }
++      return new UnmodifiableSortedMap(sm.tailMap(fromKey));
+     }
+-
+     public SortedMap subMap(Object fromKey, Object toKey)
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedSortedMap(mutex, sm.subMap(fromKey, toKey));
+-        }
++      return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey));
+     }
+-
+-    public SortedMap tailMap(Object fromKey)
+-    {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedSortedMap(mutex, sm.tailMap(fromKey));
+-        }
+-    }
+-  } // class SynchronizedSortedMap
+-
+-  /**
+-   * Returns a synchronized (thread-safe) sorted set wrapper backed by the
+-   * given set. Notice that element access through the iterator and through
+-   * subviews are thread-safe, but if the set can be structurally modified
+-   * (adding or removing elements) then you should synchronize around the
+-   * iteration to avoid non-deterministic behavior:<br>
+-   * <pre>
+-   * SortedSet s = Collections.synchronizedSortedSet(new SortedSet(...));
+-   * ...
+-   * SortedSet s2 = s.headSet(foo); // safe outside a synchronized block
+-   * synchronized (s) // synch on s, not s2
+-   *   {
+-   *     Iterator i = s2.iterator();
+-   *     while (i.hasNext())
+-   *       foo(i.next());
+-   *   }
+-   * </pre><p>
+-   *
+-   * The returned SortedSet implements Serializable, but can only be
+-   * serialized if the set it wraps is likewise Serializable.
+-   *
+-   * @param s the sorted set to wrap
+-   * @return a synchronized view of the sorted set
+-   * @see Serializable
+-   */
+-  public static SortedSet synchronizedSortedSet(SortedSet s)
+-  {
+-    return new SynchronizedSortedSet(s);
+   }
+ 
+-  /**
+-   * The implementation of {@link #synchronizedSortedSet(SortedSet)}. This
+-   * class name is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static final class SynchronizedSortedSet extends SynchronizedSet
+-    implements SortedSet
++  // All the "Synchronized" wrapper objects include a "sync" field which
++  // specifies what object to synchronize on. That way, nested wrappers such as
++  // UnmodifiableMap.keySet synchronize on the right things.
++
++  private static class SynchronizedIterator implements Iterator
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 8695801310862127406L;
+-
+-    /**
+-     * The wrapped set; stored both here and in the superclass to avoid
+-     * excessive casting.
+-     * @serial the wrapped set
+-     */
+-    private final SortedSet ss;
+-
+-    /**
+-     * Wrap a given set.
+-     * @param ss the set to wrap
+-     * @throws NullPointerException if ss is null
+-     */
+-    SynchronizedSortedSet(SortedSet ss)
++    Object sync;
++    private Iterator i;
++
++    public SynchronizedIterator(Object sync, Iterator i)
+     {
+-      super(ss);
+-      this.ss = ss;
++      this.sync = sync;
++      this.i = i;
+     }
+ 
+-    /**
+-     * Called only by trusted code to specify the mutex as well as the set.
+-     * @param sync the mutex
+-     * @param l the list
+-     */
+-    SynchronizedSortedSet(Object sync, SortedSet ss)
++    public Object next()
+     {
+-      super(sync, ss);
+-      this.ss = ss;
++      synchronized(sync)
++      {
++	return i.next();
++      }
+     }
+-
+-    public Comparator comparator()
++    public boolean hasNext()
+     {
+-      synchronized (mutex)
+-        {
+-          return ss.comparator();
+-        }
++      synchronized(sync)
++      {
++	return i.hasNext();
++      }
+     }
+-
+-    public Object first()
++    public void remove()
+     {
+-      synchronized (mutex)
+-        {
+-          return ss.first();
+-        }
++      synchronized(sync)
++      {
++	i.remove();
++      }
+     }
++  }
+ 
+-    public SortedSet headSet(Object toElement)
++  private static class SynchronizedListIterator extends SynchronizedIterator
++    implements ListIterator
++  {
++    // This is stored both here and in the superclass, to avoid excessive
++    // casting.
++    private ListIterator li;
++
++    public SynchronizedListIterator(Object sync, ListIterator li)
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedSortedSet(mutex, ss.headSet(toElement));
+-        }
++      super(sync, li);
++      this.li = li;
+     }
+ 
+-    public Object last()
++    public boolean hasPrevious()
+     {
+-      synchronized (mutex)
+-        {
+-          return ss.last();
+-        }
++      synchronized(sync)
++      {
++	return li.hasPrevious();
++      }
+     }
+-
+-    public SortedSet subSet(Object fromElement, Object toElement)
++    public Object previous()
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedSortedSet(mutex,
+-                                           ss.subSet(fromElement, toElement));
+-        }
++      synchronized(sync)
++      {
++	return li.previous();
++      }
+     }
+-
+-    public SortedSet tailSet(Object fromElement)
++    public int nextIndex()
+     {
+-      synchronized (mutex)
+-        {
+-          return new SynchronizedSortedSet(mutex, ss.tailSet(fromElement));
+-        }
+-    }
+-  } // class SynchronizedSortedSet
+-
+-
+-  /**
+-   * Returns an unmodifiable view of the given collection. This allows
+-   * "read-only" access, although changes in the backing collection show up
+-   * in this view. Attempts to modify the collection directly or via iterators
+-   * will fail with {@link UnsupportedOperationException}.
+-   * <p>
+-   *
+-   * Since the collection might be a List or a Set, and those have incompatible
+-   * equals and hashCode requirements, this relies on Object's implementation
+-   * rather than passing those calls on to the wrapped collection. The returned
+-   * Collection implements Serializable, but can only be serialized if
+-   * the collection it wraps is likewise Serializable.
+-   *
+-   * @param c the collection to wrap
+-   * @return a read-only view of the collection
+-   * @see Serializable
+-   */
+-  public static Collection unmodifiableCollection(Collection c)
+-  {
+-    return new UnmodifiableCollection(c);
++      synchronized(sync)
++      {
++	return li.nextIndex();
++      }
++    }
++    public int previousIndex()
++    {
++      synchronized(sync)
++      {
++	return li.previousIndex();
++      }
++    }
++    public void add(Object o)
++    {
++      synchronized(sync)
++      {
++	li.add(o);
++      }
++    }
++    public void set(Object o)
++    {
++      synchronized(sync)
++      {
++	li.set(o);
++      }
++    }
+   }
+ 
+   /**
+-   * The implementation of {@link #unmodifiableCollection(Collection)}. This
+-   * class name is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++   * Package visible, so that collections such as the one for
++   * Hashtable.values() can specify which object to synchronize on.
+    */
+-  private static class UnmodifiableCollection
+-    implements Collection, Serializable
++  static class SynchronizedCollection implements Collection,
++    Serializable
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = 1820017752578914078L;
+-
+-    /**
+-     * The wrapped collection. Package visible for use by subclasses.
+-     * @serial the real collection
+-     */
+-    final Collection c;
+-
+-    /**
+-     * Wrap a given collection.
+-     * @param c the collection to wrap
+-     * @throws NullPointerException if c is null
+-     */
+-    UnmodifiableCollection(Collection c)
++    Object sync;
++    Collection c;
++
++    public SynchronizedCollection(Collection c)
+     {
++      this.sync = this;
+       this.c = c;
+-      if (c == null)
+-        throw new NullPointerException();
++    }
++    public SynchronizedCollection(Object sync, Collection c)
++    {
++      this.c = c;
++      this.sync = sync;
+     }
+ 
+     public boolean add(Object o)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return c.add(o);
++      }
+     }
+-
+-    public boolean addAll(Collection c)
++    public boolean addAll(Collection col)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return c.addAll(col);
++      }
+     }
+-
+     public void clear()
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	c.clear();
++      }
+     }
+-
+     public boolean contains(Object o)
+     {
+-      return c.contains(o);
++      synchronized(sync)
++      {
++	return c.contains(o);
++      }
+     }
+-
+     public boolean containsAll(Collection c1)
+     {
+-      return c.containsAll(c1);
++      synchronized(sync)
++      {
++	return c.containsAll(c1);
++      }
+     }
+-
+     public boolean isEmpty()
+     {
+-      return c.isEmpty();
++      synchronized(sync)
++      {
++	return c.isEmpty();
++      }
+     }
+-
+     public Iterator iterator()
+     {
+-      return new UnmodifiableIterator(c.iterator());
++      synchronized(sync)
++      {
++	return new SynchronizedIterator(sync, c.iterator());
++      }
+     }
+-
+     public boolean remove(Object o)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return c.remove(o);
++      }
+     }
+-
+-    public boolean removeAll(Collection c)
++    public boolean removeAll(Collection col)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return c.removeAll(col);
++      }
+     }
+-
+-    public boolean retainAll(Collection c)
++    public boolean retainAll(Collection col)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return c.retainAll(col);
++      }
+     }
+-
+     public int size()
+     {
+-      return c.size();
++      synchronized(sync)
++      {
++	return c.size();
++      }
+     }
+-
+     public Object[] toArray()
+     {
+-      return c.toArray();
++      synchronized(sync)
++      {
++	return c.toArray();
++      }
+     }
+-
+-    public Object[] toArray(Object[] a)
++    public Object[] toArray(Object[]a)
+     {
+-      return c.toArray(a);
++      synchronized(sync)
++      {
++	return c.toArray(a);
++      }
+     }
+-
+     public String toString()
+     {
+-      return c.toString();
++      synchronized(sync)
++      {
++	return c.toString();
++      }
+     }
+-  } // class UnmodifiableCollection
++  }
+ 
+-  /**
+-   * The implementation of the various iterator methods in the
+-   * unmodifiable classes.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static class UnmodifiableIterator implements Iterator
++  private static class SynchronizedList extends SynchronizedCollection
++    implements List
+   {
+-    /**
+-     * The wrapped iterator.
+-     */
+-    private final Iterator i;
+-
+-    /**
+-     * Only trusted code creates a wrapper.
+-     * @param i the wrapped iterator
+-     */
+-    UnmodifiableIterator(Iterator i)
+-    {
+-      this.i = i;
+-    }
+-
+-    public Object next()
+-    {
+-      return i.next();
+-    }
++    // This is stored both here and in the superclass, to avoid excessive
++    // casting.
++    List l;
+ 
+-    public boolean hasNext()
++    public SynchronizedList(Object sync, List l)
+     {
+-      return i.hasNext();
++      super(sync, l);
++      this.l = l;
+     }
+-
+-    public void remove()
+-    {
+-      throw new UnsupportedOperationException();
+-    }
+-  } // class UnmodifiableIterator
+-
+-  /**
+-   * Returns an unmodifiable view of the given list. This allows
+-   * "read-only" access, although changes in the backing list show up
+-   * in this view. Attempts to modify the list directly, via iterators, or
+-   * via sublists, will fail with {@link UnsupportedOperationException}.
+-   * <p>
+-   *
+-   * The returned List implements Serializable, but can only be serialized if
+-   * the list it wraps is likewise Serializable. In addition, if the wrapped
+-   * list implements RandomAccess, this does too.
+-   *
+-   * @param l the list to wrap
+-   * @return a read-only view of the list
+-   * @see Serializable
+-   * @see RandomAccess
+-   */
+-  public static List unmodifiableList(List l)
+-  {
+-    if (l instanceof RandomAccess)
+-      return new UnmodifiableRandomAccessList(l);
+-    return new UnmodifiableList(l);
+-  }
+-
+-  /**
+-   * The implementation of {@link #unmodifiableList(List)} for sequential
+-   * lists. This class name is required for compatibility with Sun's JDK
+-   * serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static class UnmodifiableList extends UnmodifiableCollection
+-    implements List
+-  {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -283967356065247728L;
+-
+-
+-    /**
+-     * The wrapped list; stored both here and in the superclass to avoid
+-     * excessive casting. Package visible for use by subclass.
+-     * @serial the wrapped list
+-     */
+-    final List list;
+-
+-    /**
+-     * Wrap a given list.
+-     * @param l the list to wrap
+-     * @throws NullPointerException if l is null
+-     */
+-    UnmodifiableList(List l)
++    public SynchronizedList(List l)
+     {
+       super(l);
+-      list = l;
++      this.l = l;
+     }
+ 
+     public void add(int index, Object o)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	l.add(index, o);
++      }
+     }
+-
+     public boolean addAll(int index, Collection c)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return l.addAll(index, c);
++      }
+     }
+-
+     public boolean equals(Object o)
+     {
+-      return list.equals(o);
++      synchronized(sync)
++      {
++	return l.equals(o);
++      }
+     }
+-
+     public Object get(int index)
+     {
+-      return list.get(index);
++      synchronized(sync)
++      {
++	return l.get(index);
++      }
+     }
+-
+     public int hashCode()
+     {
+-      return list.hashCode();
++      synchronized(sync)
++      {
++	return l.hashCode();
++      }
+     }
+-
+     public int indexOf(Object o)
+     {
+-      return list.indexOf(o);
++      synchronized(sync)
++      {
++	return l.indexOf(o);
++      }
+     }
+-
+     public int lastIndexOf(Object o)
+     {
+-      return list.lastIndexOf(o);
++      synchronized(sync)
++      {
++	return l.lastIndexOf(o);
++      }
+     }
+-
+     public ListIterator listIterator()
+     {
+-      return new UnmodifiableListIterator(list.listIterator());
++      synchronized(sync)
++      {
++	return new SynchronizedListIterator(sync, l.listIterator());
++      }
+     }
+-
+     public ListIterator listIterator(int index)
+     {
+-      return new UnmodifiableListIterator(list.listIterator(index));
++      synchronized(sync)
++      {
++	return new SynchronizedListIterator(sync, l.listIterator(index));
++      }
+     }
+-
+     public Object remove(int index)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return l.remove(index);
++      }
++    }
++    public boolean remove(Object o)
++    {
++      synchronized(sync)
++      {
++	return l.remove(o);
++      }
+     }
+-
+     public Object set(int index, Object o)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return l.set(index, o);
++      }
+     }
+-
+     public List subList(int fromIndex, int toIndex)
+     {
+-      return unmodifiableList(list.subList(fromIndex, toIndex));
++      synchronized(sync)
++      {
++	return new SynchronizedList(l.subList(fromIndex, toIndex));
++      }
+     }
+-  } // class UnmodifiableList
++  }
+ 
+   /**
+-   * The implementation of {@link #unmodifiableList(List)} for random-access
+-   * lists. This class name is required for compatibility with Sun's JDK
+-   * serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++   * Package visible, so that sets such as the one for Hashtable.keySet()
++   * can specify which object to synchronize on.
+    */
+-  private static final class UnmodifiableRandomAccessList
+-    extends UnmodifiableList implements RandomAccess
++  static class SynchronizedSet extends SynchronizedCollection
++    implements Set
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -2542308836966382001L;
+-
+-    /**
+-     * Wrap a given list.
+-     * @param l the list to wrap
+-     * @throws NullPointerException if l is null
+-     */
+-    UnmodifiableRandomAccessList(List l)
++    public SynchronizedSet(Object sync, Set s)
+     {
+-      super(l);
++      super(sync, s);
+     }
+-  } // class UnmodifiableRandomAccessList
+-
+-  /**
+-   * The implementation of {@link UnmodifiableList#listIterator()}.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static final class UnmodifiableListIterator
+-    extends UnmodifiableIterator implements ListIterator
+-  {
+-    /**
+-     * The wrapped iterator, stored both here and in the superclass to
+-     * avoid excessive casting.
+-     */
+-    private final ListIterator li;
+-
+-    /**
+-     * Only trusted code creates a wrapper.
+-     * @param li the wrapped iterator
+-     */
+-    UnmodifiableListIterator(ListIterator li)
++    public SynchronizedSet(Set s)
+     {
+-      super(li);
+-      this.li = li;
++      super(s);
+     }
+ 
+-    public void add(Object o)
++    public boolean equals(Object o)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return c.equals(o);
++      }
+     }
+-
+-    public boolean hasPrevious()
++    public int hashCode()
+     {
+-      return li.hasPrevious();
++      synchronized(sync)
++      {
++	return c.hashCode();
++      }
+     }
++  }
+ 
+-    public int nextIndex()
++  private static class SynchronizedSortedSet extends SynchronizedSet
++    implements SortedSet
++  {
++    // This is stored both here and in the superclass, to avoid excessive
++    // casting.
++    private SortedSet ss;
++
++    public SynchronizedSortedSet(Object sync, SortedSet ss)
+     {
+-      return li.nextIndex();
++      super(sync, ss);
++      this.ss = ss;
+     }
+-
+-    public Object previous()
++    public SynchronizedSortedSet(SortedSet ss)
+     {
+-      return li.previous();
++      super(ss);
++      this.ss = ss;
+     }
+ 
+-    public int previousIndex()
++    public Comparator comparator()
+     {
+-      return li.previousIndex();
++      synchronized(sync)
++      {
++	return ss.comparator();
++      }
+     }
+-
+-    public void set(Object o)
++    public Object first()
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return ss.first();
++      }
++    }
++    public Object last()
++    {
++      synchronized(sync)
++      {
++	return ss.last();
++      }
++    }
++    public SortedSet headSet(Object toElement)
++    {
++      synchronized(sync)
++      {
++	return new SynchronizedSortedSet(sync, ss.headSet(toElement));
++      }
++    }
++    public SortedSet tailSet(Object fromElement)
++    {
++      synchronized(sync)
++      {
++	return new SynchronizedSortedSet(sync, ss.tailSet(fromElement));
++      }
++    }
++    public SortedSet subSet(Object fromElement, Object toElement)
++    {
++      synchronized(sync)
++      {
++	return new SynchronizedSortedSet(sync,
++					 ss.subSet(fromElement, toElement));
++      }
+     }
+-  } // class UnmodifiableListIterator
+-
+-  /**
+-   * Returns an unmodifiable view of the given map. This allows "read-only"
+-   * access, although changes in the backing map show up in this view.
+-   * Attempts to modify the map directly, or via collection views or their
+-   * iterators will fail with {@link UnsupportedOperationException}.
+-   * <p>
+-   *
+-   * The returned Map implements Serializable, but can only be serialized if
+-   * the map it wraps is likewise Serializable.
+-   *
+-   * @param m the map to wrap
+-   * @return a read-only view of the map
+-   * @see Serializable
+-   */
+-  public static Map unmodifiableMap(Map m)
+-  {
+-    return new UnmodifiableMap(m);
+   }
+ 
+-  /**
+-   * The implementation of {@link #unmodifiableMap(Map)}. This
+-   * class name is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static class UnmodifiableMap implements Map, Serializable
++  private static class SynchronizedMap implements Map, Serializable
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -1034234728574286014L;
+-
+-    /**
+-     * The wrapped map.
+-     * @serial the real map
+-     */
+-    private final Map m;
+-
+-    /**
+-     * Cache the entry set.
+-     */
+-    private transient Set entries;
+-
+-    /**
+-     * Cache the key set.
+-     */
+-    private transient Set keys;
+-
+-    /**
+-     * Cache the value collection.
+-     */
+-    private transient Collection values;
+-
+-    /**
+-     * Wrap a given map.
+-     * @param m the map to wrap
+-     * @throws NullPointerException if m is null
+-     */
+-    UnmodifiableMap(Map m)
++    Object sync;
++    Map m;
++
++    public SynchronizedMap(Object sync, Map m)
++    {
++      this.sync = sync;
++      this.m = m;
++    }
++    public SynchronizedMap(Map m)
+     {
+       this.m = m;
+-      if (m == null)
+-        throw new NullPointerException();
++      this.sync = this;
+     }
+ 
+     public void clear()
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	m.clear();
++      }
+     }
+-
+     public boolean containsKey(Object key)
+     {
+-      return m.containsKey(key);
++      synchronized(sync)
++      {
++	return m.containsKey(key);
++      }
+     }
+-
+     public boolean containsValue(Object value)
+     {
+-      return m.containsValue(value);
++      synchronized(sync)
++      {
++	return m.containsValue(value);
++      }
+     }
+ 
++    // This is one of the ickiest cases of nesting I've ever seen. It just
++    // means "return a SynchronizedSet, except that the iterator() method
++    // returns an SynchronizedIterator whos next() method returns a
++    // synchronized wrapper around its normal return value".
+     public Set entrySet()
+     {
+-      if (entries == null)
+-        entries = new UnmodifiableEntrySet(m.entrySet());
+-      return entries;
+-    }
+-
+-    /**
+-     * The implementation of {@link UnmodifiableMap#entrySet()}. This class
+-     * name is required for compatibility with Sun's JDK serializability.
+-     *
+-     * @author Eric Blake <ebb9@email.byu.edu>
+-     */
+-    private static final class UnmodifiableEntrySet extends UnmodifiableSet
+-      implements Serializable
+-    {
+-      /**
+-       * Compatible with JDK 1.4.
+-       */
+-      private static final long serialVersionUID = 7854390611657943733L;
+-
+-      /**
+-       * Wrap a given set.
+-       * @param s the set to wrap
+-       */
+-      UnmodifiableEntrySet(Set s)
+-      {
+-        super(s);
+-      }
+-
+-      // The iterator must return unmodifiable map entries.
+-      public Iterator iterator()
++      synchronized(sync)
+       {
+-        return new UnmodifiableIterator(c.iterator())
++	return new SynchronizedSet(sync, m.entrySet())
+ 	{
+-          public Object next()
+-          {
+-            final Map.Entry e = (Map.Entry) super.next();
+-            return new Map.Entry()
++	  public Iterator iterator()
++	  {
++	    synchronized(SynchronizedMap.this.sync)
+ 	    {
+-              public boolean equals(Object o)
+-              {
+-                return e.equals(o);
+-              }
+-              public Object getKey()
+-              {
+-                return e.getKey();
+-              }
+-              public Object getValue()
+-              {
+-                return e.getValue();
+-              }
+-              public int hashCode()
+-              {
+-                return e.hashCode();
+-              }
+-              public Object setValue(Object value)
+-              {
+-                throw new UnsupportedOperationException();
+-              }
+-              public String toString()
+-              {
+-                return e.toString();
+-              }
+-	    };
+-          }
++	      return new SynchronizedIterator(SynchronizedMap.this.sync,
++					      c.iterator())
++	      {
++		public Object next()
++		{
++		  synchronized(SynchronizedMap.this.sync)
++		  {
++		    final Map.Entry e = (Map.Entry) super.next();
++		    return new Map.Entry()
++		    {
++		      public Object getKey()
++		      {
++			synchronized(SynchronizedMap.this.sync)
++			{
++			  return e.getKey();
++			}
++		      }
++		      public Object getValue()
++		      {
++			synchronized(SynchronizedMap.this.sync)
++			{
++			  return e.getValue();
++			}
++		      }
++		      public Object setValue(Object value)
++		      {
++			synchronized(SynchronizedMap.this.sync)
++			{
++			  return e.setValue(value);
++			}
++		      }
++		      public int hashCode()
++		      {
++			synchronized(SynchronizedMap.this.sync)
++			{
++			  return e.hashCode();
++			}
++		      }
++		      public boolean equals(Object o)
++		      {
++			synchronized(SynchronizedMap.this.sync)
++			{
++			  return e.equals(o);
++			}
++		      }
++		    };
++		  }
++		}
++	      };
++	    }
++	  }
+ 	};
+       }
+-    } // class UnmodifiableEntrySet
+-
++    }
+     public boolean equals(Object o)
+     {
+-      return m.equals(o);
++      synchronized(sync)
++      {
++	return m.equals(o);
++      }
+     }
+-
+     public Object get(Object key)
+     {
+-      return m.get(key);
++      synchronized(sync)
++      {
++	return m.get(key);
++      }
+     }
+-
+     public Object put(Object key, Object value)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return m.put(key, value);
++      }
+     }
+-
+     public int hashCode()
+     {
+-      return m.hashCode();
++      synchronized(sync)
++      {
++	return m.hashCode();
++      }
+     }
+-
+     public boolean isEmpty()
+     {
+-      return m.isEmpty();
++      synchronized(sync)
++      {
++	return m.isEmpty();
++      }
+     }
+-
+     public Set keySet()
+     {
+-      if (keys == null)
+-        keys = new UnmodifiableSet(m.keySet());
+-      return keys;
++      synchronized(sync)
++      {
++	return new SynchronizedSet(sync, m.keySet());
++      }
+     }
+-
+-    public void putAll(Map m)
++    public void putAll(Map map)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	m.putAll(map);
++      }
+     }
+-
+     public Object remove(Object o)
+     {
+-      throw new UnsupportedOperationException();
++      synchronized(sync)
++      {
++	return m.remove(o);
++      }
+     }
+ 
+     public int size()
+     {
+-      return m.size();
++      synchronized(sync)
++      {
++	return m.size();
++      }
+     }
+-
+-    public String toString()
++    public Collection values()
+     {
+-      return m.toString();
++      synchronized(sync)
++      {
++	return new SynchronizedCollection(sync, m.values());
++      }
+     }
+-
+-    public Collection values()
++    public String toString()
+     {
+-      if (values == null)
+-        values = new UnmodifiableCollection(m.values());
+-      return values;
++      synchronized(sync)
++      {
++	return m.toString();
++      }
+     }
+-  } // class UnmodifiableMap
+-
+-  /**
+-   * Returns an unmodifiable view of the given set. This allows
+-   * "read-only" access, although changes in the backing set show up
+-   * in this view. Attempts to modify the set directly or via iterators
+-   * will fail with {@link UnsupportedOperationException}.
+-   * <p>
+-   *
+-   * The returned Set implements Serializable, but can only be serialized if
+-   * the set it wraps is likewise Serializable.
+-   *
+-   * @param s the set to wrap
+-   * @return a read-only view of the set
+-   * @see Serializable
+-   */
+-  public static Set unmodifiableSet(Set s)
+-  {
+-    return new UnmodifiableSet(s);
+   }
+ 
+-  /**
+-   * The implementation of {@link #unmodifiableSet(Set)}. This class
+-   * name is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static class UnmodifiableSet extends UnmodifiableCollection
+-    implements Set
++  private static class SynchronizedSortedMap extends SynchronizedMap
++    implements SortedMap
+   {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -9215047833775013803L;
+-
+-    /**
+-     * Wrap a given set.
+-     * @param s the set to wrap
+-     * @throws NullPointerException if s is null
+-     */
+-    UnmodifiableSet(Set s)
+-    {
+-      super(s);
+-    }
++    // This is stored both here and in the superclass, to avoid excessive
++    // casting.
++    private SortedMap sm;
+ 
+-    public boolean equals(Object o)
++    public SynchronizedSortedMap(Object sync, SortedMap sm)
+     {
+-      return c.equals(o);
++      super(sync, sm);
++      this.sm = sm;
+     }
+-
+-    public int hashCode()
+-    {
+-      return c.hashCode();
+-    }
+-  } // class UnmodifiableSet
+-
+-  /**
+-   * Returns an unmodifiable view of the given sorted map. This allows
+-   * "read-only" access, although changes in the backing map show up in this
+-   * view. Attempts to modify the map directly, via subviews, via collection
+-   * views, or iterators, will fail with {@link UnsupportedOperationException}.
+-   * <p>
+-   *
+-   * The returned SortedMap implements Serializable, but can only be
+-   * serialized if the map it wraps is likewise Serializable.
+-   *
+-   * @param m the map to wrap
+-   * @return a read-only view of the map
+-   * @see Serializable
+-   */
+-  public static SortedMap unmodifiableSortedMap(SortedMap m)
+-  {
+-    return new UnmodifiableSortedMap(m);
+-  }
+-
+-  /**
+-   * The implementation of {@link #unmodifiableSortedMap(SortedMap)}. This
+-   * class name is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static class UnmodifiableSortedMap extends UnmodifiableMap
+-    implements SortedMap
+-  {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -8806743815996713206L;
+-
+-    /**
+-     * The wrapped map; stored both here and in the superclass to avoid
+-     * excessive casting.
+-     * @serial the wrapped map
+-     */
+-    private final SortedMap sm;
+-
+-    /**
+-     * Wrap a given map.
+-     * @param sm the map to wrap
+-     * @throws NullPointerException if sm is null
+-     */
+-    UnmodifiableSortedMap(SortedMap sm)
++    public SynchronizedSortedMap(SortedMap sm)
+     {
+       super(sm);
+       this.sm = sm;
+@@ -3576,114 +1827,36 @@
+ 
+     public Comparator comparator()
+     {
+-      return sm.comparator();
++      synchronized(sync)
++      {
++	return sm.comparator();
++      }
+     }
+-
+     public Object firstKey()
+     {
+-      return sm.firstKey();
+-    }
+-
+-    public SortedMap headMap(Object toKey)
+-    {
+-      return new UnmodifiableSortedMap(sm.headMap(toKey));
++      synchronized(sync)
++      {
++	return sm.firstKey();
++      }
+     }
+-
+     public Object lastKey()
+     {
+-      return sm.lastKey();
++      synchronized(sync)
++      {
++	return sm.lastKey();
++      }
+     }
+-
+-    public SortedMap subMap(Object fromKey, Object toKey)
++    public SortedMap headMap(Object toKey)
+     {
+-      return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey));
++      return new SynchronizedSortedMap(sync, sm.headMap(toKey));
+     }
+-
+     public SortedMap tailMap(Object fromKey)
+     {
+-      return new UnmodifiableSortedMap(sm.tailMap(fromKey));
+-    }
+-  } // class UnmodifiableSortedMap
+-
+-  /**
+-   * Returns an unmodifiable view of the given sorted set. This allows
+-   * "read-only" access, although changes in the backing set show up
+-   * in this view. Attempts to modify the set directly, via subsets, or via
+-   * iterators, will fail with {@link UnsupportedOperationException}.
+-   * <p>
+-   *
+-   * The returns SortedSet implements Serializable, but can only be
+-   * serialized if the set it wraps is likewise Serializable.
+-   *
+-   * @param s the set to wrap
+-   * @return a read-only view of the set
+-   * @see Serializable
+-   */
+-  public static SortedSet unmodifiableSortedSet(SortedSet s)
+-  {
+-    return new UnmodifiableSortedSet(s);
+-  }
+-
+-  /**
+-   * The implementation of {@link #synchronizedSortedMap(SortedMap)}. This
+-   * class name is required for compatibility with Sun's JDK serializability.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static class UnmodifiableSortedSet extends UnmodifiableSet
+-    implements SortedSet
+-  {
+-    /**
+-     * Compatible with JDK 1.4.
+-     */
+-    private static final long serialVersionUID = -4929149591599911165L;
+-
+-    /**
+-     * The wrapped set; stored both here and in the superclass to avoid
+-     * excessive casting.
+-     * @serial the wrapped set
+-     */
+-    private SortedSet ss;
+-
+-    /**
+-     * Wrap a given set.
+-     * @param ss the set to wrap
+-     * @throws NullPointerException if ss is null
+-     */
+-    UnmodifiableSortedSet(SortedSet ss)
+-    {
+-      super(ss);
+-      this.ss = ss;
+-    }
+-
+-    public Comparator comparator()
+-    {
+-      return ss.comparator();
+-    }
+-
+-    public Object first()
+-    {
+-      return ss.first();
+-    }
+-
+-    public SortedSet headSet(Object toElement)
+-    {
+-      return new UnmodifiableSortedSet(ss.headSet(toElement));
+-    }
+-
+-    public Object last()
+-    {
+-      return ss.last();
+-    }
+-
+-    public SortedSet subSet(Object fromElement, Object toElement)
+-    {
+-      return new UnmodifiableSortedSet(ss.subSet(fromElement, toElement));
++      return new SynchronizedSortedMap(sync, sm.tailMap(fromKey));
+     }
+-
+-    public SortedSet tailSet(Object fromElement)
++    public SortedMap subMap(Object fromKey, Object toKey)
+     {
+-      return new UnmodifiableSortedSet(ss.tailSet(fromElement));
++      return new SynchronizedSortedMap(sync, sm.subMap(fromKey, toKey));
+     }
+-  } // class UnmodifiableSortedSet
+-} // class Collections
++  }
++}
Index: compare/java.util.ConcurrentModificationException.diff
===================================================================
RCS file: java.util.ConcurrentModificationException.diff
diff -N java.util.ConcurrentModificationException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.ConcurrentModificationException.diff Tue Nov 6 17:21:32 2001
@@ -0,0 +1,51 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/ConcurrentModificationException.java	Mon Oct 22 22:24:19 2001
++++ java/util/ConcurrentModificationException.java	Tue Oct 16 09:14:34 2001
+@@ -30,6 +30,7 @@
+ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+  * "The Java Language Specification", ISBN 0-201-63451-1
+  * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
++ * Status:  Believed complete and correct.
+  */
+ 
+ /**
+@@ -37,29 +38,15 @@
+  * a modification has been made to a data structure when this is not allowed,
+  * such as when a collection is structurally modified while an Iterator is
+  * operating over it. In cases where this can be detected, a
+- * ConcurrentModificationException will be thrown. An Iterator that detects
+- * this condition is referred to as fail-fast. Notice that this can occur
+- * even in single-threaded designs, if you call methods out of order.
++ * ConcurrentModificationException will be thrown. An Iterator that detects this
++ * condition is referred to as fail-fast.
+  *
+  * @author Warren Levy <warrenl@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see Iterator
+- * @see ListIterator
+- * @see Vector
+- * @see LinkedList
+- * @see HashSet
+- * @see Hashtable
+- * @see TreeMap
+- * @see AbstractList
++ * @date September 2, 1998.
+  * @since 1.2
+- * @status updated to 1.4
+  */
+ public class ConcurrentModificationException extends RuntimeException
+ {
+-  /**
+-   * Compatible with JDK 1.2.
+-   */
+   private static final long serialVersionUID = -3666751008965953603L;
+ 
+   /**
+@@ -67,6 +54,7 @@
+    */
+   public ConcurrentModificationException()
+   {
++    super();
+   }
+ 
+   /**
Index: compare/java.util.Dictionary.diff
===================================================================
RCS file: java.util.Dictionary.diff
diff -N java.util.Dictionary.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Dictionary.diff Tue Nov 6 17:21:32 2001
@@ -0,0 +1,116 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Dictionary.java	Fri Oct 26 16:06:57 2001
++++ java/util/Dictionary.java	Tue Oct 16 09:14:34 2001
+@@ -1,6 +1,6 @@
+ /* Dictionary.java -- an abstract (and essentially worthless) 
+    class which is Hashtable's superclass
+-   Copyright (C) 1998, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -35,88 +35,49 @@
+  * This is an abstract class which has really gone by the wayside.
+  * People at Javasoft are probably embarrassed by it.  At this point,
+  * it might as well be an interface rather than a class, but it remains
+- * this poor, laughable skeleton for the sake of backwards compatibility.
++ * this poor, laugable skeleton for the sake of backwards compatibility.
+  * At any rate, this was what came before the <pre>Map</pre> interface 
+  * in the Collections framework.
+  *
+- * @author Jon Zeppieri
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Map
+- * @see Hashtable
+- * @since 1.0
+- * @status updated to 1.4
++ * @author      Jon Zeppieri
+  */
+ public abstract class Dictionary extends Object
+ {
+-  /**
+-   * Sole constructor (often called implicitly).
+-   */
+-  public Dictionary()
+-  {
+-  }
+-
+-  /**
+-   * Returns an Enumeration of the values in this Dictionary.
+-   *
+-   * @return an Enumeration of the values
+-   * @see #keys()
+-   */
++  /** returns an Enumeration of the values in this Dictionary */
+   public abstract Enumeration elements();
+ 
+   /** 
+-   * Returns the value associated with the supplied key, or null
+-   * if no such value exists. Since Dictionaries are not allowed null keys
+-   * or elements, a null result always means the key is not present.
++   * returns the value associated with the supplied key, or null
++   * if no such value exists
+    *
+-   * @param key the key to use to fetch the value
+-   * @return the mapped value
+-   * @throws NullPointerException if key is null
+-   * @see #put(Object, Object)
++   * @param    key      the key to use to fetch the value
+    */
+   public abstract Object get(Object key);
+ 
+-  /**
+-   * Returns true when there are no elements in this Dictionary.
+-   *
+-   * @return <code>size() == 0</code>
+-   */
++  /** returns true IFF there are no elements in this Dictionary (size() == 0) */
+   public abstract boolean isEmpty();
+ 
+-  /**
+-   * Returns an Enumeration of the keys in this Dictionary
+-   *
+-   * @return an Enumeration of the keys
+-   * @see #elements()
+-   */
++  /** returns an Enumeration of the keys in this Dictionary */
+   public abstract Enumeration keys();
+ 
+   /**
+-   * Inserts a new value into this Dictionary, located by the
+-   * supplied key. Dictionary does not support null keys or values, so
+-   * a null return can safely be interpreted as adding a new key.
++   * inserts a new value into this Dictionary, located by the
++   * supllied key; note: Dictionary's subclasses (all 1 of them)
++   * do not support null keys or values (I can only assume this
++   * would have been more general) 
+    *
+-   * @param key the key which locates the value
+-   * @param value the value to put into the Dictionary
+-   * @return the previous value of the key, or null if there was none
+-   * @throws NullPointerException if key or value is null
+-   * @see #get(Object)
++   * @param      key      the key which locates the value
++   * @param      value    the value to put into the Dictionary
+    */
+   public abstract Object put(Object key, Object value);
+ 
+   /**
+-   * Removes from the Dictionary the value located by the given key. A null
+-   * return safely means that the key was not mapped in the Dictionary.
++   * removes fro the Dictionary the value located by the given key
+    *
+-   * @param key the key used to locate the value to be removed
+-   * @return the value associated with the removed key
+-   * @throws NullPointerException if key is null
++   * @param       key      the key used to locate the value to be removed
+    */
+   public abstract Object remove(Object key);
+ 
+-  /**
+-   * Returns the number of values currently in this Dictionary.
+-   *
+-   * @return the number of keys in the Dictionary
+-   */
++  /** returns the number of values currently in this Dictionary */
+   public abstract int size();
+ }
Index: compare/java.util.EmptyStackException.diff
===================================================================
RCS file: java.util.EmptyStackException.diff
diff -N java.util.EmptyStackException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.EmptyStackException.diff Tue Nov 6 17:21:32 2001
@@ -0,0 +1,35 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/EmptyStackException.java	Mon Oct 22 22:24:19 2001
++++ java/util/EmptyStackException.java	Tue Oct 16 09:14:34 2001
+@@ -30,6 +30,7 @@
+ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+  * "The Java Language Specification", ISBN 0-201-63451-1
+  * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
++ * Status:  Believed complete and correct.
+  */
+ 
+ /**
+@@ -37,16 +38,10 @@
+  * or otherwise access elements from an empty stack.
+  *
+  * @author Warren Levy <warrenl@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Stack
+- * @since 1.0
+- * @status updated to 1.4
++ * @date September 2, 1998.
+  */
+ public class EmptyStackException extends RuntimeException
+ {
+-  /**
+-   * Compatible with JDK 1.0.
+-   */
+   private static final long serialVersionUID = 5084686378493302095L;
+ 
+   /**
+@@ -54,5 +49,6 @@
+    */
+   public EmptyStackException()
+   {
++    super();
+   }
+ }
Index: compare/java.util.GregorianCalendar.diff
===================================================================
RCS file: java.util.GregorianCalendar.diff
diff -N java.util.GregorianCalendar.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.GregorianCalendar.diff Tue Nov 6 17:21:32 2001
@@ -0,0 +1,38 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/GregorianCalendar.java	Mon Oct 22 22:23:29 2001
++++ java/util/GregorianCalendar.java	Fri Nov  2 21:44:52 2001
+@@ -216,7 +216,7 @@
+    * Get the linear time in milliseconds since the epoch.  If you
+    * specify a nonpositive year it is interpreted as BC as
+    * following: 0 is 1 BC, -1 is 2 BC and so on.  The date is
+-   * interpreted as gregorian if the change occured before that date.
++   * interpreted as gregorian if the change occurred before that date.
+    *
+    * @param year the year of the date.
+    * @param dayOfYear the day of year of the date; 1 based.
+@@ -627,7 +627,7 @@
+    * Compares the given calender with this.  
+    * @param o the object to that we should compare.
+    * @return true, if the given object is a calendar, that represents
+-   * the same time (but doesn't neccessary have the same fields).
++   * the same time (but doesn't necessary have the same fields).
+    * @XXX Should we check if time zones, locale, cutover etc. are equal?
+    */
+   public boolean equals(Object o)
+@@ -973,7 +973,7 @@
+ 
+   /**
+    * Gets the actual minimum value that is allowed for the specified field.
+-   * This value is dependant on the values of the other fields.  Note that
++   * This value is dependent on the values of the other fields.  Note that
+    * this calls <code>complete()</code> if not enough fields are set.  This
+    * can have ugly side effects.
+    * @param field the time field. One of the time field constants.
+@@ -1001,7 +1001,7 @@
+ 
+   /**
+    * Gets the actual maximum value that is allowed for the specified field.
+-   * This value is dependant on the values of the other fields.  Note that
++   * This value is dependent on the values of the other fields.  Note that
+    * this calls <code>complete()</code> if not enough fields are set.  This
+    * can have ugly side effects.
+    * @param field the time field. One of the time field constants.
Index: compare/java.util.HashMap.diff
===================================================================
RCS file: java.util.HashMap.diff
diff -N java.util.HashMap.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.HashMap.diff Tue Nov 6 17:21:32 2001
@@ -0,0 +1,836 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/HashMap.java	Fri Oct 26 16:06:57 2001
++++ java/util/HashMap.java	Fri Nov  2 21:44:52 2001
+@@ -53,16 +53,14 @@
+  * <p>
+  *
+  * Under ideal circumstances (no collisions), HashMap offers O(1)
+- * performance on most operations (<code>containsValue()</code> is,
++ * performance on most operations (<pre>containsValue()</pre> is,
+  * of course, O(n)).  In the worst case (all keys map to the same
+  * hash code -- very unlikely), most operations are O(n).
+  * <p>
+  *
+  * HashMap is part of the JDK1.2 Collections API.  It differs from
+  * Hashtable in that it accepts the null key and null values, and it
+- * does not support "Enumeration views." Also, it is not synchronized;
+- * if you plan to use it in multiple threads, consider using:<br>
+- * <code>Map m = Collections.synchronizedMap(new HashMap(...));</code>
++ * does not support "Enumeration views."
+  * <p>
+  *
+  * The iterators are <i>fail-fast</i>, meaning that any structural
+@@ -83,7 +81,6 @@
+  * @see IdentityHashMap
+  * @see Hashtable
+  * @since 1.2
+- * @status updated to 1.4
+  */
+ public class HashMap extends AbstractMap
+   implements Map, Cloneable, Serializable
+@@ -91,16 +88,19 @@
+   /**
+    * Default number of buckets. This is the value the JDK 1.3 uses. Some
+    * early documentation specified this value as 101. That is incorrect.
+-   * Package visible for use by HashSet.
+    */
+   static final int DEFAULT_CAPACITY = 11;
+ 
+   /**
+    * The default load factor; this is explicitly specified by the spec.
+-   * Package visible for use by HashSet.
+    */
+   static final float DEFAULT_LOAD_FACTOR = 0.75f;
+ 
++  /** "enum" of iterator types. */
++  static final int KEYS = 0,
++                   VALUES = 1,
++                   ENTRIES = 2;
++
+   /**
+    * Compatible with JDK 1.2.
+    */
+@@ -108,54 +108,41 @@
+ 
+   /**
+    * The rounded product of the capacity and the load factor; when the number
+-   * of elements exceeds the threshold, the HashMap calls
+-   * <code>rehash()</code>.
+-   * @serial the threshold for rehashing
++   * of elements exceeds the threshold, the HashMap calls <pre>rehash()</pre>.
++   * @serial
+    */
+-  private int threshold;
++  int threshold;
+ 
+   /**
+    * Load factor of this HashMap:  used in computing the threshold.
+-   * Package visible for use by HashSet.
+-   * @serial the load factor
++   * @serial
+    */
+   final float loadFactor;
+ 
+   /**
+    * Array containing the actual key-value mappings.
+-   * Package visible for use by nested and subclasses.
+    */
+   transient HashEntry[] buckets;
+ 
+   /**
+    * Counts the number of modifications this HashMap has undergone, used
+    * by Iterators to know when to throw ConcurrentModificationExceptions.
+-   * Package visible for use by nested and subclasses.
+    */
+   transient int modCount;
+ 
+   /**
+    * The size of this HashMap:  denotes the number of key-value pairs.
+-   * Package visible for use by nested and subclasses.
+    */
+   transient int size;
+ 
+   /**
+-   * The cache for {@link #entrySet()}.
+-   */
+-  private transient Set entries;
+-
+-  /**
+    * Class to represent an entry in the hash table. Holds a single key-value
+-   * pair. Package visible for use by subclass.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
++   * pair.  This is extended again in LinkedHashMap.  See {@link clone()}
++   * for why this must be Cloneable.
+    */
+-  static class HashEntry extends BasicMapEntry
++  static class HashEntry extends BasicMapEntry implements Cloneable
+   {
+-    /**
+-     * The next entry in the linked list. Package visible for use by subclass.
+-     */
++    /** The next entry in the linked list. */
+     HashEntry next;
+ 
+     /**
+@@ -171,8 +158,7 @@
+     /**
+      * Called when this entry is removed from the map. This version simply
+      * returns the value, but in LinkedHashMap, it must also do bookkeeping.
+-     *
+-     * @return the value of this key as it is removed
++     * @return the value of this key as it is removed.
+      */
+     Object cleanup()
+     {
+@@ -196,8 +182,9 @@
+    *
+    * Every element in Map m will be put into this new HashMap.
+    *
+-   * @param m a Map whose key / value pairs will be put into the new HashMap.
+-   *        <b>NOTE: key / value pairs are not cloned in this constructor.</b>
++   * @param m a Map whose key / value pairs will be put into
++   *          the new HashMap.  <b>NOTE: key / value pairs
++   *          are not cloned in this constructor.</b>
+    * @throws NullPointerException if m is null
+    */
+   public HashMap(Map m)
+@@ -210,8 +197,8 @@
+    * Construct a new HashMap with a specific inital capacity and
+    * default load factor of 0.75.
+    *
+-   * @param initialCapacity the initial capacity of this HashMap (&gt;=0)
+-   * @throws IllegalArgumentException if (initialCapacity &lt; 0)
++   * @param initialCapacity the initial capacity of this HashMap (>=0)
++   * @throws IllegalArgumentException if (initialCapacity < 0)
+    */
+   public HashMap(int initialCapacity)
+   {
+@@ -221,10 +208,10 @@
+   /**
+    * Construct a new HashMap with a specific inital capacity and load factor.
+    *
+-   * @param initialCapacity the initial capacity (&gt;=0)
+-   * @param loadFactor the load factor (&gt; 0, not NaN)
+-   * @throws IllegalArgumentException if (initialCapacity &lt; 0) ||
+-   *                                     ! (loadFactor &gt; 0.0)
++   * @param initialCapacity the initial capacity (>=0)
++   * @param loadFactor the load factor (>0, not NaN)
++   * @throws IllegalArgumentException if (initialCapacity < 0) ||
++   *                                     ! (loadFactor > 0.0)
+    */
+   public HashMap(int initialCapacity, float loadFactor)
+   {
+@@ -242,8 +229,7 @@
+   }
+ 
+   /**
+-   * Returns the number of kay-value mappings currently in this Map.
+-   *
++   * Returns the number of kay-value mappings currently in this Map
+    * @return the size
+    */
+   public int size()
+@@ -252,8 +238,7 @@
+   }
+ 
+   /**
+-   * Returns true if there are no key-value mappings currently in this Map.
+-   *
++   * Returns true if there are no key-value mappings currently in this Map
+    * @return <code>size() == 0</code>
+    */
+   public boolean isEmpty()
+@@ -262,31 +247,29 @@
+   }
+ 
+   /**
+-   * Return the value in this HashMap associated with the supplied key,
+-   * or <code>null</code> if the key maps to nothing.  NOTE: Since the value
+-   * could also be null, you must use containsKey to see if this key
+-   * actually maps to something.
++   * Returns true if this HashMap contains a value <pre>o</pre>, such that
++   * <pre>o.equals(value)</pre>.
+    *
+-   * @param key the key for which to fetch an associated value
+-   * @return what the key maps to, if present
+-   * @see #put(Object, Object)
+-   * @see #containsKey(Object)
++   * @param value the value to search for in this HashMap
++   * @return true if at least one key maps to the value
+    */
+-  public Object get(Object key)
++  public boolean containsValue(Object value)
+   {
+-    int idx = hash(key);
+-    HashEntry e = buckets[idx];
+-    while (e != null)
++    for (int i = buckets.length - 1; i >= 0; i--)
+       {
+-        if (equals(key, e.key))
+-          return e.value;
+-        e = e.next;
++        HashEntry e = buckets[i];
++        while (e != null)
++          {
++            if (value == null ? e.value == null : value.equals(e.value))
++              return true;
++            e = e.next;
++          }
+       }
+-    return null;
++    return false;
+   }
+ 
+   /**
+-   * Returns true if the supplied object <code>equals()</code> a key
++   * Returns true if the supplied object <pre>equals()</pre> a key
+    * in this HashMap.
+    *
+    * @param key the key to search for in this HashMap
+@@ -299,7 +282,7 @@
+     HashEntry e = buckets[idx];
+     while (e != null)
+       {
+-        if (equals(key, e.key))
++        if (key == null ? e.key == null : key.equals(e.key))
+           return true;
+         e = e.next;
+       }
+@@ -307,6 +290,30 @@
+   }
+ 
+   /**
++   * Return the value in this HashMap associated with the supplied key,
++   * or <pre>null</pre> if the key maps to nothing.  NOTE: Since the value
++   * could also be null, you must use containsKey to see if this key
++   * actually maps to something.
++   *
++   * @param key the key for which to fetch an associated value
++   * @return what the key maps to, if present
++   * @see #put(Object, Object)
++   * @see #containsKey(Object)
++   */
++  public Object get(Object key)
++  {
++    int idx = hash(key);
++    HashEntry e = buckets[idx];
++    while (e != null)
++      {
++        if (key == null ? e.key == null : key.equals(e.key))
++          return e.value;
++        e = e.next;
++      }
++    return null;
++  }
++
++  /**
+    * Puts the supplied value into the Map, mapped by the supplied key.
+    * The value may be retrieved by any object which <code>equals()</code>
+    * this key. NOTE: Since the prior value could also be null, you must
+@@ -321,12 +328,13 @@
+    */
+   public Object put(Object key, Object value)
+   {
++    modCount++;
+     int idx = hash(key);
+     HashEntry e = buckets[idx];
+ 
+     while (e != null)
+       {
+-        if (equals(key, e.key))
++        if (key == null ? e.key == null : key.equals(e.key))
+           // Must use this method for necessary bookkeeping in LinkedHashMap.
+           return e.setValue(value);
+         else
+@@ -334,7 +342,6 @@
+       }
+ 
+     // At this point, we know we need to add a new entry.
+-    modCount++;
+     if (++size > threshold)
+       {
+         rehash();
+@@ -348,36 +355,27 @@
+   }
+ 
+   /**
+-   * Copies all elements of the given map into this hashtable.  If this table
+-   * already has a mapping for a key, the new mapping replaces the current
+-   * one.
++   * Helper method for put, that creates and adds a new Entry.  This is
++   * overridden in LinkedHashMap for bookkeeping purposes.
+    *
+-   * @param m the map to be hashed into this
++   * @param key the key of the new Entry
++   * @param value the value
++   * @param idx the index in buckets where the new Entry belongs
++   * @param callRemove Whether to call the removeEldestEntry method.
++   * @see #put(Object, Object)
+    */
+-  public void putAll(Map m)
++  void addEntry(Object key, Object value, int idx, boolean callRemove)
+   {
+-    Iterator itr = m.entrySet().iterator();
++    HashEntry e = new HashEntry(key, value);
+ 
+-    for (int msize = m.size(); msize > 0; msize--)
+-      {
+-        Map.Entry e = (Map.Entry) itr.next();
+-        // Optimize in case the Entry is one of our own.
+-        if (e instanceof BasicMapEntry)
+-          {
+-            BasicMapEntry entry = (BasicMapEntry) e;
+-            put(entry.key, entry.value);
+-          }
+-        else
+-          {
+-            put(e.getKey(), e.getValue());
+-          }
+-      }
++    e.next = buckets[idx];
++    buckets[idx] = e;
+   }
+-  
++
+   /**
+    * Removes from the HashMap and returns the value which is mapped by the
+    * supplied key. If the key maps to nothing, then the HashMap remains
+-   * unchanged, and <code>null</code> is returned. NOTE: Since the value
++   * unchanged, and <pre>null</pre> is returned. NOTE: Since the value
+    * could also be null, you must use containsKey to see if you are
+    * actually removing a mapping.
+    *
+@@ -386,15 +384,15 @@
+    */
+   public Object remove(Object key)
+   {
++    modCount++;
+     int idx = hash(key);
+     HashEntry e = buckets[idx];
+     HashEntry last = null;
+ 
+     while (e != null)
+       {
+-        if (equals(key, e.key))
++        if (key == null ? e.key == null : key.equals(e.key))
+           {
+-            modCount++;
+             if (last == null)
+               buckets[idx] = e.next;
+             else
+@@ -410,39 +408,40 @@
+   }
+ 
+   /**
+-   * Clears the Map so it has no keys. This is O(1).
++   * Copies all elements of the given map into this hashtable.  If this table
++   * already has a mapping for a key, the new mapping replaces the current
++   * one.
++   *
++   * @param m the map to be hashed into this
+    */
+-  public void clear()
++  public void putAll(Map m)
+   {
+-    if (size != 0)
++    Iterator itr = m.entrySet().iterator();
++
++    for (int msize = m.size(); msize > 0; msize--)
+       {
+-        modCount++;
+-        Arrays.fill(buckets, null);
+-        size = 0;
++        Map.Entry e = (Map.Entry) itr.next();
++        // Optimize in case the Entry is one of our own.
++        if (e instanceof BasicMapEntry)
++          {
++            BasicMapEntry entry = (BasicMapEntry) e;
++            put(entry.key, entry.value);
++          }
++        else
++          {
++            put(e.getKey(), e.getValue());
++          }
+       }
+   }
+-
++  
+   /**
+-   * Returns true if this HashMap contains a value <code>o</code>, such that
+-   * <code>o.equals(value)</code>.
+-   *
+-   * @param value the value to search for in this HashMap
+-   * @return true if at least one key maps to the value
+-   * @see containsKey(Object)
++   * Clears the Map so it has no keys. This is O(1).
+    */
+-  public boolean containsValue(Object value)
++  public void clear()
+   {
+-    for (int i = buckets.length - 1; i >= 0; i--)
+-      {
+-        HashEntry e = buckets[i];
+-        while (e != null)
+-          {
+-            if (equals(value, e.value))
+-              return true;
+-            e = e.next;
+-          }
+-      }
+-    return false;
++    modCount++;
++    Arrays.fill(buckets, null);
++    size = 0;
+   }
+ 
+   /**
+@@ -464,7 +463,6 @@
+       }
+     copy.buckets = new HashEntry[buckets.length];
+     copy.putAllInternal(this);
+-    copy.entries = null;
+     return copy;
+   }
+ 
+@@ -479,43 +477,41 @@
+    */
+   public Set keySet()
+   {
+-    if (keys == null)
+-      // Create an AbstractSet with custom implementations of those methods
+-      // that can be overridden easily and efficiently.
+-      keys = new AbstractSet()
+-      {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          // Cannot create the iterator directly, because of LinkedHashMap.
+-          return HashMap.this.iterator(KEYS);
+-        }
+-
+-        public void clear()
+-        {
+-          HashMap.this.clear();
+-        }
+-
+-        public boolean contains(Object o)
+-        {
+-          return containsKey(o);
+-        }
+-
+-        public boolean remove(Object o)
+-        {
+-          // Test against the size of the HashMap to determine if anything
+-          // really got removed. This is neccessary because the return value
+-          // of HashMap.remove() is ambiguous in the null case.
+-          int oldsize = size;
+-          HashMap.this.remove(o);
+-          return oldsize != size;
+-        }
+-      };
+-    return keys;
++    // Create an AbstractSet with custom implementations of those methods that
++    // can be overridden easily and efficiently.
++    return new AbstractSet()
++    {
++      public int size()
++      {
++        return size;
++      }
++
++      public Iterator iterator()
++      {
++        // Cannot create the iterator directly, because of LinkedHashMap.
++        return HashMap.this.iterator(KEYS);
++      }
++
++      public void clear()
++      {
++        HashMap.this.clear();
++      }
++
++      public boolean contains(Object o)
++      {
++        return HashMap.this.containsKey(o);
++      }
++
++      public boolean remove(Object o)
++      {
++        // Test against the size of the HashMap to determine if anything
++        // really got removed. This is necessary because the return value of
++        // HashMap.remove() is ambiguous in the null case.
++        int oldsize = size;
++        HashMap.this.remove(o);
++        return (oldsize != size);
++      }
++    };
+   }
+ 
+   /**
+@@ -530,34 +526,33 @@
+    */
+   public Collection values()
+   {
+-    if (values == null)
+-      // We don't bother overriding many of the optional methods, as doing so
+-      // wouldn't provide any significant performance advantage.
+-      values = new AbstractCollection()
+-      {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          // Cannot create the iterator directly, because of LinkedHashMap.
+-          return HashMap.this.iterator(VALUES);
+-        }
+-
+-        public void clear()
+-        {
+-          HashMap.this.clear();
+-        }
+-      };
+-    return values;
++    // We don't bother overriding many of the optional methods, as doing so
++    // wouldn't provide any significant performance advantage.
++    return new AbstractCollection()
++    {
++      public int size()
++      {
++        return size;
++      }
++
++      public Iterator iterator()
++      {
++        // Cannot create the iterator directly, because of LinkedHashMap.
++        return HashMap.this.iterator(VALUES);
++      }
++
++      public void clear()
++      {
++        HashMap.this.clear();
++      }
++    };
+   }
+ 
+   /**
+    * Returns a "set view" of this HashMap's entries. The set is backed by
+    * the HashMap, so changes in one show up in the other.  The set supports
+-   * element removal, but not element addition.<p>
++   * element removal, but not element addition.
++   * <p>
+    *
+    * Note that the iterators for all three views, from keySet(), entrySet(),
+    * and values(), traverse the HashMap in the same sequence.
+@@ -569,62 +564,53 @@
+    */
+   public Set entrySet()
+   {
+-    if (entries == null)
+-      // Create an AbstractSet with custom implementations of those methods
+-      // that can be overridden easily and efficiently.
+-      entries = new AbstractSet()
+-      {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          // Cannot create the iterator directly, because of LinkedHashMap.
+-          return HashMap.this.iterator(ENTRIES);
+-        }
+-
+-        public void clear()
+-        {
+-          HashMap.this.clear();
+-        }
+-
+-        public boolean contains(Object o)
+-        {
+-          return getEntry(o) != null;
+-        }
+-
+-        public boolean remove(Object o)
+-        {
+-          HashEntry e = getEntry(o);
+-          if (e != null)
+-            {
+-              HashMap.this.remove(e.key);
+-              return true;
+-            }
+-          return false;
+-        }
+-      };
+-    return entries;
++    // Create an AbstractSet with custom implementations of those methods that
++    // can be overridden easily and efficiently.
++    return new AbstractSet()
++    {
++      public int size()
++      {
++        return size;
++      }
++
++      public Iterator iterator()
++      {
++        // Cannot create the iterator directly, because of LinkedHashMap.
++        return HashMap.this.iterator(ENTRIES);
++      }
++
++      public void clear()
++      {
++        HashMap.this.clear();
++      }
++
++      public boolean contains(Object o)
++      {
++        return getEntry(o) != null;
++      }
++
++      public boolean remove(Object o)
++      {
++        HashEntry e = getEntry(o);
++        if (e != null)
++          {
++            HashMap.this.remove(e.key);
++            return true;
++          }
++        return false;
++      }
++    };
+   }
+ 
+-  /**
+-   * Helper method for put, that creates and adds a new Entry.  This is
+-   * overridden in LinkedHashMap for bookkeeping purposes.
++  /** Helper method that returns an index in the buckets array for `key;
++   * based on its hashCode().
+    *
+-   * @param key the key of the new Entry
+-   * @param value the value
+-   * @param idx the index in buckets where the new Entry belongs
+-   * @param callRemove whether to call the removeEldestEntry method
+-   * @see #put(Object, Object)
++   * @param key the key
++   * @return the bucket number
+    */
+-  void addEntry(Object key, Object value, int idx, boolean callRemove)
++  int hash(Object key)
+   {
+-    HashEntry e = new HashEntry(key, value);
+-
+-    e.next = buckets[idx];
+-    buckets[idx] = e;
++    return (key == null) ? 0 : Math.abs(key.hashCode() % buckets.length);
+   }
+ 
+   /**
+@@ -652,50 +638,6 @@
+   }
+ 
+   /**
+-   * Helper method that returns an index in the buckets array for `key'
+-   * based on its hashCode().  Package visible for use by subclasses.
+-   *
+-   * @param key the key
+-   * @return the bucket number
+-   */
+-  final int hash(Object key)
+-  {
+-    return key == null ? 0 : Math.abs(key.hashCode() % buckets.length);
+-  }
+-
+-  /**
+-   * Generates a parameterized iterator.  Must be overrideable, since
+-   * LinkedHashMap iterates in a different order.
+-   *
+-   * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
+-   * @return the appropriate iterator
+-   */
+-  Iterator iterator(int type)
+-  {
+-    return new HashIterator(type);
+-  }
+-
+-  /**
+-   * A simplified, more efficient internal implementation of putAll(). The 
+-   * Map constructor and clone() should not call putAll or put, in order to 
+-   * be compatible with the JDK implementation with respect to subclasses.
+-   *
+-   * @param m the map to initialize this from
+-   */
+-  void putAllInternal(Map m)
+-  {
+-    Iterator itr = m.entrySet().iterator();
+-
+-    for (int msize = m.size(); msize > 0; msize--)
+-      {
+-	Map.Entry e = (Map.Entry) itr.next();
+-	Object key = e.getKey();
+-	int idx = hash(key);
+-	addEntry(key, e.getValue(), idx, false);
+-      }
+-  }
+-
+-  /**
+    * Increases the size of the HashMap and rehashes all keys to new array
+    * indices; this is called when the addition of a new value would cause
+    * size() > threshold. Note that the existing Entry objects are reused in
+@@ -740,6 +682,35 @@
+   }
+ 
+   /**
++   * Generates a parameterized iterator.  Must be overrideable, since
++   * LinkedHashMap iterates in a different order.
++   * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
++   * @return the appropriate iterator
++   */
++  Iterator iterator(int type)
++  {
++    return new HashIterator(type);
++  }
++
++  /**
++   * A simplified, more efficient internal implementation of putAll(). The 
++   * Map constructor and clone() should not call putAll or put, in order to 
++   * be compatible with the JDK implementation with respect to subclasses.
++   */
++  void putAllInternal(Map m)
++  {
++    Iterator itr = m.entrySet().iterator();
++
++    for (int msize = m.size(); msize > 0; msize--)
++      {
++	Map.Entry e = (Map.Entry) itr.next();
++	Object key = e.getKey();
++	int idx = hash(key);
++	addEntry(key, e.getValue(), idx, false);
++      }
++  }
++
++  /**
+    * Serializes this object to the given stream.
+    *
+    * @param s the stream to write to
+@@ -786,6 +757,9 @@
+     // Read and use capacity.
+     buckets = new HashEntry[s.readInt()];
+     int len = s.readInt();
++    // Already happens automatically.
++    // size = 0;
++    // modCount = 0;
+ 
+     // Read and use key/value pairs.
+     for ( ; len > 0; len--)
+@@ -799,29 +773,29 @@
+    *
+    * @author Jon Zeppieri
+    */
+-  private final class HashIterator implements Iterator
++  class HashIterator implements Iterator
+   {
+     /**
+      * The type of this Iterator: {@link #KEYS}, {@link #VALUES},
+      * or {@link #ENTRIES}.
+      */
+-    private final int type;
++    final int type;
+     /**
+      * The number of modifications to the backing HashMap that we know about.
+      */
+-    private int knownMod = modCount;
++    int knownMod = modCount;
+     /** The number of elements remaining to be returned by next(). */
+-    private int count = size;
++    int count = size;
+     /** Current index in the physical hash table. */
+-    private int idx = buckets.length;
++    int idx = buckets.length;
+     /** The last Entry returned by a next() call. */
+-    private HashEntry last;
++    HashEntry last;
+     /**
+      * The next entry that should be returned by next(). It is set to something
+      * if we're iterating through a bucket that contains multiple linked
+      * entries. It is null if next() needs to find a new bucket.
+      */
+-    private HashEntry next;
++    HashEntry next;
+ 
+     /**
+      * Construct a new HashIterator with the supplied type.
+@@ -866,14 +840,14 @@
+       last = e;
+       if (type == VALUES)
+         return e.value;
+-      if (type == KEYS)
++      else if (type == KEYS)
+         return e.key;
+       return e;
+     }
+ 
+     /**
+      * Removes from the backing HashMap the last element which was fetched
+-     * with the <code>next()</code> method.
++     * with the <pre>next()</pre> method.
+      * @throws ConcurrentModificationException if the HashMap was modified
+      * @throws IllegalStateException if called when there is no last element
+      */
+@@ -885,8 +859,8 @@
+         throw new IllegalStateException();
+ 
+       HashMap.this.remove(last.key);
+-      last = null;
+       knownMod++;
++      last = null;
+     }
+   }
+ }
Index: compare/java.util.HashSet.diff
===================================================================
RCS file: java.util.HashSet.diff
diff -N java.util.HashSet.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.HashSet.diff Tue Nov 6 17:21:33 2001
@@ -0,0 +1,335 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/HashSet.java	Fri Oct 26 16:06:57 2001
++++ java/util/HashSet.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,5 @@
+-/* HashSet.java -- a class providing a HashMap-backed Set
+-   Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
++/* HashSet.java -- a class providing a HashMap-backet Set
++   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -33,115 +33,87 @@
+ import java.io.ObjectOutputStream;
+ 
+ /**
+- * This class provides a HashMap-backed implementation of the Set interface.
+- * <p>
++ * This class provides a HashMap-backed implementation of the 
++ * Set interface.
+  *
+- * Most operations are O(1), assuming no hash collisions.  In the worst
+- * case (where all hashes collide), operations are O(n). Setting the
+- * initial capacity too low will force many resizing operations, but
+- * setting the initial capacity too high (or loadfactor too low) leads
+- * to wasted memory and slower iteration.
+- * <p>
++ * Each element in the Set is a key in the backing HashMap; each key
++ * maps to a static token, denoting that the key does, in fact, exist.
+  *
+- * HashSet accepts the null key and null values.  It is not synchronized,
+- * so if you need multi-threaded access, consider using:<br>
+- * <code>Set s = Collections.synchronizedSet(new HashSet(...));</code>
+- * <p>
++ * Most operations are O(1), assuming no hash collisions.  In the worst
++ * case (where all hases collide), operations are O(n).
+  *
+- * The iterators are <i>fail-fast</i>, meaning that any structural
+- * modification, except for <code>remove()</code> called on the iterator
+- * itself, cause the iterator to throw a
+- * {@link ConcurrentModificationException} rather than exhibit
+- * non-deterministic behavior.
++ * HashSet is a part of the JDK1.2 Collections API.
+  *
+- * @author Jon Zeppieri
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see Set
+- * @see TreeSet
+- * @see Collections#synchronizedSet(Set)
+- * @see HashMap
+- * @see LinkedHashSet
+- * @since 1.2
+- * @status updated to 1.4
++ * @author      Jon Zeppieri
+  */
+ public class HashSet extends AbstractSet
+   implements Set, Cloneable, Serializable
+ {
+-  /**
+-   * Compatible with JDK 1.2.
+-   */
+-  private static final long serialVersionUID = -5024744406713321676L;
+-
+-  /**
+-   * The HashMap which backs this Set.
+-   */
+-  private transient HashMap map;
++  /** the HashMap which backs this Set */
++  transient HashMap map;
++  static final long serialVersionUID = -5024744406713321676L;
+ 
+   /**
+-   * Construct a new, empty HashSet whose backing HashMap has the default
+-   * capacity (11) and loadFacor (0.75).
++   * construct a new, empty HashSet whose backing HashMap has the default 
++   * capacity and loadFacor
+    */
+   public HashSet()
+   {
+-    this(HashMap.DEFAULT_CAPACITY, HashMap.DEFAULT_LOAD_FACTOR);
++    map = new HashMap();
+   }
+ 
+   /**
+-   * Construct a new, empty HashSet whose backing HashMap has the supplied
+-   * capacity and the default load factor (0.75).
++   * construct a new, empty HashSet whose backing HashMap has the supplied
++   * capacity and the default load factor
+    *
+-   * @param initialCapacity the initial capacity of the backing HashMap
+-   * @throws IllegalArgumentException if the capacity is negative
++   * @param          initialCapacity          the initial capacity of the backing
++   *                                          HashMap
+    */
+   public HashSet(int initialCapacity)
+   {
+-    this(initialCapacity, HashMap.DEFAULT_LOAD_FACTOR);
++    map = new HashMap(initialCapacity);
+   }
+ 
+   /**
+-   * Construct a new, empty HashSet whose backing HashMap has the supplied
+-   * capacity and load factor.
++   * construct a new, empty HashSet whose backing HashMap has the supplied
++   * capacity and load factor
+    *
+-   * @param initialCapacity the initial capacity of the backing HashMap
+-   * @param loadFactor the load factor of the backing HashMap
+-   * @throws IllegalArgumentException if either argument is negative, or
+-   *         if loadFactor is POSITIVE_INFINITY or NaN
++   * @param          initialCapacity          the initial capacity of the backing
++   *                                          HashMap
++   * @param          loadFactor               the load factor of the backing HashMap
+    */
+   public HashSet(int initialCapacity, float loadFactor)
+   {
+-    map = init(initialCapacity, loadFactor);
++    map = new HashMap(initialCapacity, loadFactor);
+   }
+ 
+   /**
+-   * Construct a new HashSet with the same elements as are in the supplied
+-   * collection (eliminating any duplicates, of course). The backing storage
+-   * has twice the size of the collection, or the default size of 11,
+-   * whichever is greater; and the default load factor (0.75).
++   * construct a new HashSet with the same elements as are in the supplied
++   * collection (eliminating any duplicates, of course; the backing HashMap
++   * will have the default capacity and load factor
+    *
+-   * @param c a collection of initial set elements
+-   * @throws NullPointerException if c is null
++   * @param          c          a collection containing the elements with
++   *                            which this set will be initialized
+    */
+   public HashSet(Collection c)
+   {
+-    this(Math.max(2 * c.size(), HashMap.DEFAULT_CAPACITY));
++    map = new HashMap();
+     addAll(c);
+   }
+ 
+   /**
+-   * Adds the given Object to the set if it is not already in the Set.
+-   * This set permits a null element.
++   * adds the given Object to the set if it is not already in the Set,
++   * returns true if teh element was added, false otherwise
+    *
+-   * @param o the Object to add to this Set
+-   * @return true if the set did not already contain o
++   * @param       o       the Object to add to this Set
+    */
+   public boolean add(Object o)
+   {
+-    return map.put(o, "") == null;
++    return (map.put(o, Boolean.TRUE) == null);
+   }
+ 
+   /**
+-   * Empties this Set of all elements; this takes constant time.
++   * empties this Set of all elements; this is a fast operation [O(1)]
+    */
+   public void clear()
+   {
+@@ -149,67 +121,53 @@
+   }
+ 
+   /**
+-   * Returns a shallow copy of this Set. The Set itself is cloned; its
+-   * elements are not.
+-   *
+-   * @return a shallow clone of the set
++   * returns a shallow copy of this Set (the Set itself is cloned; its 
++   * elements are not)
+    */
+   public Object clone()
+   {
+     HashSet copy = null;
+     try
+       {
+-        copy = (HashSet) super.clone();
++	copy = (HashSet) super.clone();
+       }
+     catch (CloneNotSupportedException x)
+       {
+-        // Impossible to get here.
+       }
+     copy.map = (HashMap) map.clone();
+     return copy;
+   }
+ 
+   /**
+-   * Returns true if the supplied element is in this Set.
++   * returns true if the supplied element is in this Set, false otherwise
+    *
+-   * @param o the Object to look for
+-   * @return true if it is in the set
++   * @param        o         the Object whose presence in this Set we are testing for
+    */
+   public boolean contains(Object o)
+   {
+     return map.containsKey(o);
+   }
+ 
+-  /**
+-   * Returns true if this set has no elements in it.
+-   *
+-   * @return <code>size() == 0</code>.
++  /** 
++   * returns true if this set has no elements in it (size() == 0)
+    */
+   public boolean isEmpty()
+   {
+-    return map.size == 0;
++    return map.isEmpty();
+   }
+ 
+   /**
+-   * Returns an Iterator over the elements of this Set, which visits the
+-   * elements in no particular order.  For this class, the Iterator allows
+-   * removal of elements. The iterator is fail-fast, and will throw a
+-   * ConcurrentModificationException if the set is modified externally.
+-   *
+-   * @return a set iterator
+-   * @see ConcurrentModificationException
++   * returns an Iterator over the elements of this Set; the Iterator allows
++   * removal of elements
+    */
+   public Iterator iterator()
+   {
+-    // Avoid creating intermediate keySet() object by using non-public API.
+-    return map.iterator(HashMap.KEYS);
++    return map.keySet().iterator();
+   }
+ 
+   /**
+-   * Removes the supplied Object from this Set if it is in the Set.
+-   *
+-   * @param o the object to remove
+-   * @return true if an element was removed
++   * removes the supplied Object from this Set if it is in the Set; returns
++   * true if an element was removed, false otherwise
+    */
+   public boolean remove(Object o)
+   {
+@@ -217,42 +175,18 @@
+   }
+ 
+   /**
+-   * Returns the number of elements in this Set (its cardinality).
+-   *
+-   * @return the size of the set
++   * returns the number of elements in this Set
+    */
+   public int size()
+   {
+-    return map.size;
+-  }
+-
+-  /**
+-   * Helper method which initializes the backing Map. Overridden by
+-   * LinkedHashSet for correct semantics.
+-   *
+-   * @param capacity the initial capacity
+-   * @param load the initial load factor
+-   * @return the backing HashMap
+-   */
+-  HashMap init(int capacity, float load)
+-  {
+-    return new HashMap(capacity, load);
++    return map.size();
+   }
+ 
+-  /**
+-   * Serializes this object to the given stream.
+-   *
+-   * @param s the stream to write to
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the <i>capacity</i> (int) and <i>loadFactor</i> (float)
+-   *             of the backing store, followed by the set size (int),
+-   *             then a listing of its elements (Object) in no order
+-   */
++  /** Serialize this Object in a manner which is binary-compatible with the 
++    * JDK */
+   private void writeObject(ObjectOutputStream s) throws IOException
+   {
+-    s.defaultWriteObject();
+-    // Avoid creating intermediate keySet() object by using non-public API.
+-    Iterator it = map.iterator(HashMap.KEYS);
++    Iterator it = iterator();
+     s.writeInt(map.buckets.length);
+     s.writeFloat(map.loadFactor);
+     s.writeInt(map.size);
+@@ -260,23 +194,25 @@
+       s.writeObject(it.next());
+   }
+ 
+-  /**
+-   * Deserializes this object from the given stream.
+-   *
+-   * @param s the stream to read from
+-   * @throws ClassNotFoundException if the underlying stream fails
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the <i>capacity</i> (int) and <i>loadFactor</i> (float)
+-   *             of the backing store, followed by the set size (int),
+-   *             then a listing of its elements (Object) in no order
+-   */
+-  private void readObject(ObjectInputStream s)
+-    throws IOException, ClassNotFoundException
+-  {
+-    s.defaultReadObject();
+-
+-    map = init(s.readInt(), s.readFloat());
+-    for (int size = s.readInt(); size > 0; size--)
+-      map.put(s.readObject(), "");
++  /** Deserialize this Object in a manner which is binary-compatible with 
++    * the JDK */
++  private void readObject(ObjectInputStream s) throws IOException,
++    ClassNotFoundException
++  {
++    int i, size, capacity;
++    float loadFactor;
++    Object element;
++
++    capacity = s.readInt();
++    loadFactor = s.readFloat();
++    size = s.readInt();
++
++    map = new HashMap(capacity, loadFactor);
++
++    for (i = 0; i < size; i++)
++      {
++	element = s.readObject();
++	map.put(element, Boolean.TRUE);
++      }
+   }
+ }
Index: compare/java.util.Hashtable.diff
===================================================================
RCS file: java.util.Hashtable.diff
diff -N java.util.Hashtable.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Hashtable.diff Tue Nov 6 17:21:33 2001
@@ -0,0 +1,869 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Hashtable.java	Fri Oct 26 16:06:57 2001
++++ java/util/Hashtable.java	Tue Oct 16 15:18:25 2001
+@@ -66,9 +66,7 @@
+  * Unlike HashMap, Hashtable does not accept `null' as a key value. Also,
+  * all accesses are synchronized: in a single thread environment, this is
+  * expensive, but in a multi-thread environment, this saves you the effort
+- * of extra synchronization. However, the old-style enumerators are not
+- * synchronized, because they can lead to unspecified behavior even if
+- * they were synchronized. You have been warned.
++ * of extra synchronization.
+  * <p>
+  *
+  * The iterators are <i>fail-fast</i>, meaning that any structural
+@@ -86,7 +84,6 @@
+  * @see IdentityHashMap
+  * @see LinkedHashMap
+  * @since 1.0
+- * @status updated to 1.4
+  */
+ public class Hashtable extends Dictionary
+   implements Map, Cloneable, Serializable
+@@ -96,12 +93,6 @@
+    */
+   private static final int DEFAULT_CAPACITY = 11;
+ 
+-  /** An "enum" of iterator types. */
+-  // Package visible for use by nested classes.
+-  static final int KEYS = 0,
+-                   VALUES = 1,
+-                   ENTRIES = 2;
+-
+   /**
+    * The default load factor; this is explicitly specified by the spec.
+    */
+@@ -115,57 +106,39 @@
+   /**
+    * The rounded product of the capacity and the load factor; when the number
+    * of elements exceeds the threshold, the Hashtable calls
+-   * <code>rehash()</code>.
++   * <pre>rehash()</pre>.
+    * @serial
+    */
+-  private int threshold;
++  int threshold;
+ 
+   /**
+    * Load factor of this Hashtable:  used in computing the threshold.
+    * @serial
+    */
+-  private final float loadFactor;
++  final float loadFactor;
+ 
+   /**
+    * Array containing the actual key-value mappings.
+    */
+-  // Package visible for use by nested classes.
+   transient HashEntry[] buckets;
+ 
+   /**
+    * Counts the number of modifications this Hashtable has undergone, used
+    * by Iterators to know when to throw ConcurrentModificationExceptions.
+    */
+-  // Package visible for use by nested classes.
+   transient int modCount;
+ 
+   /**
+    * The size of this Hashtable:  denotes the number of key-value pairs.
+    */
+-  // Package visible for use by nested classes.
+   transient int size;
+ 
+   /**
+-   * The cache for {@link #keySet()}.
+-   */
+-  private transient Set keys;
+-
+-  /**
+-   * The cache for {@link #values()}.
+-   */
+-  private transient Collection values;
+-
+-  /**
+-   * The cache for {@link #entrySet()}.
+-   */
+-  private transient Set entries;
+-
+-  /**
+    * Class to represent an entry in the hash table. Holds a single key-value
+    * pair. A Hashtable Entry is identical to a HashMap Entry, except that
+    * `null' is not allowed for keys and values.
+    */
+-  private static final class HashEntry extends BasicMapEntry
++  static class HashEntry extends BasicMapEntry
+   {
+     /** The next entry in the linked list. */
+     HashEntry next;
+@@ -186,7 +159,7 @@
+      * @return the prior value
+      * @throws NullPointerException if <code>newVal</code> is null
+      */
+-    public Object setValue(Object newVal)
++    public final Object setValue(Object newVal)
+     {
+       if (newVal == null)
+         throw new NullPointerException();
+@@ -227,8 +200,8 @@
+    * Construct a new Hashtable with a specific inital capacity and
+    * default load factor of 0.75.
+    *
+-   * @param initialCapacity the initial capacity of this Hashtable (&gt;= 0)
+-   * @throws IllegalArgumentException if (initialCapacity &lt; 0)
++   * @param initialCapacity the initial capacity of this Hashtable (>=0)
++   * @throws IllegalArgumentException if (initialCapacity < 0)
+    */
+   public Hashtable(int initialCapacity)
+   {
+@@ -239,10 +212,10 @@
+    * Construct a new Hashtable with a specific initial capacity and
+    * load factor.
+    *
+-   * @param initialCapacity the initial capacity (&gt;= 0)
+-   * @param loadFactor the load factor (&gt; 0, not NaN)
+-   * @throws IllegalArgumentException if (initialCapacity &lt; 0) ||
+-   *                                     ! (loadFactor &gt; 0.0)
++   * @param initialCapacity the initial capacity (>=0)
++   * @param loadFactor the load factor (>0, not NaN)
++   * @throws IllegalArgumentException if (initialCapacity < 0) ||
++   *                                     ! (loadFactor > 0.0)
+    */
+   public Hashtable(int initialCapacity, float loadFactor)
+   {
+@@ -278,36 +251,30 @@
+   }
+ 
+   /**
+-   * Return an enumeration of the keys of this table. There's no point
+-   * in synchronizing this, as you have already been warned that the
+-   * enumeration is not specified to be thread-safe.
+-   *
++   * Return an enumeration of the keys of this table.
+    * @return the keys
+    * @see #elements()
+    * @see #keySet()
+    */
+-  public Enumeration keys()
++  public synchronized Enumeration keys()
+   {
+-    return new Enumerator(KEYS);
++    return new Enumerator(Enumerator.KEYS);
+   }
+ 
+   /**
+-   * Return an enumeration of the values of this table. There's no point
+-   * in synchronizing this, as you have already been warned that the
+-   * enumeration is not specified to be thread-safe.
+-   *
++   * Return an enumeration of the values of this table.
+    * @return the values
+    * @see #keys()
+    * @see #values()
+    */
+-  public Enumeration elements()
++  public synchronized Enumeration elements()
+   {
+-    return new Enumerator(VALUES);
++    return new Enumerator(Enumerator.VALUES);
+   }
+ 
+   /**
+-   * Returns true if this Hashtable contains a value <code>o</code>,
+-   * such that <code>o.equals(value)</code>.  This is the same as
++   * Returns true if this Hashtable contains a value <pre>o</pre>,
++   * such that <pre>o.equals(value)</pre>.  This is the same as
+    * <code>containsValue()</code>, and is O(n).
+    * <p>
+    *
+@@ -317,46 +284,48 @@
+    *
+    * @param value the value to search for in this Hashtable
+    * @return true if at least one key maps to the value
+-   * @throws NullPointerException if <code>value</code> is null
++   * @throws NullPointerException if <pre>value</pre> is null
+    * @see #containsValue(Object)
+    * @see #containsKey(Object)
+    */
+   public synchronized boolean contains(Object value)
+   {
+-    // Check if value is null.
++    // Check if value is null in case Hashtable is empty.
+     if (value == null)
+       throw new NullPointerException();
+-    return containsValue(value);
++
++    for (int i = buckets.length - 1; i >= 0; i--)
++      {
++        HashEntry e = buckets[i];
++        while (e != null)
++          {
++            if (value.equals(e.value))
++              return true;
++            e = e.next;
++          }
++      }
++    return false;
+   }
+ 
+   /**
+-   * Returns true if this Hashtable contains a value <code>o</code>, such that
+-   * <code>o.equals(value)</code>. This is the new API for the old
+-   * <code>contains()</code>, except that it is forgiving of null.
++   * Returns true if this Hashtable contains a value <pre>o</pre>, such that
++   * <pre>o.equals(value)</pre>. This is the new API for the old
++   * <code>contains()</code>.
+    *
+    * @param value the value to search for in this Hashtable
+    * @return true if at least one key maps to the value
++   * @throws NullPointerException if <pre>value</pre> is null
+    * @see #contains(Object)
+    * @see #containsKey(Object)
+    * @since 1.2
+    */
+   public boolean containsValue(Object value)
+   {
+-    for (int i = buckets.length - 1; i >= 0; i--)
+-      {
+-        HashEntry e = buckets[i];
+-        while (e != null)
+-          {
+-            if (AbstractCollection.equals(value, e.value))
+-              return true;
+-            e = e.next;
+-          }
+-      }
+-    return false;
++    return contains(value);
+   }
+ 
+   /**
+-   * Returns true if the supplied object <code>equals()</code> a key
++   * Returns true if the supplied object <pre>equals()</pre> a key
+    * in this Hashtable.
+    *
+    * @param key the key to search for in this Hashtable
+@@ -379,7 +348,7 @@
+ 
+   /**
+    * Return the value in this Hashtable associated with the supplied key,
+-   * or <code>null</code> if the key maps to nothing.
++   * or <pre>null</pre> if the key maps to nothing.
+    *
+    * @param key the key for which to fetch an associated value
+    * @return what the key maps to, if present
+@@ -414,6 +383,7 @@
+    */
+   public synchronized Object put(Object key, Object value)
+   {
++    modCount++;
+     int idx = hash(key);
+     HashEntry e = buckets[idx];
+ 
+@@ -437,7 +407,6 @@
+       }
+ 
+     // At this point, we know we need to add a new entry.
+-    modCount++;
+     if (++size > threshold)
+       {
+         rehash();
+@@ -456,18 +425,15 @@
+   /**
+    * Removes from the table and returns the value which is mapped by the
+    * supplied key. If the key maps to nothing, then the table remains
+-   * unchanged, and <code>null</code> is returned.
+-   * <b>NOTE:</b>Map.remove and Dictionary.remove disagree whether null
+-   * is a valid parameter; at the moment, this implementation obeys Map.remove,
+-   * and silently ignores null.
++   * unchanged, and <pre>null</pre> is returned.
+    *
+    * @param key the key used to locate the value to remove
+    * @return whatever the key mapped to, if present
++   * @throws NullPointerException if key is null
+    */
+   public synchronized Object remove(Object key)
+   {
+-    if (key == null)
+-      return null;
++    modCount++;
+     int idx = hash(key);
+     HashEntry e = buckets[idx];
+     HashEntry last = null;
+@@ -476,7 +442,6 @@
+       {
+         if (key.equals(e.key))
+           {
+-            modCount++;
+             if (last == null)
+               buckets[idx] = e.next;
+             else
+@@ -523,12 +488,9 @@
+    */
+   public synchronized void clear()
+   {
+-    if (size > 0)
+-      {
+-        modCount++;
+-        Arrays.fill(buckets, null);
+-        size = 0;
+-      }
++    modCount++;
++    Arrays.fill(buckets, null);
++    size = 0;
+   }
+ 
+   /**
+@@ -549,18 +511,36 @@
+         // This is impossible.
+       }
+     copy.buckets = new HashEntry[buckets.length];
+-    copy.putAll(this);
+-    // Clear the caches.
+-    copy.keys = null;
+-    copy.values = null;
+-    copy.entries = null;
++
++    for (int i = buckets.length - 1; i >= 0; i--)
++      {
++        HashEntry e = buckets[i];
++        HashEntry last = null;
++
++        while (e != null)
++          {
++            if (last == null)
++              {
++                last = new HashEntry(e.key, e.value);
++                copy.buckets[i] = last;
++              }
++            else
++              {
++                last.next = new HashEntry(e.key, e.value);
++                last = last.next;
++              }
++            e = e.next;
++          }
++      }
+     return copy;
+   }
+ 
+   /**
+-   * Converts this Hashtable to a String, surrounded by braces, and with
+-   * key/value pairs listed with an equals sign between, separated by a
+-   * comma and space. For example, <code>"{a=1, b=2}"</code>.<p>
++   * Converts this Hashtable to a String, surrounded by braces (<pre>'{'</pre>
++   * and <pre>'}'</pre>), key/value pairs listed with an equals sign between,
++   * (<pre>'='</pre>), and pairs separated by comma and space
++   * (<pre>", "</pre>).
++   * <p>
+    *
+    * NOTE: if the <code>toString()</code> method of any key or value
+    * throws an exception, this will fail for the same reason.
+@@ -572,7 +552,7 @@
+     // Since we are already synchronized, and entrySet().iterator()
+     // would repeatedly re-lock/release the monitor, we directly use the
+     // unsynchronized HashIterator instead.
+-    Iterator entries = new HashIterator(ENTRIES);
++    Iterator entries = new HashIterator(HashIterator.ENTRIES);
+     StringBuffer r = new StringBuffer("{");
+     for (int pos = size; pos > 0; pos--)
+       {
+@@ -588,11 +568,9 @@
+    * Returns a "set view" of this Hashtable's keys. The set is backed by
+    * the hashtable, so changes in one show up in the other.  The set supports
+    * element removal, but not element addition.  The set is properly
+-   * synchronized on the original hashtable.  Sun has not documented the
+-   * proper interaction of null with this set, but has inconsistent behavior
+-   * in the JDK. Therefore, in this implementation, contains, remove,
+-   * containsAll, retainAll, removeAll, and equals just ignore a null key
+-   * rather than throwing a {@link NullPointerException}.
++   * synchronized on the original hashtable.  The set will throw a
++   * {@link NullPointerException} if null is passed to <code>contains</code>,
++   * <code>remove</code>, or related methods.
+    *
+    * @return a set view of the keys
+    * @see #values()
+@@ -601,56 +579,50 @@
+    */
+   public Set keySet()
+   {
+-    if (keys == null)
++    // Create a synchronized AbstractSet with custom implementations of those
++    // methods that can be overridden easily and efficiently.
++    Set r = new AbstractSet()
++    {
++      public int size()
+       {
+-        // Create a synchronized AbstractSet with custom implementations of
+-        // those methods that can be overridden easily and efficiently.
+-        Set r = new AbstractSet()
+-        {
+-          public int size()
+-          {
+-            return size;
+-          }
++        return size;
++      }
+ 
+-          public Iterator iterator()
+-          {
+-            return new HashIterator(KEYS);
+-          }
++      public Iterator iterator()
++      {
++        return new HashIterator(HashIterator.KEYS);
++      }
+ 
+-          public void clear()
+-          {
+-            Hashtable.this.clear();
+-          }
++      public void clear()
++      {
++        Hashtable.this.clear();
++      }
+ 
+-          public boolean contains(Object o)
+-          {
+-            if (o == null)
+-              return false;
+-            return containsKey(o);
+-          }
++      public boolean contains(Object o)
++      {
++        return Hashtable.this.containsKey(o);
++      }
+ 
+-          public boolean remove(Object o)
+-          {
+-            return Hashtable.this.remove(o) != null;
+-          }
+-        };
+-        // We must specify the correct object to synchronize upon, hence the
+-        // use of a non-public API
+-        keys = new Collections.SynchronizedSet(this, r);
++      public boolean remove(Object o)
++      {
++        return (Hashtable.this.remove(o) != null);
+       }
+-    return keys;
++    };
++
++    // We must specify the correct object to synchronize upon, hence the
++    // use of a non-public API
++    return new Collections.SynchronizedSet(this, r);
+   }
+ 
++
+   /**
+    * Returns a "collection view" (or "bag view") of this Hashtable's values.
+    * The collection is backed by the hashtable, so changes in one show up
+    * in the other.  The collection supports element removal, but not element
+    * addition.  The collection is properly synchronized on the original
+-   * hashtable.  Sun has not documented the proper interaction of null with
+-   * this set, but has inconsistent behavior in the JDK. Therefore, in this
+-   * implementation, contains, remove, containsAll, retainAll, removeAll, and
+-   * equals just ignore a null value rather than throwing a
+-   * {@link NullPointerException}.
++   * hashtable.  The collection will throw a {@link NullPointerException}
++   * if null is passed to <code>contains</code> or related methods, but not
++   * if passed to <code>remove</code> or related methods.
+    *
+    * @return a bag view of the values
+    * @see #keySet()
+@@ -659,45 +631,46 @@
+    */
+   public Collection values()
+   {
+-    if (values == null)
++    // We don't bother overriding many of the optional methods, as doing so
++    // wouldn't provide any significant performance advantage.
++    Collection r = new AbstractCollection()
++    {
++      public int size()
+       {
+-        // We don't bother overriding many of the optional methods, as doing so
+-        // wouldn't provide any significant performance advantage.
+-        Collection r = new AbstractCollection()
+-        {
+-          public int size()
+-          {
+-            return size;
+-          }
++        return size;
++      }
+ 
+-          public Iterator iterator()
+-          {
+-            return new HashIterator(VALUES);
+-          }
++      public Iterator iterator()
++      {
++        return new HashIterator(HashIterator.VALUES);
++      }
+ 
+-          public void clear()
+-          {
+-            Hashtable.this.clear();
+-          }
+-        };
+-        // We must specify the correct object to synchronize upon, hence the
+-        // use of a non-public API
+-        values = new Collections.SynchronizedCollection(this, r);
++      public void clear()
++      {
++        Hashtable.this.clear();
++      }
++
++      // Override this so that we check for null
++      public boolean contains(Object o)
++      {
++        return Hashtable.this.contains(o);
+       }
+-    return values;
++    };
++
++    // We must specify the correct object to synchronize upon, hence the
++    // use of a non-public API
++    return new Collections.SynchronizedCollection(this, r);
+   }
+ 
+   /**
+    * Returns a "set view" of this Hashtable's entries. The set is backed by
+    * the hashtable, so changes in one show up in the other.  The set supports
+    * element removal, but not element addition.  The set is properly
+-   * synchronized on the original hashtable.  Sun has not documented the
+-   * proper interaction of null with this set, but has inconsistent behavior
+-   * in the JDK. Therefore, in this implementation, contains, remove,
+-   * containsAll, retainAll, removeAll, and equals just ignore a null entry,
+-   * or an entry with a null key or value, rather than throwing a
+-   * {@link NullPointerException}. However, calling entry.setValue(null)
+-   * will fail.
++   * synchronized on the original hashtable.  The set will throw a
++   * {@link NullPointerException} if the Map.Entry passed to
++   * <code>contains</code>, <code>remove</code>, or related methods returns
++   * null for <code>getKey</code>, but not if the Map.Entry is null or
++   * returns null for <code>getValue</code>.
+    * <p>
+    *
+    * Note that the iterators for all three views, from keySet(), entrySet(),
+@@ -711,52 +684,49 @@
+    */
+   public Set entrySet()
+   {
+-    if (entries == null)
++    // Create an AbstractSet with custom implementations of those methods that
++    // can be overridden easily and efficiently.
++    Set r = new AbstractSet()
++    {
++      public int size()
+       {
+-        // Create an AbstractSet with custom implementations of those methods
+-        // that can be overridden easily and efficiently.
+-        Set r = new AbstractSet()
+-        {
+-          public int size()
+-          {
+-            return size;
+-          }
++        return size;
++      }
+ 
+-          public Iterator iterator()
+-          {
+-            return new HashIterator(ENTRIES);
+-          }
++      public Iterator iterator()
++      {
++        return new HashIterator(HashIterator.ENTRIES);
++      }
+ 
+-          public void clear()
+-          {
+-            Hashtable.this.clear();
+-          }
++      public void clear()
++      {
++        Hashtable.this.clear();
++      }
+ 
+-          public boolean contains(Object o)
+-          {
+-            return getEntry(o) != null;
+-          }
++      public boolean contains(Object o)
++      {
++        return getEntry(o) != null;
++      }
+ 
+-          public boolean remove(Object o)
++      public boolean remove(Object o)
++      {
++        HashEntry e = getEntry(o);
++        if (e != null)
+           {
+-            HashEntry e = getEntry(o);
+-            if (e != null)
+-              {
+-                Hashtable.this.remove(e.key);
+-                return true;
+-              }
+-            return false;
++            Hashtable.this.remove(e.key);
++            return true;
+           }
+-        };
+-        // We must specify the correct object to synchronize upon, hence the
+-        // use of a non-public API
+-        entries = new Collections.SynchronizedSet(this, r);
++        return false;
+       }
+-    return entries;
++    };
++
++    // We must specify the correct object to synchronize upon, hence the
++    // use of a non-public API
++    return new Collections.SynchronizedSet(this, r);
+   }
+ 
+   /**
+-   * Returns true if this Hashtable equals the supplied Object <code>o</code>.
++   * Returns true if this Hashtable equals the supplied Object <pre>o</pre>.
+    * As specified by Map, this is:
+    * <pre>
+    * (o instanceof Map) && entrySet().equals(((Map) o).entrySet());
+@@ -789,7 +759,7 @@
+     // Since we are already synchronized, and entrySet().iterator()
+     // would repeatedly re-lock/release the monitor, we directly use the
+     // unsynchronized HashIterator instead.
+-    Iterator itr = new HashIterator(ENTRIES);
++    Iterator itr = new HashIterator(HashIterator.ENTRIES);
+     int hashcode = 0;
+     for (int pos = size; pos > 0; pos--)
+       hashcode += itr.next().hashCode();
+@@ -812,25 +782,23 @@
+ 
+   /**
+    * Helper method for entrySet(), which matches both key and value
+-   * simultaneously. Ignores null, as mentioned in entrySet().
++   * simultaneously.
+    *
+    * @param o the entry to match
+    * @return the matching entry, if found, or null
++   * @throws NullPointerException if me.getKey() returns null
+    * @see #entrySet()
+    */
+   private HashEntry getEntry(Object o)
+   {
+-    if (! (o instanceof Map.Entry))
++    if (!(o instanceof Map.Entry))
+       return null;
+-    Object key = ((Map.Entry) o).getKey();
+-    if (key == null)
+-      return null;
+-
+-    int idx = hash(key);
++    Map.Entry me = (Map.Entry) o;
++    int idx = hash(me.getKey());
+     HashEntry e = buckets[idx];
+     while (e != null)
+       {
+-        if (o.equals(e))
++        if (e.equals(me))
+           return e;
+         e = e.next;
+       }
+@@ -845,8 +813,7 @@
+    * <p>
+    *
+    * This is not specified, but the new size is twice the current size plus
+-   * one; this number is not always prime, unfortunately. This implementation
+-   * is not synchronized, as it is only invoked from synchronized methods.
++   * one; this number is not always prime, unfortunately.
+    */
+   protected void rehash()
+   {
+@@ -887,8 +854,8 @@
+    *
+    * @param s the stream to write to
+    * @throws IOException if the underlying stream fails
+-   * @serialData the <i>capacity</i> (int) that is the length of the
+-   *             bucket array, the <i>size</i> (int) of the hash map
++   * @serialData the <i>capacity</i>(int) that is the length of the
++   *             bucket array, the <i>size</i>(int) of the hash map
+    *             are emitted first.  They are followed by size entries,
+    *             each consisting of a key (Object) and a value (Object).
+    */
+@@ -903,7 +870,7 @@
+     // Since we are already synchronized, and entrySet().iterator()
+     // would repeatedly re-lock/release the monitor, we directly use the
+     // unsynchronized HashIterator instead.
+-    Iterator it = new HashIterator(ENTRIES);
++    Iterator it = new HashIterator(HashIterator.ENTRIES);
+     while (it.hasNext())
+       {
+         HashEntry entry = (HashEntry) it.next();
+@@ -918,8 +885,8 @@
+    * @param s the stream to read from
+    * @throws ClassNotFoundException if the underlying stream fails
+    * @throws IOException if the underlying stream fails
+-   * @serialData the <i>capacity</i> (int) that is the length of the
+-   *             bucket array, the <i>size</i> (int) of the hash map
++   * @serialData the <i>capacity</i>(int) that is the length of the
++   *             bucket array, the <i>size</i>(int) of the hash map
+    *             are emitted first.  They are followed by size entries,
+    *             each consisting of a key (Object) and a value (Object).
+    */
+@@ -934,8 +901,7 @@
+     int len = s.readInt();
+ 
+     // Read and use key/value pairs.
+-    // TODO: should we be defensive programmers, and check for illegal nulls?
+-    while (--len >= 0)
++    for ( ; len > 0; len--)
+       put(s.readObject(), s.readObject());
+   }
+ 
+@@ -950,8 +916,13 @@
+    *
+    * @author Jon Zeppieri
+    */
+-  private final class HashIterator implements Iterator
++  class HashIterator implements Iterator
+   {
++    /** "enum" of iterator types. */
++    static final int KEYS = 0,
++                     VALUES = 1,
++                     ENTRIES = 2;
++
+     /**
+      * The type of this Iterator: {@link #KEYS}, {@link #VALUES},
+      * or {@link #ENTRIES}.
+@@ -1017,14 +988,14 @@
+       last = e;
+       if (type == VALUES)
+         return e.value;
+-      if (type == KEYS)
++      else if (type == KEYS)
+         return e.key;
+       return e;
+     }
+ 
+     /**
+      * Removes from the backing Hashtable the last element which was fetched
+-     * with the <code>next()</code> method.
++     * with the <pre>next()</pre> method.
+      * @throws ConcurrentModificationException if the hashtable was modified
+      * @throws IllegalStateException if called when there is no last element
+      */
+@@ -1036,10 +1007,10 @@
+         throw new IllegalStateException();
+ 
+       Hashtable.this.remove(last.key);
+-      last = null;
+       knownMod++;
++      last = null;
+     }
+-  } // class HashIterator
++  }
+ 
+ 
+   /**
+@@ -1056,21 +1027,21 @@
+    *
+    * @author Jon Zeppieri
+    */
+-  private final class Enumerator implements Enumeration
++  class Enumerator implements Enumeration
+   {
++    /** "enum" of iterator types. */
++    static final int KEYS = 0,
++                     VALUES = 1;
++
+     /**
+      * The type of this Iterator: {@link #KEYS} or {@link #VALUES}.
+      */
+-    final int type;
+-    /** The number of elements remaining to be returned by next(). */
+-    int count = size;
++    int type;
+     /** Current index in the physical hash table. */
+-    int idx = buckets.length;
+-    /**
+-     * Entry which will be returned by the next nextElement() call. It is
+-     * set if we are iterating through a bucket with multiple entries, or null
+-     * if we must look in the next bucket.
+-     */
++    int idx;
++    /** The last Entry returned by nextEntry(). */
++    HashEntry last;
++    /** Entry which will be returned by the next nextElement() call. */
+     HashEntry next;
+ 
+     /**
+@@ -1080,6 +1051,25 @@
+     Enumerator(int type)
+     {
+       this.type = type;
++      this.idx = buckets.length;
++    }
++
++    /**
++     * Helper method to find the next entry.
++     * @return the next entry, or null
++     */
++    private HashEntry nextEntry()
++    {
++      HashEntry e = null;
++
++      if (last != null)
++        e = last.next;
++
++      while (e == null && idx > 0)
++        e = buckets[--idx];
++
++      last = e;
++      return e;
+     }
+ 
+     /**
+@@ -1088,7 +1078,10 @@
+      */
+     public boolean hasMoreElements()
+     {
+-      return count > 0;
++      if (next != null)
++        return true;
++      next = nextEntry();
++      return next != null;
+     }
+ 
+     /**
+@@ -1098,16 +1091,19 @@
+      */
+     public Object nextElement()
+     {
+-      if (count == 0)
++      HashEntry e;
++      if (next != null)
++        {
++          e = next;
++          next = null;
++        }
++      else
++        e = nextEntry();
++      if (e == null)
+         throw new NoSuchElementException("Hashtable Enumerator");
+-      count--;
+-      HashEntry e = next;
+-
+-      while (e == null)
+-        e = buckets[--idx];
+-
+-      next = e.next;
+-      return type == VALUES ? e.value : e.key;
++      if (type == VALUES)
++        return e.value;
++      return e.key;
+     }
+-  } // class Enumerator
++  }
+ }
Index: compare/java.util.IdentityHashMap.diff
===================================================================
RCS file: java.util.IdentityHashMap.diff
diff -N java.util.IdentityHashMap.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.IdentityHashMap.diff Tue Nov 6 17:21:34 2001
@@ -0,0 +1,1176 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/IdentityHashMap.java	Fri Oct 26 16:06:57 2001
++++ java/util/IdentityHashMap.java	Tue Oct 16 09:14:34 2001
+@@ -31,888 +31,403 @@
+ 
+ /**
+  * This class provides a hashtable-backed implementation of the
+- * Map interface, but uses object identity to do its hashing.  In fact,
+- * it uses object identity for comparing values, as well. It uses a
+- * linear-probe hash table, which may have faster performance
+- * than the chaining employed by HashMap.
+- * <p>
+- *
+- * <em>WARNING: This is not a general purpose map. Because it uses
+- * System.identityHashCode and ==, instead of hashCode and equals, for
+- * comparison, it violated Map's general contract, and may cause
+- * undefined behavior when compared to other maps which are not
+- * IdentityHashMaps.  This is designed only for the rare cases when
+- * identity semantics are needed.</em> An example use is
+- * topology-preserving graph transformations, such as deep cloning,
+- * or as proxy object mapping such as in debugging.
+- * <p>
+- *
+- * This map permits <code>null</code> keys and values, and does not
+- * guarantee that elements will stay in the same order over time. The
+- * basic operations (<code>get</code> and <code>put</code>) take
+- * constant time, provided System.identityHashCode is decent. You can
+- * tune the behavior by specifying the expected maximum size. As more
+- * elements are added, the map may need to allocate a larger table,
+- * which can be expensive.
+- * <p>
+- *
+- * This implementation is unsynchronized.  If you want multi-thread
+- * access to be consistent, you must synchronize it, perhaps by using
+- * <code>Collections.synchronizedMap(new IdentityHashMap(...));</code>.
+- * The iterators are <i>fail-fast</i>, meaning that a structural modification
+- * made to the map outside of an iterator's remove method cause the
+- * iterator, and in the case of the entrySet, the Map.Entry, to
+- * fail with a {@link ConcurrentModificationException}.
++ * Map interface.  Unlike HashMap, it uses object identity to
++ * do its hashing.  Also, it uses a linear-probe hash table.
+  *
+  * @author Tom Tromey <tromey@redhat.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see System#identityHashCode(Object)
+- * @see Collection
+- * @see Map
+- * @see HashMap
+- * @see TreeMap
+- * @see LinkedHashMap
+- * @see WeakHashMap
+  * @since 1.4
+- * @status updated to 1.4
+  */
+ public class IdentityHashMap extends AbstractMap
+   implements Map, Serializable, Cloneable
+ {
+-  /** The default capacity. */
+   private static final int DEFAULT_CAPACITY = 21;
+ 
+-  /**
+-   * This object is used to mark deleted items. Package visible for use by
+-   * nested classes.
+-   */
+-  static final Object tombstone = new Object();
+-
+-  /**
+-   * This object is used to mark empty slots.  We need this because
+-   * using null is ambiguous. Package visible for use by nested classes.
+-   */
+-  static final Object emptyslot = new Object();
+-
+-  /**
+-   * Compatible with JDK 1.4.
+-   */
+-  private static final long serialVersionUID = 8188218128353913216L;
+-
+-  /**
+-   * The number of mappings in the table. Package visible for use by nested
+-   * classes.
+-   * @serial
+-   */
+-  int size;
+-
+-  /**
+-   * The table itself. Package visible for use by nested classes.
+-   */
+-  transient Object[] table;
+-
+-  /**
+-   * The number of structural modifications made so far. Package visible for
+-   * use by nested classes.
+-   */
+-  transient int modCount;
+-
+-  /**
+-   * The cache for {@link #entrySet()}.
+-   */
+-  private transient Set entries;
+-
+-  /**
+-   * The threshold for rehashing, which is 75% of (table.length / 2).
+-   */
+-  private transient int threshold;
+-
+-  /**
+-   * Create a new IdentityHashMap with the default capacity (21 entries).
++  /** Create a new IdentityHashMap with the default capacity (21
++   * entries).
+    */
+-  public IdentityHashMap()
++  public IdentityHashMap ()
+   {
+-    this(DEFAULT_CAPACITY);
++    this (DEFAULT_CAPACITY);
+   }
+ 
+-  /**
+-   * Create a new IdentityHashMap with the indicated number of
++  /** Create a new IdentityHashMap with the indicated number of
+    * entries.  If the number of elements added to this hash map
+    * exceeds this maximum, the map will grow itself; however, that
+    * incurs a performance penalty.
+-   *
+-   * @param max initial size
+-   * @throws IllegalArgumentException if max is negative
++   * @param max Initial size
+    */
+-  public IdentityHashMap(int max)
++  public IdentityHashMap (int max)
+   {
+     if (max < 0)
+-      throw new IllegalArgumentException();
+-    // Need at least two slots, or hash() will break.
+-    if (max < 2)
+-      max = 2;
++      throw new IllegalArgumentException ();
+     table = new Object[2 * max];
+-    Arrays.fill(table, emptyslot);
+-    // This is automatically set.
+-    // size = 0;
+-    threshold = max / 4 * 3;
++    Arrays.fill (table, emptyslot);
++    size = 0;
+   }
+ 
+-  /**
+-   * Create a new IdentityHashMap whose contents are taken from the
++  /** Create a new IdentityHashMap whose contents are taken from the
+    * given Map.
+-   *
+-   * @param m The map whose elements are to be put in this map
+-   * @throws NullPointerException if m is null
++   * @param m The map whose elements are to be put in this map.
+    */
+-  public IdentityHashMap(Map m)
++  public IdentityHashMap (Map m)
+   {
+-    this(Math.max(m.size() * 2, DEFAULT_CAPACITY));
+-    putAll(m);
++    int len = 2 * Math.max (m.size (), DEFAULT_CAPACITY);
++    table = new Object[len];
++    Arrays.fill (table, emptyslot);
++    putAll (m);
+   }
+ 
+-  /**
+-   * Remove all mappings from this map.
+-   */
+-  public void clear()
++  public void clear ()
+   {
+-    if (size != 0)
+-      {
+-        modCount++;
+-        Arrays.fill(table, emptyslot);
+-        size = 0;
+-      }
++    Arrays.fill (table, emptyslot);
++    size = 0;
+   }
+ 
+   /**
+    * Creates a shallow copy where keys and values are not cloned.
+    */
+-  public Object clone()
++  public Object clone ()
+   {
+-    try
++    try 
+       {
+-        IdentityHashMap copy = (IdentityHashMap) super.clone();
+-        copy.table = (Object[]) table.clone();
+-        copy.entries = null; // invalidate the cache
+-        return copy;
++        IdentityHashMap copy = (IdentityHashMap) super.clone ();
++	copy.table = (Object[]) table.clone ();
++	return copy;
+       }
+-    catch (CloneNotSupportedException e)
++    catch (CloneNotSupportedException e) 
+       {
+-        // Can't happen.
+-        return null;
++	// Can't happen.
++	return null;
+       }
+   }
+ 
+-  /**
+-   * Tests whether the specified key is in this map.  Unlike normal Maps,
+-   * this test uses <code>entry == key</code> instead of
+-   * <code>entry == null ? key == null : entry.equals(key)</code>.
+-   *
+-   * @param key the key to look for
+-   * @return true if the key is contained in the map
+-   * @see #containsValue(Object)
+-   * @see #get(Object)
+-   */
+-  public boolean containsKey(Object key)
++  public boolean containsKey (Object key)
+   {
+-    return key == table[hash(key)];
++    int h = getHash (key);
++    int save = h;
++    while (true)
++      {
++	if (table[h] == key)
++	  return true;
++	if (table[h] == emptyslot)
++	  return false;
++	h += 2;
++	if (h >= table.length)
++	  h = 0;
++	if (h == save)
++	  return false;
++      }
+   }
+ 
+-  /**
+-   * Returns true if this HashMap contains the value.  Unlike normal maps,
+-   * this test uses <code>entry == value</code> instead of
+-   * <code>entry == null ? value == null : entry.equals(value)</code>.
+-   *
+-   * @param value the value to search for in this HashMap
+-   * @return true if at least one key maps to the value
+-   * @see #containsKey(Object)
+-   */
+-  public boolean containsValue(Object value)
++  public boolean containsValue (Object value)
+   {
+-    for (int i = table.length - 1; i > 0; i -= 2)
++    for (int i = 1; i < table.length; i += 2)
+       if (table[i] == value)
+-        return true;
++	return true;
+     return false;
+   }
+ 
+-  /**
+-   * Returns a "set view" of this Map's entries. The set is backed by
+-   * the Map, so changes in one show up in the other.  The set supports
+-   * element removal, but not element addition.
+-   * <p>
+-   *
+-   * <em>The semantics of this set, and of its contained entries, are
+-   * different from the contract of Set and Map.Entry in order to make
+-   * IdentityHashMap work.  This means that while you can compare these
+-   * objects between IdentityHashMaps, comparing them with regular sets
+-   * or entries is likely to have undefined behavior.</em>  The entries
+-   * in this set are reference-based, rather than the normal object
+-   * equality.  Therefore, <code>e1.equals(e2)</code> returns
+-   * <code>e1.getKey() == e2.getKey() && e1.getValue() == e2.getValue()</code>,
+-   * and <code>e.hashCode()</code> returns
+-   * <code>System.identityHashCode(e.getKey()) ^
+-   *       System.identityHashCode(e.getValue())</code>.
+-   * <p>
+-   *
+-   * Note that the iterators for all three views, from keySet(), entrySet(),
+-   * and values(), traverse the Map in the same sequence.
+-   *
+-   * @return a set view of the entries
+-   * @see #keySet()
+-   * @see #values()
+-   * @see Map.Entry
+-   */
+-  public Set entrySet()
++  public Set entrySet ()
+   {
+-    if (entries == null)
+-      entries = new AbstractSet()
++    return new AbstractSet ()
++    {
++      public int size ()
+       {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          return new IdentityIterator(ENTRIES);
+-        }
+-
+-        public void clear()
+-        {
+-          IdentityHashMap.this.clear();
+-        }
+-
+-        public boolean contains(Object o)
+-        {
+-          if (! (o instanceof Map.Entry))
+-            return false;
+-          Map.Entry m = (Map.Entry) o;
+-          return m.getValue() == table[hash(m.getKey()) + 1];
+-        }
+-
+-        public int hashCode()
+-        {
+-          return IdentityHashMap.this.hashCode();
+-        }
+-
+-        public boolean remove(Object o)
+-        {
+-          if (! (o instanceof Map.Entry))
+-            return false;
+-          Object key = ((Map.Entry) o).getKey();
+-          int h = hash(key);
+-          if (table[h] == key)
+-            {
+-              size--;
+-              modCount++;
+-              table[h] = tombstone;
+-              table[h + 1] = tombstone;
+-              return true;
+-            }
+-          return false;
+-        }
+-      };
+-    return entries;
+-  }
++	return size;
++      }
+ 
+-  /**
+-   * Compares two maps for equality. This returns true only if both maps
+-   * have the same reference-identity comparisons. While this returns
+-   * <code>this.entrySet().equals(m.entrySet())</code> as specified by Map,
+-   * this will not work with normal maps, since the entry set compares
+-   * with == instead of .equals.
+-   *
+-   * @param o the object to compare to
+-   * @return true if it is equal
+-   */
+-  public boolean equals(Object o)
+-  {
+-    // Why did Sun specify this one? The superclass does the right thing.
+-    return super.equals(o);
+-  }
++      public Iterator iterator ()
++      {
++	return new IdentityIterator (IdentityIterator.ENTRIES);
++      }
+ 
+-  /**
+-   * Return the value in this Map associated with the supplied key,
+-   * or <pre>null</pre> if the key maps to nothing.  NOTE: Since the value
+-   * could also be null, you must use containsKey to see if this key
+-   * actually maps to something.  Unlike normal maps, this tests for the key
+-   * with <code>entry == key</code> instead of
+-   * <code>entry == null ? key == null : entry.equals(key)</code>.
+-   *
+-   * @param key the key for which to fetch an associated value
+-   * @return what the key maps to, if present
+-   * @see #put(Object, Object)
+-   * @see #containsKey(Object)
+-   */
+-  public Object get(Object key)
+-  {
+-    int h = hash(key);
+-    return table[h] == key ? table[h + 1] : null;
++      public void clear ()
++      {
++	IdentityHashMap.this.clear ();
++      }
++
++      public boolean contains (Object o)
++      {
++	if (! (o instanceof Map.Entry))
++	  return false;
++	Map.Entry m = (Map.Entry) o;
++	return (IdentityHashMap.this.containsKey (m.getKey ())
++		&& IdentityHashMap.this.get (m.getKey ()) == m.getValue ());
++      }
++
++      public boolean remove (Object o)
++      {
++	if (! (o instanceof Map.Entry))
++	  return false;
++	Map.Entry m = (Map.Entry) o;
++	if (IdentityHashMap.this.containsKey (m.getKey ())
++	    && IdentityHashMap.this.get (m.getKey ()) == m.getValue ())
++	  {
++	    int oldsize = size;
++	    IdentityHashMap.this.remove (m.getKey ());
++	    return oldsize != size;
++	  }
++	return false;
++      }
++    };
+   }
+ 
+-  /**
+-   * Returns the hashcode of this map. This guarantees that two
+-   * IdentityHashMaps that compare with equals() will have the same hash code,
+-   * but may break with comparison to normal maps since it uses
+-   * System.identityHashCode() instead of hashCode().
+-   *
+-   * @return the hash code
+-   */
+-  public int hashCode()
++  public Object get (Object key)
+   {
+-    int hash = 0;
+-    for (int i = table.length - 2; i >= 0; i -= 2)
++    int h = getHash (key);
++    int save = h;
++    while (true)
+       {
+-        Object key = table[i];
+-        if (key == emptyslot || key == tombstone)
+-          continue;
+-        hash += (System.identityHashCode(key)
+-                 ^ System.identityHashCode(table[i + 1]));
++	if (table[h] == key)
++	  return table[h + 1];
++	if (table[h] == emptyslot)
++	  return null;
++	h += 2;
++	if (h >= table.length)
++	  h = 0;
++	if (h == save)
++	  return null;
+       }
+-    return hash;
+   }
+ 
+-  /**
+-   * Returns true if there are no key-value mappings currently in this Map
+-   * @return <code>size() == 0</code>
+-   */
+-  public boolean isEmpty()
++  public boolean isEmpty ()
+   {
+     return size == 0;
+   }
+ 
+-  /**
+-   * Returns a "set view" of this Map's keys. The set is backed by the
+-   * Map, so changes in one show up in the other.  The set supports
+-   * element removal, but not element addition.
+-   * <p>
+-   *
+-   * <em>The semantics of this set are different from the contract of Set
+-   * in order to make IdentityHashMap work.  This means that while you can
+-   * compare these objects between IdentityHashMaps, comparing them with
+-   * regular sets is likely to have undefined behavior.</em>  The hashCode
+-   * of the set is the sum of the identity hash codes, instead of the
+-   * regular hashCodes, and equality is determined by reference instead
+-   * of by the equals method.
+-   * <p>
+-   *
+-   * @return a set view of the keys
+-   * @see #values()
+-   * @see #entrySet()
+-   */
+-  public Set keySet()
++  public Set keySet ()
+   {
+-    if (keys == null)
+-      keys = new AbstractSet()
++    return new AbstractSet ()
++    {
++      public int size ()
+       {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          return new IdentityIterator(KEYS);
+-        }
+-
+-        public void clear()
+-        {
+-          IdentityHashMap.this.clear();
+-        }
+-
+-        public boolean contains(Object o)
+-        {
+-          return containsKey(o);
+-        }
+-
+-        public int hashCode()
+-        {
+-          int hash = 0;
+-          for (int i = table.length - 2; i >= 0; i -= 2)
+-            {
+-              Object key = table[i];
+-              if (key == emptyslot || key == tombstone)
+-                continue;
+-              hash += System.identityHashCode(key);
+-            }
+-          return hash;
+-
+-        }
+-
+-        public boolean remove(Object o)
+-        {
+-          int h = hash(o);
+-          if (table[h] == o)
+-            {
+-              size--;
+-              modCount++;
+-              table[h] = tombstone;
+-              table[h + 1] = tombstone;
+-              return true;
+-            }
+-          return false;
+-        }
+-      };
+-    return keys;
+-  }
++	return size;
++      }
+ 
+-  /**
+-   * Puts the supplied value into the Map, mapped by the supplied key.
+-   * The value may be retrieved by any object which <code>equals()</code>
+-   * this key. NOTE: Since the prior value could also be null, you must
+-   * first use containsKey if you want to see if you are replacing the
+-   * key's mapping.  Unlike normal maps, this tests for the key
+-   * with <code>entry == key</code> instead of
+-   * <code>entry == null ? key == null : entry.equals(key)</code>.
+-   *
+-   * @param key the key used to locate the value
+-   * @param value the value to be stored in the HashMap
+-   * @return the prior mapping of the key, or null if there was none
+-   * @see #get(Object)
+-   */
+-  public Object put(Object key, Object value)
+-  {
+-    // Rehash if the load factor is too high.
+-    if (size > threshold)
++      public Iterator iterator ()
+       {
+-        Object[] old = table;
+-        // This isn't necessarily prime, but it is an odd number of key/value
+-        // slots, which has a higher probability of fewer collisions.
+-        table = new Object[old.length * 2 + 2];
+-        Arrays.fill(table, emptyslot);
+-        size = 0;
+-        threshold = table.length / 4 * 3;
+-
+-        for (int i = old.length - 2; i >= 0; i -= 2)
+-          {
+-            Object oldkey = old[i];
+-            if (oldkey != tombstone && oldkey != emptyslot)
+-              // Just use put.  This isn't very efficient, but it is ok.
+-              put(oldkey, old[i + 1]);
+-          }
+-      }
+-
+-    int h = hash(key);
+-    if (table[h] == key)
+-      {
+-        Object r = table[h + 1];
+-        table[h + 1] = value;
+-        return r;
+-      }
+-
+-    // At this point, we add a new mapping.
+-    modCount++;
+-    size++;
+-    table[h] = key;
+-    table[h + 1] = value;
+-    return null;
+-  }
++	return new IdentityIterator (IdentityIterator.KEYS);
++      }
+ 
+-  /**
+-   * Copies all of the mappings from the specified map to this. If a key
+-   * is already in this map, its value is replaced.
+-   *
+-   * @param m the map to copy
+-   * @throws NullPointerException if m is null
+-   */
+-  public void putAll(Map m)
+-  {
+-    // Why did Sun specify this one? The superclass does the right thing.
+-    super.putAll(m);
+-  }
++      public void clear ()
++      {
++	IdentityHashMap.this.clear ();
++      }
+ 
+-  /**
+-   * Removes from the HashMap and returns the value which is mapped by the
+-   * supplied key. If the key maps to nothing, then the HashMap remains
+-   * unchanged, and <pre>null</pre> is returned. NOTE: Since the value
+-   * could also be null, you must use containsKey to see if you are
+-   * actually removing a mapping.  Unlike normal maps, this tests for the
+-   * key with <code>entry == key</code> instead of
+-   * <code>entry == null ? key == null : entry.equals(key)</code>.
+-   *
+-   * @param key the key used to locate the value to remove
+-   * @return whatever the key mapped to, if present
+-   */
+-  public Object remove(Object key)
+-  {
+-    int h = hash(key);
+-    if (table[h] == key)
++      public boolean contains (Object o)
+       {
+-        modCount++;
+-        size--;
+-        Object r = table[h + 1];
+-        table[h] = tombstone;
+-        table[h + 1] = tombstone;
+-        return r;
++	return IdentityHashMap.this.containsKey (o);
+       }
+-    return null;
+-  }
+ 
+-  /**
+-   * Returns the number of kay-value mappings currently in this Map
+-   * @return the size
+-   */
+-  public int size()
+-  {
+-    return size;
++      public boolean remove (Object o)
++      {
++	int oldsize = size;
++	IdentityHashMap.this.remove (o);
++	return oldsize != size;
++      }
++    };
+   }
+ 
+-  /**
+-   * Returns a "collection view" (or "bag view") of this Map's values.
+-   * The collection is backed by the Map, so changes in one show up
+-   * in the other.  The collection supports element removal, but not element
+-   * addition.
+-   * <p>
+-   *
+-   * <em>The semantics of this set are different from the contract of
+-   * Collection in order to make IdentityHashMap work.  This means that
+-   * while you can compare these objects between IdentityHashMaps, comparing
+-   * them with regular sets is likely to have undefined behavior.</em>
+-   * Likewise, contains and remove go by == instead of equals().
+-   * <p>
+-   *
+-   * @return a bag view of the values
+-   * @see #keySet()
+-   * @see #entrySet()
+-   */
+-  public Collection values()
++  public Object put (Object key, Object value)
+   {
+-    if (values == null)
+-      values = new AbstractCollection()
++    // Rehash if the load factor is too high.  We use a factor of 1.5
++    // -- the division by 2 is implicit on both sides.
++    if (size * 3 > table.length)
++      {
++	Object[] old = table;
++	table = new Object[old.length * 2];
++	Arrays.fill (table, emptyslot);
++	size = 0;
++	for (int i = 0; i < old.length; i += 2)
++	  {
++	    if (old[i] != tombstone && old[i] != emptyslot)
++	      {
++		// Just use put.  This isn't very efficient, but it is
++		// ok.
++		put (old[i], old[i + 1]);
++	      }
++	  }
++      }
++
++    int h = getHash (key);
++    int save = h;
++    int del = -1;
++    while (true)
++      {
++	if (table[h] == key)
++	  {
++	    Object r = table[h + 1];
++	    table[h + 1] = value;
++	    return r;
++	  }
++	else if (table[h] == tombstone && del == -1)
++	  del = h;
++	else if (table[h] == emptyslot)
++	  {
++	    if (del == -1)
++	      del = h;
++	    break;
++	  }
++	h += 2;
++	if (h >= table.length)
++	  h = 0;
++	if (h == save)
++	  break;
++      }
++
++    if (del != -1)
+       {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          return new IdentityIterator(VALUES);
+-        }
+-
+-        public void clear()
+-        {
+-          IdentityHashMap.this.clear();
+-        }
+-
+-        public boolean remove(Object o)
+-        {
+-          for (int i = table.length - 1; i > 0; i -= 2)
+-            if (table[i] == o)
+-              {
+-                modCount++;
+-                table[i - 1] = tombstone;
+-                table[i] = tombstone;
+-                size--;
+-                return true;
+-              }
+-          return false;
+-        }
+-      };
+-    return values;
++	table[del] = key;
++	table[del + 1] = value;
++	++size;
++	return null;
++      }
++
++    // This is an error.
++    return null;
+   }
+ 
+-  /**
+-   * Helper method which computes the hash code, then traverses the table
+-   * until it finds the key, or the spot where the key would go.
+-   *
+-   * @param key the key to check
+-   * @return the index where the key belongs
+-   * @see #IdentityHashMap(int)
+-   * @see #put(Object, Object)
+-   */
+-  // Package visible for use by nested classes.
+-  int hash(Object key)
++  public Object remove (Object key)
+   {
+-    // Implementation note: it is feasible for the table to have no
+-    // emptyslots, if it is full with entries and tombstones, so we must
+-    // remember where we started. If we encounter the key or an emptyslot,
+-    // we are done.  If we encounter a tombstone, the key may still be in
+-    // the array.  If we don't encounter the key, we use the first emptyslot
+-    // or tombstone we encountered as the location where the key would go.
+-    // By requiring at least 2 key/value slots, and rehashing at 75%
+-    // capacity, we guarantee that there will always be either an emptyslot
+-    // or a tombstone somewhere in the table.
+-    int h = 2 * Math.abs(System.identityHashCode(key) % table.length);
+-    int del = -1;
++    int h = getHash (key);
+     int save = h;
+-
+-    do
++    while (true)
+       {
+-        if (table[h] == key)
+-          return h;
+-        if (table[h] == emptyslot)
+-          break;
+-        if (table[h] == tombstone && del < 0)
+-          del = h;
+-        h -= 2;
+-        if (h < 0)
+-          h = table.length - 2;
++	if (table[h] == key)
++	  {
++	    Object r = table[h + 1];
++	    table[h] = tombstone;
++	    table[h + 1] = tombstone;
++	    --size;
++	    return r;
++	  }
++	h += 2;
++	if (h >= table.length)
++	  h = 0;
++	if (h == save)
++	  break;
+       }
+-    while (h != save);
+ 
+-    return del < 0 ? h : del;
++    return null;
+   }
+ 
+-  /**
+-   * This class allows parameterized iteration over IdentityHashMaps.  Based
+-   * on its construction, it returns the key or value of a mapping, or
+-   * creates the appropriate Map.Entry object with the correct fail-fast
+-   * semantics and identity comparisons.
+-   *
+-   * @author Tom Tromey <tromey@redhat.com>
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private final class IdentityIterator implements Iterator
++  public int size ()
+   {
+-    /**
+-     * The type of this Iterator: {@link #KEYS}, {@link #VALUES},
+-     * or {@link #ENTRIES}.
+-     */
+-    final int type;
+-    /** The number of modifications to the backing Map that we know about. */
+-    int knownMod = modCount;
+-    /** The number of elements remaining to be returned by next(). */
+-    int count = size;
+-    /** Location in the table. */
+-    int loc = table.length;
+-
+-    /**
+-     * Construct a new Iterator with the supplied type.
+-     * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
+-     */
+-    IdentityIterator(int type)
+-    {
+-      this.type = type;
+-    }
+-
+-    /**
+-     * Returns true if the Iterator has more elements.
+-     * @return true if there are more elements
+-     * @throws ConcurrentModificationException if the Map was modified
+-     */
+-    public boolean hasNext()
+-    {
+-      if (knownMod != modCount)
+-        throw new ConcurrentModificationException();
+-      return count > 0;
+-    }
++    return size;
++  }
+ 
+-    /**
+-     * Returns the next element in the Iterator's sequential view.
+-     * @return the next element
+-     * @throws ConcurrentModificationException if the Map was modified
+-     * @throws NoSuchElementException if there is none
+-     */
+-    public Object next()
++  public Collection values ()
++  {
++    return new AbstractCollection ()
+     {
+-      if (knownMod != modCount)
+-        throw new ConcurrentModificationException();
+-      if (count == 0)
+-        throw new NoSuchElementException();
+-      count--;
+-
+-      Object key;
+-      do
+-        {
+-          loc -= 2;
+-          key = table[loc];
+-        }
+-      while (key == emptyslot || key == tombstone);
++      public int size ()
++      {
++	return size;
++      }
+ 
+-      return type == KEYS ? key : (type == VALUES ? table[loc + 1]
+-                                   : new IdentityEntry(loc));
+-    }
++      public Iterator iterator ()
++      {
++	return new IdentityIterator (IdentityIterator.VALUES);
++      }
+ 
+-    /**
+-     * Removes from the backing Map the last element which was fetched
+-     * with the <pre>next()</pre> method.
+-     * @throws ConcurrentModificationException if the Map was modified
+-     * @throws IllegalStateException if called when there is no last element
+-     */
+-    public void remove()
+-    {
+-      if (knownMod != modCount)
+-        throw new ConcurrentModificationException();
+-      if (loc == table.length || table[loc] == tombstone)
+-        throw new IllegalStateException();
+-      modCount++;
+-      size--;
+-      table[loc] = tombstone;
+-      table[loc + 1] = tombstone;
+-      knownMod++;
+-    }
+-  } // class IdentityIterator
++      public void clear ()
++      {
++	IdentityHashMap.this.clear ();
++      }
++    };
++  }
+ 
+-  /**
+-   * This class provides Map.Entry objects for IdentityHashMaps.  The entry
+-   * is fail-fast, and will throw a ConcurrentModificationException if
+-   * the underlying map is modified, or if remove is called on the iterator
+-   * that generated this object.  It is identity based, so it violates
+-   * the general contract of Map.Entry, and is probably unsuitable for
+-   * comparison to normal maps; but it works among other IdentityHashMaps.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private final class IdentityEntry implements Map.Entry
++  private class IdentityIterator implements Iterator
+   {
+-    /** The location of this entry. */
+-    final int loc;
+-    /** The number of modifications to the backing Map that we know about. */
+-    final int knownMod = modCount;
+-
+-    /**
+-     * Constructs the Entry.
+-     *
+-     * @param loc the location of this entry in table
+-     */
+-    IdentityEntry(int loc)
+-    {
+-      this.loc = loc;
+-    }
++    static final int KEYS = 0;
++    static final int VALUES = 1;
++    static final int ENTRIES = 2;
+ 
+-    /**
+-     * Compares the specified object with this entry, using identity
+-     * semantics. Note that this can lead to undefined results with
+-     * Entry objects created by normal maps.
+-     *
+-     * @param o the object to compare
+-     * @return true if it is equal
+-     * @throws ConcurrentModificationException if the entry was invalidated
+-     *         by modifying the Map or calling Iterator.remove()
+-     */
+-    public boolean equals(Object o)
+-    {
+-      if (knownMod != modCount || table[loc] == tombstone)
+-        throw new ConcurrentModificationException();
+-      if (! (o instanceof Map.Entry))
+-        return false;
+-      Map.Entry e = (Map.Entry) o;
+-      return table[loc] == e.getKey() && table[loc + 1] == e.getValue();
+-    }
+-
+-    /**
+-     * Returns the key of this entry.
+-     *
+-     * @return the key
+-     * @throws ConcurrentModificationException if the entry was invalidated
+-     *         by modifying the Map or calling Iterator.remove()
+-     */
+-    public Object getKey()
+-    {
+-      if (knownMod != modCount || table[loc] == tombstone)
+-        throw new ConcurrentModificationException();
+-      return table[loc];
+-    }
++    // Type of iterator.
++    int type;
++    // Location in the table.
++    int loc;
++    // How many items we've seen.
++    int seen;
+ 
+-    /**
+-     * Returns the value of this entry.
+-     *
+-     * @return the value
+-     * @throws ConcurrentModificationException if the entry was invalidated
+-     *         by modifying the Map or calling Iterator.remove()
+-     */
+-    public Object getValue()
++    IdentityIterator (int type)
+     {
+-      if (knownMod != modCount || table[loc] == tombstone)
+-        throw new ConcurrentModificationException();
+-      return table[loc + 1];
++      this.type = type;
++      loc = 0;
++      seen = 0;
+     }
+ 
+-    /**
+-     * Returns the hashcode of the entry, using identity semantics.
+-     * Note that this can lead to undefined results with Entry objects
+-     * created by normal maps.
+-     *
+-     * @return the hash code
+-     * @throws ConcurrentModificationException if the entry was invalidated
+-     *         by modifying the Map or calling Iterator.remove()
+-     */
+-    public int hashCode()
++    public boolean hasNext ()
+     {
+-      if (knownMod != modCount || table[loc] == tombstone)
+-        throw new ConcurrentModificationException();
+-      return (System.identityHashCode(table[loc])
+-              ^ System.identityHashCode(table[loc + 1]));
++      return seen < size;
+     }
+ 
+-    /**
+-     * Replaces the value of this mapping, and returns the old value.
+-     *
+-     * @param value the new value
+-     * @return the old value
+-     * @throws ConcurrentModificationException if the entry was invalidated
+-     *         by modifying the Map or calling Iterator.remove()
+-     */
+-    public Object setValue(Object value)
++    public Object next ()
+     {
+-      if (knownMod != modCount || table[loc] == tombstone)
+-        throw new ConcurrentModificationException();
+-      Object r = table[loc + 1];
+-      table[loc + 1] = value;
+-      return r;
++      while (true)
++	{
++	  loc += 2;
++	  if (loc >= table.length)
++	    throw new NoSuchElementException ();
++	  if (table[loc] != tombstone && table[loc] != emptyslot)
++	    {
++	      ++seen;
++	      return table[loc];
++	    }
++	}
+     }
+ 
+-    /**
+-     * This provides a string representation of the entry. It is of the form
+-     * "key=value", where string concatenation is used on key and value.
+-     *
+-     * @return the string representation
+-     * @throws ConcurrentModificationException if the entry was invalidated
+-     *         by modifying the Map or calling Iterator.remove()
+-     */
+-    public final String toString()
++    public void remove ()
+     {
+-      if (knownMod != modCount || table[loc] == tombstone)
+-        throw new ConcurrentModificationException();
+-      return table[loc] + "=" + table[loc + 1];
++      if (loc >= table.length
++	  || table[loc] == tombstone
++	  || table[loc] == emptyslot)
++	throw new IllegalStateException ();
++      table[loc] = tombstone;
++      table[loc + 1] = tombstone;
++      --size;
+     }
+-  } // class IdentityEntry
++  }
+ 
+-  /**
+-   * Reads the object from a serial stream.
+-   *
+-   * @param s the stream to read from
+-   * @throws ClassNotFoundException if the underlying stream fails
+-   * @throws IOException if the underlying stream fails
+-   * @serialData expects the size (int), followed by that many key (Object)
+-   *             and value (Object) pairs, with the pairs in no particular
+-   *             order
+-   */
+-  private void readObject(ObjectInputStream s)
++  private void readObject (ObjectInputStream s)
+     throws IOException, ClassNotFoundException
+   {
+-    s.defaultReadObject();
+-
+-    int num = s.readInt();
+-    table = new Object[2 * Math.max(num * 2, DEFAULT_CAPACITY)];
+-    // Read key/value pairs.
+-    while (--num >= 0)
+-      put(s.readObject(), s.readObject());
++    int num = s.readInt ();
++    for (int i = 0; i < num; ++i)
++      {
++	Object key = s.readObject ();
++	Object value = s.readObject ();
++	put (key, value);
++      }
+   }
+ 
+-  /**
+-   * Writes the object to a serial stream.
+-   *
+-   * @param s the stream to write to
+-   * @throws IOException if the underlying stream fails
+-   * @serialData outputs the size (int), followed by that many key (Object)
+-   *             and value (Object) pairs, with the pairs in no particular
+-   *             order
+-   */
+-  private void writeObject(ObjectOutputStream s)
++  private void writeObject (ObjectOutputStream s)
+     throws IOException
+   {
+-    s.defaultWriteObject();
+-    s.writeInt(size);
+-    for (int i = table.length - 2; i >= 0; i -= 2)
+-      {
+-        Object key = table[i];
+-        if (key != tombstone && key != emptyslot)
+-          {
+-            s.writeObject(key);
+-            s.writeObject(table[i + 1]);
+-          }
++    s.writeInt (size);
++    Iterator it = entrySet ().iterator ();
++    while (it.hasNext ())
++      {
++	Map.Entry entry = (Map.Entry) it.next ();
++	s.writeObject (entry.getKey ());
++	s.writeObject (entry.getValue ());
+       }
+   }
++
++  // Compute the hash value we will use for an object.
++  private int getHash (Object o)
++  {
++    return 2 * Math.abs (System.identityHashCode (o) % (table.length / 2));
++  }
++
++  // Number of items in hash table.
++  private int size;
++  // The table itself.
++  private Object[] table;
++
++  // This object is used to mark deleted items.
++  private static final Object tombstone = new Object ();
++  // This object is used to mark empty slots.  We need this because
++  // using null is ambiguous.
++  private static final Object emptyslot = new Object ();
+ }
Index: compare/java.util.LinkedHashMap.diff
===================================================================
RCS file: java.util.LinkedHashMap.diff
diff -N java.util.LinkedHashMap.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.LinkedHashMap.diff Tue Nov 6 17:21:34 2001
@@ -0,0 +1,105 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/LinkedHashMap.java	Fri Oct 26 16:06:57 2001
++++ java/util/LinkedHashMap.java	Mon Oct 15 23:47:01 2001
+@@ -28,6 +28,11 @@
+ 
+ package java.util;
+ 
++import java.io.IOException;
++import java.io.Serializable;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++
+ /**
+  * This class provides a hashtable-backed implementation of the
+  * Map interface, with predictable traversal order.
+@@ -84,7 +89,6 @@
+  * @see TreeMap
+  * @see Hashtable
+  * @since 1.4
+- * @status updated to 1.4
+  */
+ public class LinkedHashMap extends HashMap
+ {
+@@ -214,8 +218,8 @@
+    * Construct a new insertion-ordered LinkedHashMap with a specific
+    * inital capacity and default load factor of 0.75.
+    *
+-   * @param initialCapacity the initial capacity of this HashMap (&gt;= 0)
+-   * @throws IllegalArgumentException if (initialCapacity &lt; 0)
++   * @param initialCapacity the initial capacity of this HashMap (>=0)
++   * @throws IllegalArgumentException if (initialCapacity < 0)
+    */
+   public LinkedHashMap(int initialCapacity)
+   {
+@@ -227,10 +231,10 @@
+    * Construct a new insertion-orderd LinkedHashMap with a specific
+    * inital capacity and load factor.
+    *
+-   * @param initialCapacity the initial capacity (&gt;= 0)
+-   * @param loadFactor the load factor (&gt; 0, not NaN)
+-   * @throws IllegalArgumentException if (initialCapacity &lt; 0) ||
+-   *                                     ! (loadFactor &gt; 0.0)
++   * @param initialCapacity the initial capacity (>=0)
++   * @param loadFactor the load factor (>0, not NaN)
++   * @throws IllegalArgumentException if (initialCapacity < 0) ||
++   *                                     ! (loadFactor > 0.0)
+    */
+   public LinkedHashMap(int initialCapacity, float loadFactor)
+   {
+@@ -277,7 +281,7 @@
+     LinkedHashEntry e = head;
+     while (e != null)
+       {
+-        if (equals(value, e.value))
++        if (value == null ? e.value == null : value.equals(e.value))
+           return true;
+         e = e.succ;
+       }
+@@ -303,7 +307,7 @@
+     HashEntry e = buckets[idx];
+     while (e != null)
+       {
+-        if (equals(key, e.key))
++        if (key == null ? e.key == null : key.equals(e.key))
+           {
+             if (accessOrder)
+               {
+@@ -372,14 +376,13 @@
+     return false;
+   }
+ 
+-  /**
+-   * Helper method called by <code>put</code>, which creates and adds a
++  /** Helper method called by <code>put</code>, which creates and adds a
+    * new Entry, followed by performing bookkeeping (like removeEldestEntry).
+    *
+    * @param key the key of the new Entry
+    * @param value the value
+    * @param idx the index in buckets where the new Entry belongs
+-   * @param callRemove whether to call the removeEldestEntry method
++   * @param callRemove Whether to call the removeEldestEntry method.
+    * @see #put(Object, Object)
+    * @see #removeEldestEntry(Map.Entry)
+    */
+@@ -394,11 +397,6 @@
+       remove(head);
+   }
+ 
+-  /**
+-   * Helper method, called by clone() to reset the doubly-linked list.
+-   * @param m the map to add entries from
+-   * @see #clone()
+-   */
+   void putAllInternal(Map m)
+   {
+     head = null;
+@@ -468,8 +466,8 @@
+           throw new IllegalStateException();
+ 
+         LinkedHashMap.this.remove(last.key);
+-        last = null;
+         knownMod++;
++        last = null;
+       }
+     };
+   }
Index: compare/java.util.LinkedList.diff
===================================================================
RCS file: java.util.LinkedList.diff
diff -N java.util.LinkedList.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.LinkedList.diff Tue Nov 6 17:21:35 2001
@@ -0,0 +1,1125 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/LinkedList.java	Fri Oct 26 16:06:57 2001
++++ java/util/LinkedList.java	Tue Oct 16 09:14:34 2001
+@@ -1,5 +1,5 @@
+ /* LinkedList.java -- Linked list implementation of the List interface
+-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -32,49 +32,25 @@
+ import java.io.IOException;
+ import java.lang.reflect.Array;
+ 
++// TO DO:
++// ~ Doc comment for the class.
++// ~ Doc comments for the non-list methods.
++// ~ other general implementation notes.
++
+ /**
+- * Linked list implementation of the List interface. In addition to the
+- * methods of the List interface, this class provides access to the first
+- * and last list elements in O(1) time for easy stack, queue, or double-ended
+- * queue (deque) creation. The list is doubly-linked, with traversal to a
+- * given index starting from the end closest to the element.<p>
+- *
+- * LinkedList is not synchronized, so if you need multi-threaded access,
+- * consider using:<br>
+- * <code>List l = Collections.synchronizedList(new LinkedList(...));</code>
+- * <p>
+- *
+- * The iterators are <i>fail-fast</i>, meaning that any structural
+- * modification, except for <code>remove()</code> called on the iterator
+- * itself, cause the iterator to throw a
+- * {@link ConcurrentModificationException} rather than exhibit
+- * non-deterministic behavior.
+- *
+- * @author Original author unknown
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see List
+- * @see ArrayList
+- * @see Vector
+- * @see Collections#synchronizedList(List)
+- * @since 1.2
+- * @status missing javadoc, but complete to 1.4
++ * Linked list implementation of the List interface.
+  */
+ public class LinkedList extends AbstractSequentialList
+   implements List, Cloneable, Serializable
+ {
+-  /**
+-   * Compatible with JDK 1.2.
+-   */
+-  private static final long serialVersionUID = 876323262645176354L;
++  static final long serialVersionUID = 876323262645176354L;
+ 
+   /**
+-   * The first element in the list.
++   * An Entry containing the head (in the next field) and the tail (in the
++   * previous field) of the list. The data field is null. If the list is empty,
++   * both the head and the tail point to ends itself.
+    */
+   transient Entry first;
+-
+-  /**
+-   * The last element in the list.
+-   */
+   transient Entry last;
+ 
+   /**
+@@ -85,27 +61,18 @@
+   /**
+    * Class to represent an entry in the list. Holds a single element.
+    */
+-  private static final class Entry
++  private static class Entry
+   {
+-    /** The element in the list. */
+     Object data;
+-
+-    /** The next list entry, null if this is last. */
+     Entry next;
+-
+-    /** The previous list entry, null if this is first. */
+     Entry previous;
+-
+-    /**
+-     * Construct an entry.
+-     * @param data the list element
+-     */
++    
+     Entry(Object data)
+     {
+       this.data = data;
+     }
+-  } // class Entry
+-
++  }
++  
+   /**
+    * Obtain the Entry at a given position in a list. This method of course
+    * takes linear time, but it is intelligent enough to take the shorter of the
+@@ -115,8 +82,7 @@
+    * For speed and flexibility, range checking is not done in this method:
+    * Incorrect values will be returned if (n < 0) or (n >= size).
+    *
+-   * @param n the number of the entry to get
+-   * @return the entry at position n
++   * @param n the number of the entry to get.
+    */
+   private Entry getEntry(int n)
+   {
+@@ -124,76 +90,50 @@
+     if (n < size / 2)
+       {
+         e = first;
+-        // n less than size/2, iterate from start
+-        while (n-- > 0)
+-          e = e.next;
++	// n less than size/2, iterate from start
++	while (n-- > 0)
++	  {
++	    e = e.next;
++	  }
+       }
+     else
+       {
+-        e = last;
+-        // n greater than size/2, iterate from end
+-        while (++n < size)
+-          e = e.previous;
++        e = last;      
++	// n greater than size/2, iterate from end
++	while (++n < size)
++	  {
++	    e = e.previous;
++	  }
+       }
+     return e;
+   }
+-
+-  /**
+-   * Remove an entry from the list. This will adjust size and deal with
+-   *  `first' and  `last' appropriatly.
+-   *
+-   * @param e the entry to remove
+-   */
++  
++  /** Remove an entry from the list. This will adjust size and deal with
++   *  `first' and  `last' appropriatly. It does not effect modCount, that is 
++   *  the responsibility of the caller. */
+   private void removeEntry(Entry e)
+   {
+-    modCount++;
+-    size--;
+-    if (size == 0)
++    if (size == 1)
+       first = last = null;
+     else
+       {
+-        if (e == first)
+-          {
+-            first = e.next;
+-            e.next.previous = null;
+-          }
+-        else if (e == last)
+-          {
+-            last = e.previous;
+-            e.previous.next = null;
+-          }
+-        else
+-          {
+-            e.next.previous = e.previous;
+-            e.previous.next = e.next;
+-          }
++	if (e == first)
++	  {
++	    first = e.next;
++	    e.next.previous = null;
++	  }
++	else if (e == last)
++	  {
++	    last = e.previous;
++	    e.previous.next = null;
++	  }
++	else
++	  {
++	    e.next.previous = e.previous;	
++	    e.previous.next = e.next;
++	  }
+       }
+-  }
+-
+-  /**
+-   * Checks that the index is in the range of possible elements (inclusive).
+-   *
+-   * @param index the index to check
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size
+-   */
+-  private void checkBoundsInclusive(int index)
+-  {
+-    if (index < 0 || index > size)
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size);
+-  }
+-
+-  /**
+-   * Checks that the index is in the range of existing elements (exclusive).
+-   *
+-   * @param index the index to check
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size
+-   */
+-  private void checkBoundsExclusive(int index)
+-  {
+-    if (index < 0 || index >= size)
+-      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+-                                          + size);
++    size--;
+   }
+ 
+   /**
+@@ -201,26 +141,24 @@
+    */
+   public LinkedList()
+   {
++    super();
+   }
+ 
+   /**
+    * Create a linked list containing the elements, in order, of a given
+    * collection.
+    *
+-   * @param c the collection to populate this list from
+-   * @throws NullPointerException if c is null
++   * @param c the collection to populate this list from.
+    */
+   public LinkedList(Collection c)
+   {
++    super();
++    // Note: addAll could be made slightly faster, but not enough so to justify
++    // re-implementing it from scratch. It is just a matter of a relatively
++    // small constant factor.
+     addAll(c);
+   }
+ 
+-  /**
+-   * Returns the first element in the list.
+-   *
+-   * @return the first list element
+-   * @throws NoSuchElementException if the list is empty
+-   */
+   public Object getFirst()
+   {
+     if (size == 0)
+@@ -228,12 +166,6 @@
+     return first.data;
+   }
+ 
+-  /**
+-   * Returns the last element in the list.
+-   *
+-   * @return the last list element
+-   * @throws NoSuchElementException if the list is empty
+-   */
+   public Object getLast()
+   {
+     if (size == 0)
+@@ -241,374 +173,273 @@
+     return last.data;
+   }
+ 
+-  /**
+-   * Remove and return the first element in the list.
+-   *
+-   * @return the former first element in the list
+-   * @throws NoSuchElementException if the list is empty
+-   */
+   public Object removeFirst()
+   {
+     if (size == 0)
+       throw new NoSuchElementException();
+-    modCount++;
+     size--;
++    modCount++;
+     Object r = first.data;
+-
++    
+     if (first.next != null)
+       first.next.previous = null;
+     else
+       last = null;
+ 
+     first = first.next;
+-
++    
+     return r;
+   }
+ 
+-  /**
+-   * Remove and return the last element in the list.
+-   *
+-   * @return the former last element in the list
+-   * @throws NoSuchElementException if the list is empty
+-   */
+   public Object removeLast()
+   {
+     if (size == 0)
+       throw new NoSuchElementException();
+-    modCount++;
+     size--;
++    modCount++;
+     Object r = last.data;
+-
++    
+     if (last.previous != null)
+       last.previous.next = null;
+     else
+       first = null;
+-
++    
+     last = last.previous;
+-
++    
+     return r;
+   }
+ 
+-  /**
+-   * Insert an element at the first of the list.
+-   *
+-   * @param o the element to insert
+-   */
+   public void addFirst(Object o)
+   {
+-    Entry e = new Entry(o);
+-
+     modCount++;
+-    size++;
+-    if (size == 1)
++    Entry e = new Entry(o);
++    
++    if (size == 0)
+       first = last = e;
+     else
+       {
+-        e.next = first;
++	e.next = first;
+         first.previous = e;
+-        first = e;
+-      }
++	first = e;
++      }    
++    size++;
+   }
+ 
+-  /**
+-   * Insert an element at the last of the list.
+-   *
+-   * @param o the element to insert
+-   */
+   public void addLast(Object o)
+   {
++    modCount++;
+     addLastEntry(new Entry(o));
+   }
+-
+-  /**
+-   * Inserts an element at the end of the list.
+-   *
+-   * @param e the entry to add
+-   */
++  
+   private void addLastEntry(Entry e)
+   {
+-    modCount++;
+-    size++;
+     if (size == 0)
+       first = last = e;
+     else
+       {
+-        e.previous = last;
++	e.previous = last;
+         last.next = e;
+-        last = e;
++	last = e;
+       }
++    size++;
+   }
+ 
+-  /**
+-   * Returns true if the list contains the given object. Comparison is done by
+-   * <code>o == null ? e = null : o.equals(e)</code>.
+-   *
+-   * @param o the element to look for
+-   * @return true if it is found
+-   */
+   public boolean contains(Object o)
+   {
+     Entry e = first;
+     while (e != null)
+       {
+-        if (equals(o, e.data))
+-          return true;
++        if (e.data == null ? o == null : o.equals(e.data))
++	  return true;
+         e = e.next;
+       }
+     return false;
+   }
+ 
+-  /**
+-   * Returns the size of the list.
+-   *
+-   * @return the list size
+-   */
+   public int size()
+   {
+     return size;
+   }
+-
+-  /**
+-   * Adds an element to the end of the list.
+-   *
+-   * @param e the entry to add
+-   * @return true, as it always succeeds
+-   */
++  
+   public boolean add(Object o)
+   {
++    modCount++;
+     addLastEntry(new Entry(o));
+     return true;
+   }
+-
+-  /**
+-   * Removes the entry at the lowest index in the list that matches the given
+-   * object, comparing by <code>o == null ? e = null : o.equals(e)</code>.
+-   *
+-   * @param o the object to remove
+-   * @return true if an instance of the object was removed
+-   */
++  
+   public boolean remove(Object o)
+   {
++    modCount++;
+     Entry e = first;
+     while (e != null)
+       {
+-        if (equals(o, e.data))
+-          {
+-            removeEntry(e);
+-            return true;
+-          }
++        if (e.data == null ? o == null : o.equals(e.data))
++	  {
++	    removeEntry(e);
++	    return true;
++	  }
+         e = e.next;
+       }
+     return false;
+   }
+ 
+-  /**
+-   * Append the elements of the collection in iteration order to the end of
+-   * this list. If this list is modified externally (for example, if this
+-   * list is the collection), behavior is unspecified.
+-   *
+-   * @param c the collection to append
+-   * @return true if the list was modified
+-   * @throws NullPointerException if c is null
+-   */
+   public boolean addAll(Collection c)
+   {
+     return addAll(size, c);
+   }
+-
+-  /**
+-   * Insert the elements of the collection in iteration order at the given
+-   * index of this list. If this list is modified externally (for example,
+-   * if this list is the collection), behavior is unspecified.
+-   *
+-   * @param c the collection to append
+-   * @return true if the list was modified
+-   * @throws NullPointerException if c is null
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
+-   */
++  
+   public boolean addAll(int index, Collection c)
+   {
+-    checkBoundsInclusive(index);
++    if (index < 0 || index > size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
++    modCount++;
+     int csize = c.size();
+ 
+     if (csize == 0)
+       return false;
+ 
+     Iterator itr = c.iterator();
+-
++    
+     // Get the entries just before and after index. If index is at the start
+-    // of the list, BEFORE is null. If index is at the end of the list, AFTER
+-    // is null. If the list is empty, both are null.
++    // of the list, BEFORE is null. If index is at the end of thelist, AFTER is
++    // null. If the list is empty, both are null.
+     Entry after = null;
+-    Entry before = null;
++    Entry before = null;    
+     if (index != size)
+       {
+-        after = getEntry(index);
+-        before = after.previous;
++	after = getEntry(index);
++	before = after.previous;
+       }
+     else
+       before = last;
+-
++      
+     // Create the first new entry. We do not yet set the link from `before'
+-    // to the first entry, in order to deal with the case where (c == this).
+-    // [Actually, we don't have to handle this case to fufill the
++    // to the first entry, in order to deal with the case where (c == this). 
++    // [Actually, we don't have to handle this case to fufill the 
+     // contract for addAll(), but Sun's implementation appears to.]
+     Entry e = new Entry(itr.next());
+     e.previous = before;
+     Entry prev = e;
+     Entry firstNew = e;
+-
++    
+     // Create and link all the remaining entries.
+     for (int pos = 1; pos < csize; pos++)
+       {
+         e = new Entry(itr.next());
+-        e.previous = prev;
+-        prev.next = e;
+-        prev = e;
++	e.previous = prev;	
++	prev.next = e;
++	prev = e;
+       }
+-
+     // Link the new chain of entries into the list.
+-    modCount++;
+-    size += csize;
+     prev.next = after;
+     if (after != null)
+       after.previous = e;
+     else
+       last = e;
+-
++    
+     if (before != null)
+       before.next = firstNew;
+     else
+       first = firstNew;
++    
++    size += csize;
+     return true;
+   }
+ 
+-  /**
+-   * Remove all elements from this list.
+-   */
+   public void clear()
+   {
+-    if (size > 0)
+-      {
+-        modCount++;
+-        first = null;
+-        last = null;
+-        size = 0;
+-      }
++    modCount++;
++    first = null;
++    last = null;
++    size = 0;
+   }
+ 
+-  /**
+-   * Return the element at index.
+-   *
+-   * @param index the place to look
+-   * @return the element at index
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   */
+   public Object get(int index)
+   {
+-    checkBoundsExclusive(index);
+-    return getEntry(index).data;
++    if (index < 0 || index >= size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
++    Entry e = getEntry(index);
++    return e.data;
+   }
+-
+-  /**
+-   * Replace the element at the given location in the list.
+-   *
+-   * @param index which index to change
+-   * @param o the new element
+-   * @return the prior element
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
+-   */
++  
+   public Object set(int index, Object o)
+   {
+-    checkBoundsExclusive(index);
++    if (index < 0 || index >= size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
+     Entry e = getEntry(index);
+     Object old = e.data;
+     e.data = o;
+     return old;
+   }
+ 
+-  /**
+-   * Inserts an element in the given position in the list.
+-   *
+-   * @param index where to insert the element
+-   * @param o the element to insert
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
+-   */
+   public void add(int index, Object o)
+   {
+-    checkBoundsInclusive(index);
+-    Entry e = new Entry(o);
+-
++    if (index < 0 || index > size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
++    modCount++;
++    addEntry(index, new Entry(o));    
++  }
++  
++  private void addEntry(int index, Entry e)
++  {
+     if (index < size)
+       {
+-        modCount++;
+-        size++;
+-        Entry after = getEntry(index);
+-        e.next = after;
+-        e.previous = after.previous;
+-        if (after.previous == null)
+-          first = e;
+-        else
+-          after.previous.next = e;
+-        after.previous = e;
++	Entry after = getEntry(index);
++	e.next = after;
++	e.previous = after.previous;
++	if (after.previous == null)
++	  first = e;
++	else
++	  after.previous.next = e;
++	after.previous = e;
++	size++;        
+       }
+     else
+       addLastEntry(e);
+   }
+-
+-  /**
+-   * Removes the element at the given position from the list.
+-   *
+-   * @param index the location of the element to remove
+-   * @return the removed element
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
+-   */
++  
+   public Object remove(int index)
+   {
+-    checkBoundsExclusive(index);
++    if (index < 0 || index >= size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
++    modCount++;
+     Entry e = getEntry(index);
+     removeEntry(e);
+     return e.data;
+   }
+-
+-  /**
+-   * Returns the first index where the element is located in the list, or -1.
+-   *
+-   * @param o the element to look for
+-   * @return its position, or -1 if not found
+-   */
++  
+   public int indexOf(Object o)
+   {
+     int index = 0;
+     Entry e = first;
+     while (e != null)
+       {
+-        if (equals(o, e.data))
+-          return index;
+-        index++;
++        if (e.data == null ? o == null : o.equals(e.data))
++	  return index;
++	++index;
+         e = e.next;
+       }
+     return -1;
+   }
+-
+-  /**
+-   * Returns the last index where the element is located in the list, or -1.
+-   *
+-   * @param o the element to look for
+-   * @return its position, or -1 if not found
+-   */
++  
+   public int lastIndexOf(Object o)
+   {
+     int index = size - 1;
+     Entry e = last;
+     while (e != null)
+       {
+-        if (equals(o, e.data))
+-          return index;
+-        index--;
++        if (e.data == null ? o == null : o.equals(e.data))
++	  return index;
++	--index;
+         e = e.previous;
+       }
+-    return -1;
++    return -1;  
+   }
+ 
+   /**
+@@ -617,27 +448,28 @@
+    * methods.
+    *
+    * @param index the index of the element to be returned by the first call to
+-   *        next(), or size() to be initially positioned at the end of the list
+-   * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
++   *   next(), or size() to be initially positioned at the end of the list.
++   * @exception IndexOutOfBoundsException if index < 0 || index > size().
+    */
+   public ListIterator listIterator(int index)
+   {
+-    checkBoundsInclusive(index);
++    if (index < 0 || index > size)
++      throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + 
++                                          size);
+     return new LinkedListItr(index);
+   }
+ 
+   /**
+-   * Create a shallow copy of this LinkedList (the elements are not cloned).
+-   *
++   * Create a shallow copy of this LinkedList.
+    * @return an object of the same class as this object, containing the
+-   *         same elements in the same order
++   * same elements in the same order.
+    */
+   public Object clone()
+   {
+     LinkedList copy = null;
+     try
+       {
+-        copy = (LinkedList) super.clone();
++	copy = (LinkedList) super.clone();
+       }
+     catch (CloneNotSupportedException ex)
+       {
+@@ -646,12 +478,7 @@
+     copy.addAll(this);
+     return copy;
+   }
+-
+-  /**
+-   * Returns an array which contains the elements of the list in order.
+-   *
+-   * @return an array containing the list elements
+-   */
++  
+   public Object[] toArray()
+   {
+     Object[] array = new Object[size];
+@@ -663,285 +490,182 @@
+       }
+     return array;
+   }
+-
+-  /**
+-   * Returns an Array whose component type is the runtime component type of
+-   * the passed-in Array.  The returned Array is populated with all of the
+-   * elements in this LinkedList.  If the passed-in Array is not large enough
+-   * to store all of the elements in this List, a new Array will be created 
+-   * and returned; if the passed-in Array is <i>larger</i> than the size
+-   * of this List, then size() index will be set to null.
+-   *
+-   * @param a the passed-in Array
+-   * @return an array representation of this list
+-   * @throws ArrayStoreException if the runtime type of a does not allow
+-   *         an element in this list
+-   * @throws NullPointerException if a is null
+-   */
+-  public Object[] toArray(Object[] a)
+-  {
+-    if (a.length < size)
+-      a = (Object[]) Array.newInstance(a.getClass().getComponentType(), size);
+-    else if (a.length > size)
+-      a[size] = null;
++  
++  public Object[] toArray(Object[] array)
++  {
++    if (array.length < size)
++      array = (Object[]) Array.newInstance(array.getClass().getComponentType(), 
++        				   size);
++    else if (array.length > size)
++      array[size] = null;
+     Entry e = first;
+     for (int i = 0; i < size; i++)
+       {
+-        a[i] = e.data;
++        array[i] = e.data;
+         e = e.next;
+       }
+-    return a;
++    return array;  
+   }
+ 
+   /**
+-   * Serializes this object to the given stream.
+-   *
+-   * @param s the stream to write to
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the size of the list (int), followed by all the elements
+-   *             (Object) in proper order
++   * Serialize an object to a stream.
++   * @serialdata the size of the list (int), followed by all the elements
++   * (Object) in proper order.
+    */
+   private void writeObject(ObjectOutputStream s) throws IOException
+   {
+-    s.defaultWriteObject();
+     s.writeInt(size);
+-    Entry e = first;
+-    while (e != null)
+-      {
+-        s.writeObject(e.data);
+-        e = e.next;
+-      }
++    Iterator itr = iterator();
++    for (int i = 0; i < size; i++)
++      s.writeObject(itr.next());
+   }
+ 
+   /**
+-   * Deserializes this object from the given stream.
+-   *
+-   * @param s the stream to read from
+-   * @throws ClassNotFoundException if the underlying stream fails
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the size of the list (int), followed by all the elements
+-   *             (Object) in proper order
++   * Deserialize an object from a stream.
++   * @serialdata the size of the list (int), followed by all the elements
++   * (Object) in proper order.
+    */
+   private void readObject(ObjectInputStream s)
+     throws IOException, ClassNotFoundException
+   {
+-    s.defaultReadObject();
+-    int i = s.readInt();
+-    while (--i >= 0)
++    int serialSize = s.readInt();
++    for (int i = 0; i < serialSize; i++)
+       addLastEntry(new Entry(s.readObject()));
+   }
+-
+-  /**
+-   * A ListIterator over the list. This class keeps track of its
++  
++  /** A ListIterator over the list. This class keeps track of its
+    * position in the list and the two list entries it is between.
+-   *
+-   * @author Original author unknown
+-   * @author Eric Blake <ebb9@email.byu.edu>
+    */
+-  private final class LinkedListItr implements ListIterator
++  class LinkedListItr implements ListIterator
+   {
+-    /** Number of modifications we know about. */
+-    private int knownMod = modCount;
+-
+-    /** Entry that will be returned by next(). */
+-    private Entry next;
++    int knownMod;
++    Entry next;         // entry that will be returned by next().
++    Entry previous;     // entry that will be returned by previous().
++    Entry lastReturned; // entry that will be affected by remove() or set().
++    int position;       // index of `next'.
+ 
+-    /** Entry that will be returned by previous(). */
+-    private Entry previous;
+-
+-    /** Entry that will be affected by remove() or set(). */
+-    private Entry lastReturned;
+-
+-    /** Index of `next'. */
+-    private int position;
+-
+-    /**
+-     * Initialize the iterator.
+-     *
+-     * @param index the initial index
+-     */
+     LinkedListItr(int index)
+     {
+       if (index == size)
+         {
+           next = null;
+-          previous = last;
+-        }
++	  previous = last;
++	}
+       else
+         {
+           next = getEntry(index);
+-          previous = next.previous;
+-        }
++	  previous = next.previous;
++	}
+       position = index;
++      knownMod = modCount;
+     }
+ 
+-    /**
+-     * Checks for iterator consistency.
+-     *
+-     * @throws ConcurrentModificationException if the list was modified
+-     */
+     private void checkMod()
+     {
+       if (knownMod != modCount)
+-        throw new ConcurrentModificationException();
++	throw new ConcurrentModificationException();
+     }
+ 
+-    /**
+-     * Returns the index of the next element.
+-     *
+-     * @return the next index
+-     * @throws ConcurrentModificationException if the list was modified
+-     */
+     public int nextIndex()
+     {
+       checkMod();
+       return position;
+     }
+ 
+-    /**
+-     * Returns the index of the previous element.
+-     *
+-     * @return the previous index
+-     * @throws ConcurrentModificationException if the list was modified
+-     */
+     public int previousIndex()
+     {
+       checkMod();
+       return position - 1;
+     }
+ 
+-    /**
+-     * Returns true if more elements exist via next.
+-     *
+-     * @return true if next will succeed
+-     * @throws ConcurrentModificationException if the list was modified
+-     */
+     public boolean hasNext()
+     {
+       checkMod();
+       return (next != null);
+     }
+ 
+-    /**
+-     * Returns true if more elements exist via previous.
+-     *
+-     * @return true if previous will succeed
+-     * @throws ConcurrentModificationException if the list was modified
+-     */
+     public boolean hasPrevious()
+     {
+       checkMod();
+       return (previous != null);
+     }
+ 
+-    /**
+-     * Returns the next element.
+-     *
+-     * @return the next element
+-     * @throws ConcurrentModificationException if the list was modified
+-     * @throws NoSuchElementException if there is no next
+-     */
+     public Object next()
+     {
+       checkMod();
+       if (next == null)
+-        throw new NoSuchElementException();
++	throw new NoSuchElementException();
+       position++;
+       lastReturned = previous = next;
+       next = lastReturned.next;
+       return lastReturned.data;
+     }
+ 
+-    /**
+-     * Returns the previous element.
+-     *
+-     * @return the previous element
+-     * @throws ConcurrentModificationException if the list was modified
+-     * @throws NoSuchElementException if there is no previous
+-     */
+     public Object previous()
+     {
+       checkMod();
+       if (previous == null)
+-        throw new NoSuchElementException();
++	throw new NoSuchElementException();
+       position--;
+       lastReturned = next = previous;
+       previous = lastReturned.previous;
+       return lastReturned.data;
+     }
+ 
+-    /**
+-     * Remove the most recently returned element from the list.
+-     *
+-     * @throws ConcurrentModificationException if the list was modified
+-     * @throws IllegalStateException if there was no last element
+-     */
+     public void remove()
+     {
+       checkMod();
+       if (lastReturned == null)
+-        throw new IllegalStateException();
++	throw new IllegalStateException();
+ 
+       // Adjust the position to before the removed element, if the element
+       // being removed is behind the cursor.
+       if (lastReturned == previous)
+-        position--;
++	position--;
+ 
+       next = lastReturned.next;
+       previous = lastReturned.previous;
+-      removeEntry(lastReturned);
++      modCount++;
+       knownMod++;
+-
++      removeEntry(lastReturned);
++      
+       lastReturned = null;
+     }
+ 
+-    /**
+-     * Adds an element between the previous and next, and advance to the next.
+-     *
+-     * @param o the element to add
+-     * @throws ConcurrentModificationException if the list was modified
+-     */
+     public void add(Object o)
+     {
+       checkMod();
+       modCount++;
+       knownMod++;
+-      size++;
+-      position++;
+       Entry e = new Entry(o);
+       e.previous = previous;
+       e.next = next;
+ 
+       if (previous != null)
+-        previous.next = e;
++	previous.next = e;
+       else
+-        first = e;
++	first = e;
+ 
+       if (next != null)
+         {
+-          next.previous = e;
+-          next = next.next;
+-        }
++	  next.previous = e;
++	  next = next.next;
++	}
+       else
+-        last = e;
++	last = e;
+ 
+       previous = e;
++      size++;
++      position++;
+       lastReturned = null;
+     }
+ 
+-    /**
+-     * Changes the contents of the element most recently returned.
+-     *
+-     * @param o the new element
+-     * @throws ConcurrentModificationException if the list was modified
+-     * @throws IllegalStateException if there was no last element
+-     */
+     public void set(Object o)
+     {
+       checkMod();
+       if (lastReturned == null)
+-        throw new IllegalStateException();
++	throw new IllegalStateException();
+       lastReturned.data = o;
+     }
+-  } // class LinkedListItr
++  }  // class LinkedListItr  
+ }
Index: compare/java.util.List.diff
===================================================================
RCS file: java.util.List.diff
diff -N java.util.List.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.List.diff Tue Nov 6 17:21:35 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/List.java	Mon Oct 15 10:45:18 2001
++++ java/util/List.java	Fri Nov  2 21:44:52 2001
+@@ -288,7 +288,7 @@
+   Object remove(int index);
+ 
+   /**
+-   * Remove the first occurence of an object from this list (optional
++   * Remove the first occurrence of an object from this list (optional
+    * operation). That is, remove the first element e such that
+    * <code>o == null ? e == null : o.equals(e)</code>.
+    *
Index: compare/java.util.NoSuchElementException.diff
===================================================================
RCS file: java.util.NoSuchElementException.diff
diff -N java.util.NoSuchElementException.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.NoSuchElementException.diff Tue Nov 6 17:21:35 2001
@@ -0,0 +1,48 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/NoSuchElementException.java	Mon Oct 22 22:24:19 2001
++++ java/util/NoSuchElementException.java	Tue Oct 16 09:14:34 2001
+@@ -30,32 +30,20 @@
+ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+  * "The Java Language Specification", ISBN 0-201-63451-1
+  * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
++ * Status:  Believed complete and correct.
+  */
+ 
+ /**
+  * Exception thrown when an attempt is made to access an element that does not
+- * exist. This exception is thrown by the Enumeration, Iterator and
+- * ListIterator classes if the nextElement, next or previous method goes
+- * beyond the end of the list of elements that are being accessed. It is also
+- * thrown by Vector and Stack when attempting to access the first or last
+- * element of an empty collection.
++ * exist. This exception is thrown by the Enumeration, Iterator and ListIterator
++ * classes if the nextElement, next or previous method goes beyond the end of
++ * the list of elements that are being accessed.
+  *
+  * @author Warren Levy <warrenl@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Enumeration
+- * @see Iterator
+- * @see ListIterator
+- * @see Enumeration#nextElement()
+- * @see Iterator#next()
+- * @see ListIterator#previous()
+- * @since 1.0
+- * @status updated to 1.4
++ * @date September 2, 1998.
+  */
+ public class NoSuchElementException extends RuntimeException
+ {
+-  /**
+-   * Compatible with JDK 1.0.
+-   */
+   private static final long serialVersionUID = 6769829250639411880L;
+ 
+   /**
+@@ -63,6 +51,7 @@
+    */
+   public NoSuchElementException()
+   {
++    super();
+   }
+ 
+   /**
Index: compare/java.util.Properties.diff
===================================================================
RCS file: java.util.Properties.diff
diff -N java.util.Properties.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Properties.diff Tue Nov 6 17:21:35 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Properties.java	Mon Sep 10 21:22:48 2001
++++ java/util/Properties.java	Fri Nov  2 21:44:52 2001
+@@ -125,7 +125,7 @@
+    * </pre>
+    *
+    * @param in the input stream
+-   * @exception IOException if an error occured when reading
++   * @exception IOException if an error occurred when reading
+    * from the input.  */
+   public void load(InputStream inStream) throws IOException
+   {
Index: compare/java.util.ResourceBundle.diff
===================================================================
RCS file: java.util.ResourceBundle.diff
diff -N java.util.ResourceBundle.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.ResourceBundle.diff Tue Nov 6 17:21:35 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/ResourceBundle.java	Sun Nov  4 14:58:58 2001
++++ java/util/ResourceBundle.java	Mon Nov  5 14:36:58 2001
+@@ -93,7 +93,7 @@
+   /**
+    * We override SecurityManager in order to access getClassContext(). 
+    */
+-  class Security extends SecurityManager
++  static class Security extends SecurityManager
+   {
+     /** Return the ClassLoader of the class which called into this
+         ResourceBundle, or null if it cannot be determined. */
Index: compare/java.util.Stack.diff
===================================================================
RCS file: java.util.Stack.diff
diff -N java.util.Stack.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Stack.diff Tue Nov 6 17:21:35 2001
@@ -0,0 +1,135 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Stack.java	Fri Oct 26 16:06:57 2001
++++ java/util/Stack.java	Tue Oct 16 09:14:35 2001
+@@ -32,30 +32,24 @@
+  * "The Java Language Specification", ISBN 0-201-63451-1
+  * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+  * Status:  Believed complete and correct
++ */
+ 
+ /**
+  * Stack provides a Last In First Out (LIFO) data type, commonly known
+- * as a Stack.  Stack itself extends Vector and provides the additional
+- * methods for stack manipulation (push, pop, peek). You can also seek for
+- * the 1-based position of an element on the stack.
++ * as a Stack.  
++ *
++ * Stack itself extends Vector and provides the additional methods
++ * for stack manipulation (push, pop, peek). 
+  *
+  * @author Warren Levy <warrenl@cygnus.com>
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see List
+- * @see AbstractList
+- * @see LinkedList
+- * @since 1.0
+- * @status updated to 1.4
++ * @date August 20, 1998.
+  */
+ public class Stack extends Vector
+ {
+-  // We could use Vector methods internally for the following methods,
++  // Could use Vector methods internally for the following methods
+   // but have used Vector fields directly for efficiency (i.e. this
+   // often reduces out duplicate bounds checking).
+ 
+-  /**
+-   * Compatible with JDK 1.0+.
+-   */
+   private static final long serialVersionUID = 1224463164541339165L;
+ 
+   /**
+@@ -63,15 +57,16 @@
+    */
+   public Stack()
+   {
++    super();
+   }
+ 
+   /**
+    * Pushes an Object onto the top of the stack.  This method is effectively
+-   * the same as addElement(item).
++   * the same as addElement(item)
+    *
+    * @param item the Object to push onto the stack
+-   * @return the Object pushed onto the stack
+-   * @see Vector#addElement(Object)
++   * @returns the Object pushed onto the stack
++   * @see java.util.Vector#addElement(java.util.Object)
+    */
+   public Object push(Object item)
+   {
+@@ -85,29 +80,26 @@
+ 
+   /**
+    * Pops an item from the stack and returns it.  The item popped is
+-   * removed from the Stack.
++   * removed from the Stack
+    *
+-   * @return the Object popped from the stack
+-   * @throws EmptyStackException if the stack is empty
++   * @returns the Object popped from the stack
+    */
+   public synchronized Object pop()
+   {
+     if (elementCount == 0)
+       throw new EmptyStackException();
+ 
+-    modCount++;
+     Object obj = elementData[--elementCount];
+ 
+-    // Set topmost element to null to assist the gc in cleanup.
++    // Set topmost element to null to assist the gc in cleanup
+     elementData[elementCount] = null;
+     return obj;
+   }
+ 
+   /**
+-   * Returns the top Object on the stack without removing it.
++   * Returns the top Object on the stack without removing it
+    *
+-   * @return the top Object on the stack
+-   * @throws EmptyStackException if the stack is empty
++   * @returns the top Object on the stack
+    */
+   public synchronized Object peek()
+   {
+@@ -118,11 +110,11 @@
+   }
+ 
+   /**
+-   * Tests if the stack is empty.
++   * Tests if the stack is empty
+    *
+-   * @return true if the stack contains no items, false otherwise
++   * @returns true if the stack contains no items, false otherwise
+    */
+-  public synchronized boolean empty()
++  public boolean empty()
+   {
+     return elementCount == 0;
+   }
+@@ -130,18 +122,18 @@
+   /**
+    * Returns the position of an Object on the stack, with the top
+    * most Object being at position 1, and each Object deeper in the
+-   * stack at depth + 1.
++   * stack at depth + 1
+    *
+    * @param o The object to search for
+-   * @return The 1 based depth of the Object, or -1 if the Object
+-   *         is not on the stack
++   * @returns The 1 based depth of the Object, or -1 if the Object 
++   * is not on the stack.
+    */
+   public synchronized int search(Object o)
+   {
+-    int i = elementCount;
+-    while (--i >= 0)
+-      if (equals(o, elementData[i]))
++    for (int i = elementCount-1; i >=0; --i)
++      if (elementData[i].equals(o))
+         return elementCount - i;
++
+     return -1;
+   }
+ }
Index: compare/java.util.Timer.diff
===================================================================
RCS file: java.util.Timer.diff
diff -N java.util.Timer.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Timer.diff Tue Nov 6 17:21:35 2001
@@ -0,0 +1,58 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Timer.java	Fri Feb  9 16:31:22 2001
++++ java/util/Timer.java	Fri Nov  2 21:44:52 2001
+@@ -39,8 +39,8 @@
+  * scheduling guarantees more or less that the task will be executed at a
+  * specific time, but if there is ever a delay in execution then the period
+  * between successive executions will be shorter. The first method of
+- * repeated scheduling is prefered for repeated tasks in response to user
+- * interaction, the second method of repeated scheduling is prefered for tasks
++ * repeated scheduling is preferred for repeated tasks in response to user
++ * interaction, the second method of repeated scheduling is preferred for tasks
+  * that act like alarms.
+  * <p>
+  * The Timer keeps a binary heap as a task priority queue which means that
+@@ -65,7 +65,7 @@
+     /** Default size of this queue */
+     private final int DEFAULT_SIZE = 32;
+ 
+-    /** Wheter to return null when there is nothing in the queue */
++    /** Whether to return null when there is nothing in the queue */
+     private boolean nullOnEmpty;
+ 
+     /**
+@@ -375,7 +375,7 @@
+   private boolean canceled;
+ 
+   /**
+-   * Creates a new Timer with a non deamon Thread as Scheduler, with normal
++   * Creates a new Timer with a non daemon Thread as Scheduler, with normal
+    * priority and a default name.
+    */
+   public Timer()
+@@ -384,7 +384,7 @@
+   }
+ 
+   /**
+-   * Creates a new Timer with a deamon Thread as scheduler if deamon is true,
++   * Creates a new Timer with a daemon Thread as scheduler if daemon is true,
+    * with normal priority and a default name.
+    */
+   public Timer(boolean daemon)
+@@ -393,7 +393,7 @@
+   }
+ 
+   /**
+-   * Creates a new Timer with a deamon Thread as scheduler if deamon is true,
++   * Creates a new Timer with a daemon Thread as scheduler if daemon is true,
+    * with the priority given and a default name.
+    */
+   private Timer(boolean daemon, int priority)
+@@ -402,7 +402,7 @@
+   }
+ 
+   /**
+-   * Creates a new Timer with a deamon Thread as scheduler if deamon is true,
++   * Creates a new Timer with a daemon Thread as scheduler if daemon is true,
+    * with the priority and name given.E
+    */
+   private Timer(boolean daemon, int priority, String name)
Index: compare/java.util.TreeMap.diff
===================================================================
RCS file: java.util.TreeMap.diff
diff -N java.util.TreeMap.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.TreeMap.diff Tue Nov 6 17:21:36 2001
@@ -0,0 +1,2767 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/TreeMap.java	Fri Oct 26 16:06:59 2001
++++ java/util/TreeMap.java	Tue Oct 16 09:14:35 2001
+@@ -38,166 +38,80 @@
+  * interface.  Elements in the Map will be sorted by either a user-provided
+  * Comparator object, or by the natural ordering of the keys.
+  *
+- * The algorithms are adopted from Corman, Leiserson, and Rivest's
+- * <i>Introduction to Algorithms.</i>  TreeMap guarantees O(log n)
+- * insertion and deletion of elements.  That being said, there is a large
+- * enough constant coefficient in front of that "log n" (overhead involved
+- * in keeping the tree balanced), that TreeMap may not be the best choice
+- * for small collections. If something is already sorted, you may want to
+- * just use a LinkedHashMap to maintain the order while providing O(1) access.
++ * The algorithms are adopted from Corman, Leiserson,
++ * and Rivest's <i>Introduction to Algorithms.</i>  In other words,
++ * I cribbed from the same pseudocode as Sun.  <em>Any similarity
++ * between my code and Sun's (if there is any -- I have never looked
++ * at Sun's) is a result of this fact.</em>
+  *
+- * TreeMap is a part of the JDK1.2 Collections API.  Null keys are allowed
+- * only if a Comparator is used which can deal with them; natural ordering
+- * cannot cope with null.  Null values are always allowed. Note that the
+- * ordering must be <i>consistent with equals</i> to correctly implement
+- * the Map interface. If this condition is violated, the map is still
+- * well-behaved, but you may have suprising results when comparing it to
+- * other maps.<p>
+- *
+- * This implementation is not synchronized. If you need to share this between
+- * multiple threads, do something like:<br>
+- * <code>SortedMap m
+- *       = Collections.synchronizedSortedMap(new TreeMap(...));</code><p>
++ * TreeMap guarantees O(log n) insertion and deletion of elements.  That 
++ * being said, there is a large enough constant coefficient in front of 
++ * that "log n" (overhead involved in keeping the tree 
++ * balanced), that TreeMap may not be the best choice for small
++ * collections.
+  *
+- * The iterators are <i>fail-fast</i>, meaning that any structural
+- * modification, except for <code>remove()</code> called on the iterator
+- * itself, cause the iterator to throw a
+- * <code>ConcurrentModificationException</code> rather than exhibit
+- * non-deterministic behavior.
++ * TreeMap is a part of the JDK1.2 Collections API.  Null keys are allowed
++ * only if a Comparator is used which can deal with them.  Null values are 
++ * always allowed.
+  *
+- * @author Jon Zeppieri
+- * @author Bryce McKinlay
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Map
+- * @see HashMap
+- * @see Hashtable
+- * @see LinkedHashMap
+- * @see Comparable
+- * @see Comparator
+- * @see Collection
+- * @see Collections#synchronizedSortedMap(SortedMap)
+- * @since 1.2
+- * @status updated to 1.4
++ * @author           Jon Zeppieri
++ * @author	     Bryce McKinlay
+  */
+ public class TreeMap extends AbstractMap
+   implements SortedMap, Cloneable, Serializable
+ {
+-  // Implementation note:
+-  // A red-black tree is a binary search tree with the additional properties
+-  // that all paths to a leaf node visit the same number of black nodes,
+-  // and no red node has red children. To avoid some null-pointer checks,
+-  // we use the special node nil which is always black, has no relatives,
+-  // and has key and value of null (but is not equal to a mapping of null).
+-
+-  /**
+-   * Compatible with JDK 1.2.
+-   */
+-  private static final long serialVersionUID = 919286545866124006L;
++  private static final int RED = -1,
++                           BLACK = 1;
+ 
+-  /**
+-   * Color status of a node. Package visible for use by nested classes.
+-   */
+-  static final int RED = -1,
+-                   BLACK = 1;
+-
+-  /**
+-   * Sentinal node, used to avoid null checks for corner cases and make the
+-   * delete rebalance code simpler. The rebalance code must never assign
+-   * the parent, left, or right of nil, but may safely reassign the color
+-   * to be black. This object must never be used as a key in a TreeMap, or
+-   * it will break bounds checking of a SubMap.
+-   */
+-  static final Node nil = new Node(null, null, BLACK);
+-  static
+-    {
+-      // Nil is self-referential, so we must initialize it after creation.
+-      nil.parent = nil;
+-      nil.left = nil;
+-      nil.right = nil;
+-    }
++  /** Sentinal node, used to avoid null checks for corner cases and make the
++      delete rebalance code simpler. Note that this must not be static, due 
++      to thread-safety concerns. */
++  transient Node nil = new Node(null, null);
+ 
+-  /**
+-   * The root node of this TreeMap.
+-   */
+-  private transient Node root = nil;
++  /** The root node of this TreeMap */
++  transient Node root = nil;
+ 
+-  /**
+-   * The size of this TreeMap. Package visible for use by nested classes.
+-   */
+-  transient int size;
++  /** The size of this TreeMap */
++  transient int size = 0;
+ 
+-  /**
+-   * The cache for {@link #entrySet()}.
+-   */
+-  private transient Set entries;
++  /** Number of modifications */
++  transient int modCount = 0;
+ 
+-  /**
+-   * Counts the number of modifications this TreeMap has undergone, used
+-   * by Iterators to know when to throw ConcurrentModificationExceptions.
+-   * Package visible for use by nested classes.
+-   */
+-  transient int modCount;
++  /** This TreeMap's comparator, if any. */
++  Comparator comparator = null;
+ 
+-  /**
+-   * This TreeMap's comparator, or null for natural ordering.
+-   * Package visible for use by nested classes.
+-   * @serial the comparator ordering this tree, or null
+-   */
+-  final Comparator comparator;
++  static final long serialVersionUID = 919286545866124006L;
+ 
+-  /**
+-   * Class to represent an entry in the tree. Holds a single key-value pair,
+-   * plus pointers to parent and child nodes.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private static final class Node extends BasicMapEntry
++  private static class Node extends BasicMapEntry implements Map.Entry
+   {
+-    // All fields package visible for use by nested classes.
+-    /** The color of this node. */
+     int color;
++    Node left;
++    Node right;
++    Node parent;
+ 
+-    /** The left child node. */
+-    Node left = nil;
+-    /** The right child node. */
+-    Node right = nil;
+-    /** The parent node. */
+-    Node parent = nil;
+-
+-    /**
+-     * Simple constructor.
+-     * @param key the key
+-     * @param value the value
+-     */
+-    Node(Object key, Object value, int color)
++    Node(Object key, Object value)
+     {
+       super(key, value);
+-      this.color = color;
++      this.color = BLACK;
+     }
+   }
+ 
+   /**
+-   * Instantiate a new TreeMap with no elements, using the keys' natural
+-   * ordering to sort. All entries in the map must have a key which implements
+-   * Comparable, and which are <i>mutually comparable</i>, otherwise map
+-   * operations may throw a {@link ClassCastException}. Attempts to use
+-   * a null key will throw a {@link NullPointerException}.
++   * Instantiate a new TreeMap with no elements, using the keys'
++   * natural ordering to sort.
+    *
+-   * @see Comparable
++   * @see java.lang.Comparable
+    */
+   public TreeMap()
+   {
+-    this((Comparator) null);
+   }
+ 
+   /**
+-   * Instantiate a new TreeMap with no elements, using the provided comparator
+-   * to sort. All entries in the map must have keys which are mutually
+-   * comparable by the Comparator, otherwise map operations may throw a
+-   * {@link ClassCastException}.
++   * Instantiate a new TreeMap with no elements, using the provided
++   * comparator to sort.
+    *
+-   * @param comparator the sort order for the keys of this map, or null
+-   *        for the natural order
++   * @param        oComparator        a Comparator object, used to sort 
++   *                                  the keys of this SortedMap
+    */
+   public TreeMap(Comparator c)
+   {
+@@ -205,70 +119,62 @@
+   }
+ 
+   /**
+-   * Instantiate a new TreeMap, initializing it with all of the elements in
+-   * the provided Map.  The elements will be sorted using the natural
+-   * ordering of the keys. This algorithm runs in n*log(n) time. All entries
+-   * in the map must have keys which implement Comparable and are mutually
+-   * comparable, otherwise map operations may throw a
+-   * {@link ClassCastException}.
++   * Instantiate a new TreeMap, initializing it with all of the
++   * elements in the provided Map.  The elements will be sorted 
++   * using the natural ordering of the keys.
++   *
++   * @param              map         a Map, whose keys will be put into
++   *                                  this TreeMap
++   *
++   * @throws             ClassCastException     if the keys in the provided
++   *                                            Map do not implement 
++   *                                            Comparable
+    *
+-   * @param map a Map, whose entries will be put into this TreeMap
+-   * @throws ClassCastException if the keys in the provided Map are not
+-   *         comparable
+-   * @throws NullPointerException if map is null
+-   * @see Comparable
++   * @see                java.lang.Comparable
+    */
+   public TreeMap(Map map)
+   {
+-    this((Comparator) null);
+     putAll(map);
+   }
+ 
+-  /**
+-   * Instantiate a new TreeMap, initializing it with all of the elements in
+-   * the provided SortedMap.  The elements will be sorted using the same
+-   * comparator as in the provided SortedMap. This runs in linear time.
+-   *
+-   * @param sm a SortedMap, whose entries will be put into this TreeMap
+-   * @throws NullPointerException if sm is null
++  /** 
++   * Instantiate a new TreeMap, initializing it with all of the
++   * elements in the provided SortedMap.  The elements will be sorted 
++   * using the same method as in the provided SortedMap.
+    */
+   public TreeMap(SortedMap sm)
+   {
+     this(sm.comparator());
+-    int pos = sm.size();
++
++    int sm_size = sm.size();
+     Iterator itr = sm.entrySet().iterator();
+ 
+-    fabricateTree(pos);
++    fabricateTree(sm_size);
+     Node node = firstNode();
+-
+-    while (--pos >= 0)
++    
++    for (int i = 0; i < sm_size; i++)
+       {
+-        Map.Entry me = (Map.Entry) itr.next();
+-        node.key = me.getKey();
+-        node.value = me.getValue();
+-        node = successor(node);
++	Map.Entry me = (Map.Entry) itr.next();
++	node.key = me.getKey();
++	node.value = me.getValue();	
++	node = successor(node);
+       }
+   }
+ 
+-  /**
+-   * Clears the Map so it has no keys. This is O(1).
+-   */
++  public int size()
++  {
++    return size;
++  }
++
+   public void clear()
+   {
+-    if (size > 0)
+-      {
+-        modCount++;
+-        root = nil;
+-        size = 0;
+-      }
++    modCount++;
++    root = nil;
++    // nil node could have a residual parent reference, clear it for GC.
++    nil.parent = null;
++    size = 0;
+   }
+ 
+-  /**
+-   * Returns a shallow clone of this TreeMap. The Map itself is cloned,
+-   * but its contents are not.
+-   *
+-   * @return the clone
+-   */
+   public Object clone()
+   {
+     TreeMap copy = null;
+@@ -279,805 +185,547 @@
+     catch (CloneNotSupportedException x)
+       {
+       }
+-    copy.entries = null;
++    // Each instance must have a unique sentinal.
++    copy.nil = new Node(null, null);
+     copy.fabricateTree(size);
+ 
+     Node node = firstNode();
+     Node cnode = copy.firstNode();
+-
++    
+     while (node != nil)
+       {
+         cnode.key = node.key;
+-        cnode.value = node.value;
+-        node = successor(node);
+-        cnode = copy.successor(cnode);
++	cnode.value = node.value;
++	node = successor(node);
++	cnode = copy.successor(cnode);
+       }
+     return copy;
+   }
+-
+-  /**
+-   * Return the comparator used to sort this map, or null if it is by
+-   * natural order.
+-   *
+-   * @return the map's comparator
+-   */
++  
+   public Comparator comparator()
+   {
+     return comparator;
+   }
+ 
+-  /**
+-   * Returns true if the map contains a mapping for the given key.
+-   *
+-   * @param key the key to look for
+-   * @return true if the key has a mapping
+-   * @throws ClassCastException if key is not comparable to map elements
+-   * @throws NullPointerException if key is null and the comparator is not
+-   *         tolerant of nulls
+-   */
+   public boolean containsKey(Object key)
+   {
+     return getNode(key) != nil;
+   }
+ 
+-  /**
+-   * Returns true if the map contains at least one mapping to the given value.
+-   * This requires linear time.
+-   *
+-   * @param value the value to look for
+-   * @return true if the value appears in a mapping
+-   */
+   public boolean containsValue(Object value)
+   {
+     Node node = firstNode();
++    Object currentVal;
++
+     while (node != nil)
+       {
+-        if (equals(value, node.value))
+-          return true;
+-        node = successor(node);
++	currentVal = node.getValue();
++
++        if (value == null ? currentVal == null : value.equals (currentVal))
++	  return true;
++
++	node = successor(node);
+       }
+     return false;
+   }
+ 
+-  /**
+-   * Returns a "set view" of this TreeMap's entries. The set is backed by
+-   * the TreeMap, so changes in one show up in the other.  The set supports
+-   * element removal, but not element addition.<p>
+-   *
+-   * Note that the iterators for all three views, from keySet(), entrySet(),
+-   * and values(), traverse the TreeMap in sorted sequence.
+-   *
+-   * @return a set view of the entries
+-   * @see #keySet()
+-   * @see #values()
+-   * @see Map.Entry
+-   */
+   public Set entrySet()
+   {
+-    if (entries == null)
+-      // Create an AbstractSet with custom implementations of those methods
+-      // that can be overriden easily and efficiently.
+-      entries = new AbstractSet()
++    // Create an AbstractSet with custom implementations of those methods that 
++    // can be overriden easily and efficiently.
++    return new AbstractSet()
++    {
++      public int size()
+       {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          return new TreeIterator(ENTRIES);
+-        }
+-
+-        public void clear()
+-        {
+-          TreeMap.this.clear();
+-        }
+-
+-        public boolean contains(Object o)
+-        {
+-          if (! (o instanceof Map.Entry))
+-            return false;
+-          Map.Entry me = (Map.Entry) o;
+-          Node n = getNode(me.getKey());
+-          return n != nil && AbstractSet.equals(me.getValue(), n.value);
++        return size;
++      }
++      
++      public Iterator iterator()
++      {
++        return new TreeIterator(TreeIterator.ENTRIES);
++      }
++            
++      public void clear()
++      {
++        TreeMap.this.clear();
+       }
+ 
+-        public boolean remove(Object o)
+-        {
+-          if (! (o instanceof Map.Entry))
+-            return false;
+-          Map.Entry me = (Map.Entry) o;
+-          Node n = getNode(me.getKey());
+-          if (n != nil && AbstractSet.equals(me.getValue(), n.value))
+-            {
+-              removeNode(n);
+-              return true;
+-            }
+-          return false;
+-        }
+-      };
+-    return entries;
++      public boolean contains(Object o)
++      {
++        if (!(o instanceof Map.Entry))
++	  return false;
++	Map.Entry me = (Map.Entry) o;
++	Node n = getNode(me.getKey());
++	return (n != nil && me.getValue().equals(n.value));
++      }
++      
++      public boolean remove(Object o)
++      {
++        if (!(o instanceof Map.Entry))
++	  return false;
++	Map.Entry me = (Map.Entry) o;
++	Node n = getNode(me.getKey());
++	if (n != nil && me.getValue().equals(n.value))
++	  {
++	    removeNode(n);
++	    return true;
++	  }
++	return false;
++      }
++    };
+   }
+ 
+-  /**
+-   * Returns the first (lowest) key in the map.
+-   *
+-   * @return the first key
+-   * @throws NoSuchElementException if the map is empty
+-   */
+   public Object firstKey()
+   {
+     if (root == nil)
+-      throw new NoSuchElementException();
+-    return firstNode().key;
++      throw new NoSuchElementException("empty");
++    return firstNode().getKey();
++  }
++  
++  private Node firstNode()
++  {
++    if (root == nil)
++      return nil;
++    Node node = root;
++    while (node.left != nil)
++      node = node.left;
++    return node;
+   }
+ 
+-  /**
+-   * Return the value in this TreeMap associated with the supplied key,
+-   * or <code>null</code> if the key maps to nothing.  NOTE: Since the value
+-   * could also be null, you must use containsKey to see if this key
+-   * actually maps to something.
+-   *
+-   * @param key the key for which to fetch an associated value
+-   * @return what the key maps to, if present
+-   * @throws ClassCastException if key is not comparable to elements in the map
+-   * @throws NullPointerException if key is null but the comparator does not
+-   *         tolerate nulls
+-   * @see #put(Object, Object)
+-   * @see #containsKey(Object)
+-   */
++  public Object lastKey()
++  {
++    if (root == nil)
++      throw new NoSuchElementException("empty");
++    return lastNode().getKey();
++  }
++  
++  private Node lastNode()
++  {
++    if (root == nil)
++      return nil;
++    Node node = root;
++    while (node.right != nil)
++      node = node.right;
++    return node;  
++  }
++  
+   public Object get(Object key)
+   {
+-    // Exploit fact that nil.value == null.
+     return getNode(key).value;
+   }
+-
+-  /**
+-   * Returns a view of this Map including all entries with keys less than
+-   * <code>toKey</code>. The returned map is backed by the original, so changes
+-   * in one appear in the other. The submap will throw an
+-   * {@link IllegalArgumentException} for any attempt to access or add an
+-   * element beyond the specified cutoff. The returned map does not include
+-   * the endpoint; if you want inclusion, pass the successor element.
+-   *
+-   * @param toKey the (exclusive) cutoff point
+-   * @return a view of the map less than the cutoff
+-   * @throws ClassCastException if <code>toKey</code> is not compatible with
+-   *         the comparator (or is not Comparable, for natural ordering)
+-   * @throws NullPointerException if toKey is null, but the comparator does not
+-   *         tolerate null elements
+-   */
+-  public SortedMap headMap(Object toKey)
++  
++  /** Return the TreeMap.Node associated with KEY, or the nil node if no such
++      node exists in the tree. */
++  private Node getNode(Object key)
+   {
+-    return new SubMap(nil, toKey);
++    int comparison;
++    Node current = root;
++
++    while (current != nil)
++      {
++        comparison = compare(key, current.key);
++	if (comparison > 0)
++	  current = current.right;
++	else if (comparison < 0)
++	  current = current.left;
++	else
++	  return current;
++      }
++    return current; 
+   }
+ 
+-  /**
+-   * Returns a "set view" of this TreeMap's keys. The set is backed by the
+-   * TreeMap, so changes in one show up in the other.  The set supports
+-   * element removal, but not element addition.
+-   *
+-   * @return a set view of the keys
+-   * @see #values()
+-   * @see #entrySet()
+-   */
+   public Set keySet()
+   {
+-    if (keys == null)
+-      // Create an AbstractSet with custom implementations of those methods
+-      // that can be overriden easily and efficiently.
+-      keys = new AbstractSet()
++    // Create an AbstractSet with custom implementations of those methods that 
++    // can be overriden easily and efficiently.
++    return new AbstractSet()
++    {
++      public int size()
+       {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          return new TreeIterator(KEYS);
+-        }
+-
+-        public void clear()
+-        {
+-          TreeMap.this.clear();
+-        }
+-
+-        public boolean contains(Object o)
+-        {
+-          return containsKey(o);
+-        }
++        return size;
++      }
++      
++      public Iterator iterator()
++      {
++        return new TreeIterator(TreeIterator.KEYS);
++      }
+ 
+-        public boolean remove(Object key)
+-        {
+-          Node n = getNode(key);
+-          if (n == nil)
+-            return false;
+-          removeNode(n);
+-          return true;
+-        }
+-      };
+-    return keys;
+-  }
++      public void clear()
++      {
++        TreeMap.this.clear();
++      }
+ 
+-  /**
+-   * Returns the last (highest) key in the map.
+-   *
+-   * @return the last key
+-   * @throws NoSuchElementException if the map is empty
+-   */
+-  public Object lastKey()
+-  {
+-    if (root == nil)
+-      throw new NoSuchElementException("empty");
+-    return lastNode().key;
++      public boolean contains(Object o)
++      {
++        return TreeMap.this.containsKey(o);
++      }
++      
++      public boolean remove(Object key)
++      {
++        Node n = getNode(key);
++	if (n == nil)
++	  return false;
++        TreeMap.this.removeNode(n);
++	return true;
++      }
++    };
+   }
+ 
+-  /**
+-   * Puts the supplied value into the Map, mapped by the supplied key.
+-   * The value may be retrieved by any object which <code>equals()</code>
+-   * this key. NOTE: Since the prior value could also be null, you must
+-   * first use containsKey if you want to see if you are replacing the
+-   * key's mapping.
+-   *
+-   * @param key the key used to locate the value
+-   * @param value the value to be stored in the HashMap
+-   * @return the prior mapping of the key, or null if there was none
+-   * @throws ClassCastException if key is not comparable to current map keys
+-   * @throws NullPointerException if key is null, but the comparator does
+-   *         not tolerate nulls
+-   * @see #get(Object)
+-   * @see Object#equals(Object)
+-   */
+   public Object put(Object key, Object value)
+   {
++    modCount++;
+     Node current = root;
+     Node parent = nil;
+     int comparison = 0;
+-
++    
+     // Find new node's parent.
+     while (current != nil)
+       {
+-        parent = current;
+-        comparison = compare(key, current.key);
+-        if (comparison > 0)
+-          current = current.right;
+-        else if (comparison < 0)
+-          current = current.left;
+-        else // Key already in tree.
+-          return current.setValue(value);
++	parent = current;
++	comparison = compare(key, current.key);
++	if (comparison > 0)
++	  current = current.right;
++	else if (comparison < 0)
++	  current = current.left;
++	else
++	  {
++	    // Key already in tree.
++	    Object r = current.value;
++	    current.value = value;
++	    return r;
++	  }
+       }
+-
++    
+     // Set up new node.
+-    Node n = new Node(key, value, RED);
++    Node n = new Node(key, value);
++    n.color = RED;
+     n.parent = parent;
+-
++    n.left = nil;
++    n.right = nil;
++    
+     // Insert node in tree.
+-    modCount++;
+     size++;
+     if (parent == nil)
+       {
+-        // Special case inserting into an empty tree.
+-        root = n;
+-        return null;
++        // Special case: inserting into an empty tree.
++	root = n;
++	n.color = BLACK;
++	return null;
+       }
+-    if (comparison > 0)
++    else if (comparison > 0)
+       parent.right = n;
+     else
+-      parent.left = n;
+-
++      parent.left = n;   
++    
+     // Rebalance after insert.
+     insertFixup(n);
++    //verifyTree();
+     return null;
+   }
+ 
+-  /**
+-   * Copies all elements of the given map into this hashtable.  If this table
+-   * already has a mapping for a key, the new mapping replaces the current
+-   * one.
+-   *
+-   * @param m the map to be hashed into this
+-   * @throws ClassCastException if a key in m is not comparable with keys
+-   *         in the map
+-   * @throws NullPointerException if a key in m is null, and the comparator
+-   *         does not tolerate nulls
+-   */
+-  public void putAll(Map m)
+-  {
+-    Iterator itr = m.entrySet().iterator();
+-    int pos = m.size();
+-    while (--pos >= 0)
+-      {
+-        Map.Entry e = (Map.Entry) itr.next();
+-        put(e.getKey(), e.getValue());
+-      }
+-  }
+-
+-  /**
+-   * Removes from the TreeMap and returns the value which is mapped by the
+-   * supplied key. If the key maps to nothing, then the TreeMap remains
+-   * unchanged, and <code>null</code> is returned. NOTE: Since the value
+-   * could also be null, you must use containsKey to see if you are
+-   * actually removing a mapping.
+-   *
+-   * @param key the key used to locate the value to remove
+-   * @return whatever the key mapped to, if present
+-   * @throws ClassCastException if key is not comparable to current map keys
+-   * @throws NullPointerException if key is null, but the comparator does
+-   *         not tolerate nulls
+-   */
+-  public Object remove(Object key)
+-  {
+-    Node n = getNode(key);
+-    if (n == nil)
+-      return null;
+-    removeNode(n);
+-    return n.value;
+-  }
+-
+-  /**
+-   * Returns the number of key-value mappings currently in this Map.
+-   *
+-   * @return the size
+-   */
+-  public int size()
+-  {
+-    return size;
+-  }
+-
+-  /**
+-   * Returns a view of this Map including all entries with keys greater or
+-   * equal to <code>fromKey</code> and less than <code>toKey</code> (a
+-   * half-open interval). The returned map is backed by the original, so
+-   * changes in one appear in the other. The submap will throw an
+-   * {@link IllegalArgumentException} for any attempt to access or add an
+-   * element beyond the specified cutoffs. The returned map includes the low
+-   * endpoint but not the high; if you want to reverse this behavior on
+-   * either end, pass in the successor element.
+-   *
+-   * @param fromKey the (inclusive) low cutoff point
+-   * @param toKey the (exclusive) high cutoff point
+-   * @return a view of the map between the cutoffs
+-   * @throws ClassCastException if either cutoff is not compatible with
+-   *         the comparator (or is not Comparable, for natural ordering)
+-   * @throws NullPointerException if fromKey or toKey is null, but the
+-   *         comparator does not tolerate null elements
+-   * @throws IllegalArgumentException if fromKey is greater than toKey
+-   */
+-  public SortedMap subMap(Object fromKey, Object toKey)
+-  {
+-    return new SubMap(fromKey, toKey);
+-  }
+-
+-  /**
+-   * Returns a view of this Map including all entries with keys greater or
+-   * equal to <code>fromKey</code>. The returned map is backed by the
+-   * original, so changes in one appear in the other. The submap will throw an
+-   * {@link IllegalArgumentException} for any attempt to access or add an
+-   * element beyond the specified cutoff. The returned map includes the
+-   * endpoint; if you want to exclude it, pass in the successor element.
+-   *
+-   * @param fromKey the (inclusive) low cutoff point
+-   * @return a view of the map above the cutoff
+-   * @throws ClassCastException if <code>fromKey</code> is not compatible with
+-   *         the comparator (or is not Comparable, for natural ordering)
+-   * @throws NullPointerException if fromKey is null, but the comparator
+-   *         does not tolerate null elements
+-   */
+-  public SortedMap tailMap(Object fromKey)
+-  {
+-    return new SubMap(fromKey, nil);
+-  }
+-
+-  /**
+-   * Returns a "collection view" (or "bag view") of this TreeMap's values.
+-   * The collection is backed by the TreeMap, so changes in one show up
+-   * in the other.  The collection supports element removal, but not element
+-   * addition.
+-   *
+-   * @return a bag view of the values
+-   * @see #keySet()
+-   * @see #entrySet()
+-   */
+-  public Collection values()
+-  {
+-    if (values == null)
+-      // We don't bother overriding many of the optional methods, as doing so
+-      // wouldn't provide any significant performance advantage.
+-      values = new AbstractCollection()
+-      {
+-        public int size()
+-        {
+-          return size;
+-        }
+-
+-        public Iterator iterator()
+-        {
+-          return new TreeIterator(VALUES);
+-        }
+-
+-        public void clear()
+-        {
+-          TreeMap.this.clear();
+-        }
+-      };
+-    return values;
+-  }
+-
+-  /**
+-   * Compares two elements by the set comparator, or by natural ordering.
+-   * Package visible for use by nested classes.
+-   *
+-   * @param o1 the first object
+-   * @param o2 the second object
+-   * @throws ClassCastException if o1 and o2 are not mutually comparable,
+-   *         or are not Comparable with natural ordering
+-   * @throws NullPointerException if o1 or o2 is null with natural ordering
+-   */
+-  final int compare(Object o1, Object o2)
+-  {
+-    return (comparator == null
+-            ? ((Comparable) o1).compareTo(o2)
+-            : comparator.compare(o1, o2));
+-  }
+-
+-  /**
+-   * Maintain red-black balance after deleting a node.
+-   *
+-   * @param node the child of the node just deleted, possibly nil
+-   * @param parent the parent of the node just deleted, never nil
+-   */
+-  private void deleteFixup(Node node, Node parent)
++  /** Maintain red-black balance after inserting a new node. */
++  private void insertFixup(Node n)
+   {
+-    // if (parent == nil)
+-    //   throw new InternalError();
+-    // If a black node has been removed, we need to rebalance to avoid
+-    // violating the "same number of black nodes on any path" rule. If
+-    // node is red, we can simply recolor it black and all is well.
+-    while (node != root && node.color == BLACK)
++    // Only need to rebalance when parent is a RED node, and while at least
++    // 2 levels deep into the tree (ie: node has a grandparent).
++    while (n != root && n.parent.parent != nil && n.parent.color == RED)
+       {
+-        if (node == parent.left)
+-          {
+-            // Rebalance left side.
+-            Node sibling = parent.right;
+-            // if (sibling == nil)
+-            //   throw new InternalError();
+-            if (sibling.color == RED)
+-              {
+-                // Case 1: Sibling is red.
+-                // Recolor sibling and parent, and rotate parent left.
+-                sibling.color = BLACK;
+-                parent.color = RED;
+-                rotateLeft(parent);
+-                sibling = parent.right;
+-              }
+-
+-            if (sibling.left.color == BLACK && sibling.right.color == BLACK)
+-              {
+-                // Case 2: Sibling has no red children.
+-                // Recolor sibling, and move to parent.
+-                sibling.color = RED;
+-                node = parent;
+-                parent = parent.parent;
++	if (n.parent == n.parent.parent.left)
++	  {
++            Node uncle = n.parent.parent.right;
++            if (uncle != nil && uncle.color == RED) 
++	      {
++        	n.parent.color = BLACK;
++        	uncle.color = BLACK;
++        	n.parent.parent.color = RED;
++        	n = n.parent.parent;
+               }
+-            else
+-              {
+-                if (sibling.right.color == BLACK)
+-                  {
+-                    // Case 3: Sibling has red left child.
+-                    // Recolor sibling and left child, rotate sibling right.
+-                    sibling.left.color = BLACK;
+-                    sibling.color = RED;
+-                    rotateRight(sibling);
+-                    sibling = parent.right;
++	    else // Uncle is BLACK.
++	      {                
++                if (n == n.parent.right)
++		  {
++                    // Make n a left child.
++                    n = n.parent;
++                    rotateLeft(n);
+                   }
+-                // Case 4: Sibling has red right child. Recolor sibling,
+-                // right child, and parent, and rotate parent left.
+-                sibling.color = parent.color;
+-                parent.color = BLACK;
+-                sibling.right.color = BLACK;
+-                rotateLeft(parent);
+-                node = root; // Finished.
+-              }
+-          }
+-        else
+-          {
+-            // Symmetric "mirror" of left-side case.
+-            Node sibling = parent.left;
+-            // if (sibling == nil)
+-            //   throw new InternalError();
+-            if (sibling.color == RED)
+-              {
+-                // Case 1: Sibling is red.
+-                // Recolor sibling and parent, and rotate parent right.
+-                sibling.color = BLACK;
+-                parent.color = RED;
+-                rotateRight(parent);
+-                sibling = parent.left;
+-              }
+ 
+-            if (sibling.right.color == BLACK && sibling.left.color == BLACK)
+-              {
+-                // Case 2: Sibling has no red children.
+-                // Recolor sibling, and move to parent.
+-                sibling.color = RED;
+-                node = parent;
+-                parent = parent.parent;
++                // Recolor and rotate.
++                n.parent.color = BLACK;
++                n.parent.parent.color = RED;
++                rotateRight(n.parent.parent);
+               }
+-            else
+-              {
+-                if (sibling.left.color == BLACK)
+-                  {
+-                    // Case 3: Sibling has red right child.
+-                    // Recolor sibling and right child, rotate sibling left.
+-                    sibling.right.color = BLACK;
+-                    sibling.color = RED;
+-                    rotateLeft(sibling);
+-                    sibling = parent.left;
+-                  }
+-                // Case 4: Sibling has red left child. Recolor sibling,
+-                // left child, and parent, and rotate parent right.
+-                sibling.color = parent.color;
+-                parent.color = BLACK;
+-                sibling.left.color = BLACK;
+-                rotateRight(parent);
+-                node = root; // Finished.
++	  }
++	else
++	  {
++	    // Mirror image of above code.
++	    Node uncle = n.parent.parent.left;
++            if (uncle != nil && uncle.color == RED)
++	      {
++                n.parent.color = BLACK;
++                uncle.color = BLACK;
++                n.parent.parent.color = RED;
++                n = n.parent.parent;
+               }
+-          }
++	    else
++	      {
++                if (n == n.parent.left)
++		  {
++                    n = n.parent;
++                    rotateRight(n);
++                  }
++                n.parent.color = BLACK;
++                n.parent.parent.color = RED;
++                rotateLeft(n.parent.parent);
++	      }
++	  }
+       }
+-    node.color = BLACK;
++    root.color = BLACK;
+   }
+ 
+-  /**
+-   * Construct a perfectly balanced tree consisting of n "blank" nodes. This
+-   * permits a tree to be generated from pre-sorted input in linear time.
+-   *
+-   * @param count the number of blank nodes, non-negative
+-   */
+-  private void fabricateTree(final int count)
++  public void putAll(Map m)
+   {
+-    if (count == 0)
+-      return;
+-
+-    // We color every row of nodes black, except for the overflow nodes.
+-    // I believe that this is the optimal arrangement. We construct the tree
+-    // in place by temporarily linking each node to the next node in the row,
+-    // then updating those links to the children when working on the next row.
+-
+-    // Make the root node.
+-    root = new Node(null, null, BLACK);
+-    size = count;
+-    Node row = root;
+-    int rowsize;
++    Iterator itr = m.entrySet().iterator();
++    int msize = m.size();
++    Map.Entry e;
+ 
+-    // Fill each row that is completely full of nodes.
+-    for (rowsize = 2; rowsize + rowsize < count; rowsize <<= 1)
++    for (int i = 0; i < msize; i++)
+       {
+-        Node parent = row;
+-        Node last = null;
+-        for (int i = 0; i < rowsize; i += 2)
+-          {
+-            Node left = new Node(null, null, BLACK);
+-            Node right = new Node(null, null, BLACK);
+-            left.parent = parent;
+-            left.right = right;
+-            right.parent = parent;
+-            parent.left = left;
+-            Node next = parent.right;
+-            parent.right = right;
+-            parent = next;
+-            if (last != null)
+-              last.right = left;
+-            last = right;
+-          }
+-        row = row.left;
+-      }
+-
+-    // Now do the partial final row in red.
+-    int overflow = count - rowsize;
+-    Node parent = row;
+-    int i;
+-    for (i = 0; i < overflow; i += 2)
+-      {
+-        Node left = new Node(null, null, RED);
+-        Node right = new Node(null, null, RED);
+-        left.parent = parent;
+-        right.parent = parent;
+-        parent.left = left;
+-        Node next = parent.right;
+-        parent.right = right;
+-        parent = next;
+-      }
+-    // Add a lone left node if necessary.
+-    if (i - overflow == 0)
+-      {
+-        Node left = new Node(null, null, RED);
+-        left.parent = parent;
+-        parent.left = left;
+-        parent = parent.right;
+-        left.parent.right = nil;
+-      }
+-    // Unlink the remaining nodes of the previous row.
+-    while (parent != nil)
+-      {
+-        Node next = parent.right;
+-        parent.right = nil;
+-        parent = next;
++	e = (Map.Entry) itr.next();
++	put(e.getKey(), e.getValue());
+       }
+   }
+ 
+-  /**
+-   * Returns the first sorted node in the map, or nil if empty. Package
+-   * visible for use by nested classes.
+-   *
+-   * @return the first node
+-   */
+-  final Node firstNode()
++  public Object remove(Object key)
+   {
+-    // Exploit fact that nil.left == nil.
+-    Node node = root;
+-    while (node.left != nil)
+-      node = node.left;
+-    return node;
++    Node n = getNode(key);
++    if (n != nil)
++      {
++        removeNode(n);
++	return n.value;
++      }
++    return null;
+   }
++  
++  // Remove node from tree. This will increment modCount and decrement size. 
++  // Node must exist in the tree.
++  private void removeNode(Node node) // z
++  {
++    Node splice; // y
++    Node child;  // x
++    
++    modCount++;
++    size--;
+ 
+-  /**
+-   * Return the TreeMap.Node associated with key, or the nil node if no such
+-   * node exists in the tree. Package visible for use by nested classes.
+-   *
+-   * @param key the key to search for
+-   * @return the node where the key is found, or nil
+-   */
+-  final Node getNode(Object key)
+-  {
+-    Node current = root;
+-    while (current != nil)
++    // Find splice, the node at the position to actually remove from the tree. 
++    if (node.left == nil || node.right == nil)
+       {
+-        int comparison = compare(key, current.key);
+-        if (comparison > 0)
+-          current = current.right;
+-        else if (comparison < 0)
+-          current = current.left;
+-        else
+-          return current;
++	// Node to be deleted has 0 or 1 children.
++        splice = node;
++	if (node.left == nil)
++	  child = node.right;
++	else
++	  child = node.left;
++      }
++    else
++      {
++	// Node has 2 children. Splice is node's successor, and will be 
++	// swapped with node since we can't remove node directly.
++        splice = node.right;
++        while (splice.left != nil)
++	  splice = splice.left;
++	child = splice.right;
+       }
+-    return current;
+-  }
+ 
+-  /**
+-   * Find the "highest" node which is &lt; key. If key is nil, return last
+-   * node. Package visible for use by nested classes.
+-   *
+-   * @param key the upper bound, exclusive
+-   * @return the previous node
+-   */
+-  final Node highestLessThan(Object key)
+-  {
+-    if (key == nil)
+-      return lastNode();
++    // Unlink splice from the tree.
++    Node parent = splice.parent;
++    child.parent = parent;
++    if (parent != nil)
++      {
++	if (splice == parent.left)
++          parent.left = child;
++	else
++          parent.right = child;
++      }
++    else
++      root = child;
+ 
+-    Node last = nil;
+-    Node current = root;
+-    int comparison = 0;
++    // Keep track of splice's color in case it gets changed in the swap.
++    int spliceColor = splice.color;
+ 
+-    while (current != nil)
++/*
++    if (splice != node)
+       {
+-        last = current;
+-        comparison = compare(key, current.key);
+-        if (comparison > 0)
+-          current = current.right;
+-        else if (comparison < 0)
+-          current = current.left;
+-        else // Exact match.
+-          return predecessor(last);
++        node.key = splice.key;
++	node.value = splice.value;
++      }
++*/
++    if (splice != node)
++      {
++        // Swap SPLICE for NODE. Some implementations optimize here by simply
++	// swapping the values, but we can't do that: if an iterator was
++	// referencing a node in its "next" field, and that node got swapped, 
++	// things would get confused.
++	if (node == root)
++	  {
++	    root = splice;
++	  }
++	else
++	  {
++	    if (node.parent.left == node)
++	      node.parent.left = splice;
++	    else
++	      node.parent.right = splice;
++          }
++	splice.parent = node.parent;
++	splice.left = node.left;
++	splice.right = node.right;
++	splice.left.parent = splice;
++	splice.right.parent = splice;
++	splice.color = node.color;
+       }
+-    return comparison <= 0 ? predecessor(last) : last;
++
++    if (spliceColor == BLACK)
++      deleteFixup (child);
++    
++    //verifyTree();      
+   }
+ 
+-  /**
+-   * Maintain red-black balance after inserting a new node.
+-   *
+-   * @param n the newly inserted node
+-   */
+-  private void insertFixup(Node n)
++  /** Maintain red-black balance after deleting a node. */
++  private void deleteFixup (Node node)
+   {
+-    // Only need to rebalance when parent is a RED node, and while at least
+-    // 2 levels deep into the tree (ie: node has a grandparent). Remember
+-    // that nil.color == BLACK.
+-    while (n.parent.color == RED && n.parent.parent != nil)
++    // A black node has been removed, so we need to rebalance to avoid 
++    // violating the "same number of black nodes on any path" rule. If
++    // node is red, we can simply recolor it black and all is well. 
++    while (node != root && node.color == BLACK)
+       {
+-        if (n.parent == n.parent.parent.left)
+-          {
+-            Node uncle = n.parent.parent.right;
+-            // Uncle may be nil, in which case it is BLACK.
+-            if (uncle.color == RED)
+-              {
+-                // Case 1. Uncle is RED: Change colors of parent, uncle,
+-                // and grandparent, and move n to grandparent.
+-                n.parent.color = BLACK;
+-                uncle.color = BLACK;
+-                uncle.parent.color = RED;
+-                n = uncle.parent;
+-              }
+-            else
+-              {
+-                if (n == n.parent.right)
+-                  {
+-                    // Case 2. Uncle is BLACK and x is right child.
+-                    // Move n to parent, and rotate n left.
+-                    n = n.parent;
+-                    rotateLeft(n);
+-                  }
+-                // Case 3. Uncle is BLACK and x is left child.
+-                // Recolor parent, grandparent, and rotate grandparent right.
+-                n.parent.color = BLACK;
+-                n.parent.parent.color = RED;
+-                rotateRight(n.parent.parent);
+-              }
+-          }
+-        else
+-          {
+-            // Mirror image of above code.
+-            Node uncle = n.parent.parent.left;
+-            // Uncle may be nil, in which case it is BLACK.
+-            if (uncle.color == RED)
++        if (node == node.parent.left)
++	  {
++	    // Rebalance left side.
++	    Node sibling = node.parent.right;
++	    if (sibling.color == RED)
++	      {
++                sibling.color = BLACK;
++                node.parent.color = RED;
++                rotateLeft(node.parent);
++                sibling = node.parent.right;
++	      }
++
++	    if (sibling.left.color == BLACK && sibling.right.color == BLACK)
+               {
+-                // Case 1. Uncle is RED: Change colors of parent, uncle,
+-                // and grandparent, and move n to grandparent.
+-                n.parent.color = BLACK;
+-                uncle.color = BLACK;
+-                uncle.parent.color = RED;
+-                n = uncle.parent;
++	        // Case 2: Sibling has no red children.
++		sibling.color = RED;
++		// Black height has been decreased, so move up the tree and 
++		// repeat.
++		node = node.parent;
+               }
+-            else
++	    else
++	      {	      
++	        if (sibling.right.color == BLACK)
++		  {
++		    // Case 3: Sibling has red left child.
++		    sibling.left.color = BLACK;
++		    sibling.color = RED;
++                    rotateRight(sibling);
++                    sibling = node.parent.right;
++		  }		  
++		
++		// Case 4: Sibling has red right child.
++		sibling.color = sibling.parent.color;
++		sibling.parent.color = BLACK;
++		sibling.right.color = BLACK;
++                rotateLeft(node.parent);
++                node = root; // Finished.
++	      }
++	  }
++	else
++	  {
++	    // Symmetric "mirror" of left-side case.
++	    Node sibling = node.parent.left;
++	    if (sibling.color == RED)
++	      {
++                sibling.color = BLACK;
++                node.parent.color = RED;
++                rotateRight(node.parent);
++                sibling = node.parent.left;
++	      }
++
++	    if (sibling.left.color == BLACK && sibling.right.color == BLACK)
+               {
+-                if (n == n.parent.left)
+-                {
+-                    // Case 2. Uncle is BLACK and x is left child.
+-                    // Move n to parent, and rotate n right.
+-                    n = n.parent;
+-                    rotateRight(n);
+-                  }
+-                // Case 3. Uncle is BLACK and x is right child.
+-                // Recolor parent, grandparent, and rotate grandparent left.
+-                n.parent.color = BLACK;
+-                n.parent.parent.color = RED;
+-                rotateLeft(n.parent.parent);
++		sibling.color = RED;
++		node = node.parent;
+               }
+-          }
++	    else
++	      {	      
++	        if (sibling.left.color == BLACK)
++		  {
++		    sibling.right.color = BLACK;
++		    sibling.color = RED;
++                    rotateLeft(sibling);
++                    sibling = node.parent.left;
++		  }		  
++		
++		sibling.color = sibling.parent.color;
++		sibling.parent.color = BLACK;
++		sibling.left.color = BLACK;
++                rotateRight(node.parent);
++                node = root;
++	      }
++	  }
+       }
+-    root.color = BLACK;
++    node.color = BLACK;
+   }
+ 
+-  /**
+-   * Returns the last sorted node in the map, or nil if empty.
+-   *
+-   * @return the last node
+-   */
+-  private Node lastNode()
++  public SortedMap subMap(Object fromKey, Object toKey)
+   {
+-    // Exploit fact that nil.right == nil.
+-    Node node = root;
+-    while (node.right != nil)
+-      node = node.right;
+-    return node;
++    if (compare(fromKey, toKey) <= 0)
++      return new SubMap(fromKey, toKey);
++    else
++      throw new IllegalArgumentException("fromKey > toKey");
+   }
+ 
+-  /**
+-   * Find the "lowest" node which is &gt;= key. If key is nil, return either
+-   * nil or the first node, depending on the parameter first.
+-   * Package visible for use by nested classes.
+-   *
+-   * @param key the lower bound, inclusive
+-   * @param first true to return the first element instead of nil for nil key
+-   * @return the next node
+-   */
+-  final Node lowestGreaterThan(Object key, boolean first)
++  public SortedMap headMap(Object toKey)
+   {
+-    if (key == nil)
+-      return first ? firstNode() : nil;
++    return new SubMap(nil, toKey);
++  }
++
++  public SortedMap tailMap(Object fromKey)
++  {
++    return new SubMap(fromKey, nil);
++  }
++
++  /** Returns a "collection view" (or "bag view") of this TreeMap's values. */
++  public Collection values()
++  {
++    // We don't bother overriding many of the optional methods, as doing so
++    // wouldn't provide any significant performance advantage.
++    return new AbstractCollection()
++    {
++      public int size()
++      {
++        return size;
++      }
++      
++      public Iterator iterator()
++      {
++        return new TreeIterator(TreeIterator.VALUES);
++      }
++      
++      public void clear()
++      {
++        TreeMap.this.clear();
++      }
++    };
++  }
+ 
++  // Find the "highest" node which is < key. If key is nil, return last node.
++  // Note that highestLessThan is exclusive (it won't return a key which is
++  // equal to "key"), while lowestGreaterThan is inclusive, in order to be 
++  // consistent with the semantics of subMap().
++  private Node highestLessThan(Object key)
++  {
++    if (key == nil)
++      return lastNode();
++  
+     Node last = nil;
+     Node current = root;
+     int comparison = 0;
+@@ -1086,176 +734,122 @@
+       {
+         last = current;
+         comparison = compare(key, current.key);
+-        if (comparison > 0)
+-          current = current.right;
+-        else if (comparison < 0)
+-          current = current.left;
+-        else
+-          return current;
++	if (comparison > 0)
++	  current = current.right;
++	else if (comparison < 0)
++	  current = current.left;
++	else /* Exact match. */
++	  return predecessor(last);
+       }
+-    return comparison > 0 ? successor(last) : last;
++    if (comparison <= 0)
++      return predecessor(last);
++    else
++      return last;
+   }
+ 
+-  /**
+-   * Return the node preceding the given one, or nil if there isn't one.
+-   *
+-   * @param node the current node, not nil
+-   * @return the prior node in sorted order
+-   */
+-  private Node predecessor(Node node)
++  // Find the "lowest" node which is >= key. If key is nil, return first node.
++  private Node lowestGreaterThan(Object key)
+   {
+-    if (node.left != nil)
+-      {
+-        node = node.left;
+-        while (node.right != nil)
+-          node = node.right;
+-        return node;
+-      }
+-
+-    Node parent = node.parent;
+-    // Exploit fact that nil.left == nil and node is non-nil.
+-    while (node == parent.left)
+-      {
+-        node = parent;
+-        parent = node.parent;
+-      }
+-    return parent;
+-  }
++    if (key == nil)
++      return firstNode();
+ 
+-  /**
+-   * Construct a tree from sorted keys in linear time. Package visible for
+-   * use by TreeSet.
+-   *
+-   * @param s the stream to read from
+-   * @param count the number of keys to read
+-   * @param readValue true to read values, false to insert "" as the value
+-   * @throws ClassNotFoundException if the underlying stream fails
+-   * @throws IOException if the underlying stream fails
+-   * @see #readObject(ObjectInputStream)
+-   * @see TreeSet#readObject(ObjectInputStream)
+-   */
+-  final void putFromObjStream(ObjectInputStream s, int count,
+-                              boolean readValues)
+-    throws IOException, ClassNotFoundException
+-  {
+-    fabricateTree(count);
+-    Node node = firstNode();
++    Node last = nil;
++    Node current = root;
++    int comparison = 0;
+ 
+-    while (--count >= 0)
++    while (current != nil)
+       {
+-        node.key = s.readObject();
+-        node.value = readValues ? s.readObject() : "";
+-        node = successor(node);
++        last = current;
++        comparison = compare(key, current.key);
++	if (comparison > 0)
++	  current = current.right;
++	else if (comparison < 0)
++	  current = current.left;
++	else
++	  return current;
+       }
+-  }
++    if (comparison > 0)
++      return successor(last);
++    else
++      return last;
++  }  
+ 
+-  /**
+-   * Construct a tree from sorted keys in linear time, with values of "".
+-   * Package visible for use by TreeSet.
+-   *
+-   * @param keys the iterator over the sorted keys
+-   * @param count the number of nodes to insert
+-   * @see TreeSet#TreeSet(SortedSet)
+-   */
+-  final void putKeysLinear(Iterator keys, int count)
++  private void writeObject(ObjectOutputStream out) throws IOException
+   {
+-    fabricateTree(count);
+-    Node node = firstNode();
++    out.defaultWriteObject();
+ 
+-    while (--count >= 0)
++    Node node = firstNode();
++    out.writeInt(size);
++    
++    while (node != nil)
+       {
+-        node.key = keys.next();
+-        node.value = "";
+-        node = successor(node);
++        out.writeObject(node.key);
++	out.writeObject(node.value);
++	node = successor(node);
+       }
+   }
+ 
+-  /**
+-   * Deserializes this object from the given stream.
+-   *
+-   * @param s the stream to read from
+-   * @throws ClassNotFoundException if the underlying stream fails
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the <i>size</i> (int), followed by key (Object) and value
+-   *             (Object) pairs in sorted order
+-   */
+-  private void readObject(ObjectInputStream s)
++  private void readObject(ObjectInputStream in)
+     throws IOException, ClassNotFoundException
+   {
+-    s.defaultReadObject();
+-    int size = s.readInt();
+-    putFromObjStream(s, size, true);
++    in.defaultReadObject();
++    int size = in.readInt();
++    putFromObjStream(in, size, true);
+   }
+ 
+-  /**
+-   * Remove node from tree. This will increment modCount and decrement size.
+-   * Node must exist in the tree. Package visible for use by nested classes.
+-   *
+-   * @param node the node to remove
+-   */
+-  final void removeNode(Node node)
++  private int compare(Object o1, Object o2)
+   {
+-    Node splice;
+-    Node child;
+-
+-    modCount++;
+-    size--;
++    if (comparator == null)
++      return ((Comparable) o1).compareTo(o2);
++    else
++      return comparator.compare(o1, o2);
++  }
+ 
+-    // Find splice, the node at the position to actually remove from the tree.
+-    if (node.left == nil)
++  /* Return the node following Node, or nil if there isn't one. */
++  private Node successor(Node node)
++  {
++    if (node.right != nil)
+       {
+-        // Node to be deleted has 0 or 1 children.
+-        splice = node;
+-        child = node.right;
++        node = node.right;
++	while (node.left != nil)
++	  node = node.left;
++	return node;
+       }
+-    else if (node.right == nil)
++
++    Node parent = node.parent;
++    while (parent != nil && node == parent.right)
+       {
+-        // Node to be deleted has 0 children.
+-        splice = node;
+-        child = nil;
++	node = parent;
++	parent = parent.parent;
+       }
+-    else
++    return parent;
++  }
++
++  /* Return the node preceeding Node, or nil if there isn't one. */
++  private Node predecessor(Node node)
++  {
++    if (node.left != nil)
+       {
+-        // Node has 2 children. Splice is node's predecessor, and we swap
+-        // its contents into node.
+-        splice = node.left;
+-        while (splice.right != nil)
+-          splice = splice.right;
+-        child = splice.left;
+-        node.key = splice.key;
+-        node.value = splice.value;
++        node = node.left;
++	while (node.right != nil)
++	  node = node.right;
++	return node;
+       }
+-
+-    // Unlink splice from the tree.
+-    Node parent = splice.parent;
+-    if (child != nil)
+-      child.parent = parent;
+-    if (parent == nil)
++      
++    Node parent = node.parent;
++    while (parent != nil && node == parent.left)
+       {
+-        // Special case for 0 or 1 node remaining.
+-        root = child;
+-        return;
++	node = parent;
++	parent = parent.parent;
+       }
+-    if (splice == parent.left)
+-      parent.left = child;
+-    else
+-      parent.right = child;
+-
+-    if (splice.color == BLACK)
+-      deleteFixup(child, parent);
++    return parent;
+   }
+ 
+-  /**
+-   * Rotate node n to the left.
+-   *
+-   * @param node the node to rotate
+-   */
++  /** Rotate node n to the left. */
+   private void rotateLeft(Node node)
+   {
+     Node child = node.right;
+-    // if (node == nil || child == nil)
+-    //   throw new InternalError();
+-
++    
+     // Establish node.right link.
+     node.right = child.left;
+     if (child.left != nil)
+@@ -1266,146 +860,331 @@
+     if (node.parent != nil)
+       {
+         if (node == node.parent.left)
+-          node.parent.left = child;
+-        else
+-          node.parent.right = child;
++	  node.parent.left = child;
++	else
++	  node.parent.right = child;
+       }
+     else
+       root = child;
+ 
+     // Link n and child.
+     child.left = node;
+-    node.parent = child;
++    if (node != nil)
++      node.parent = child;
+   }
+ 
+-  /**
+-   * Rotate node n to the right.
+-   *
+-   * @param node the node to rotate
+-   */
++  /** Rotate node n to the right. */
+   private void rotateRight(Node node)
+   {
+     Node child = node.left;
+-    // if (node == nil || child == nil)
+-    //   throw new InternalError();
+-
++    
+     // Establish node.left link.
+     node.left = child.right;
+     if (child.right != nil)
+       child.right.parent = node;
+-
++      
+     // Establish child->parent link.
+     child.parent = node.parent;
+     if (node.parent != nil)
+       {
+         if (node == node.parent.right)
+-          node.parent.right = child;
+-        else
+-          node.parent.left = child;
++	  node.parent.right = child;
++	else
++	  node.parent.left = child;
+       }
+     else
+       root = child;
+-
++    
+     // Link n and child.
+     child.right = node;
+-    node.parent = child;
++    if (node != nil)
++      node.parent = child;
+   }
+-
+-  /**
+-   * Return the node following the given one, or nil if there isn't one.
+-   * Package visible for use by nested classes.
+-   *
+-   * @param node the current node, not nil
+-   * @return the next node in sorted order
+-   */
+-  final Node successor(Node node)
++  
++  /* Construct a tree from sorted keys in linear time. This is used to
++     implement TreeSet's SortedSet constructor. */
++  void putKeysLinear(Iterator keys, int count)
+   {
+-    if (node.right != nil)
++    fabricateTree(count);    
++    Node node = firstNode();
++    
++    for (int i = 0; i < count; i++)
+       {
+-        node = node.right;
+-        while (node.left != nil)
+-          node = node.left;
+-        return node;
++	node.key = keys.next();
++	node.value = Boolean.TRUE;
++	node = successor(node);
+       }
+-
+-    Node parent = node.parent;
+-    // Exploit fact that nil.right == nil and node is non-nil.
+-    while (node == parent.right)
++  }
++  
++  /* As above, but load keys from an ObjectInputStream. Used by readObject()
++     methods. If "readValues" is set, entry values will also be read from the 
++     stream. If not, only keys will be read. */
++  void putFromObjStream(ObjectInputStream in, int count, boolean readValues) 
++    throws IOException, ClassNotFoundException
++  {
++    fabricateTree(count);    
++    Node node = firstNode();
++    
++    for (int i = 0; i < count; i++)
+       {
+-        node = parent;
+-        parent = parent.parent;
+-      }
+-    return parent;
++	node.key = in.readObject();
++	if (readValues)
++	  node.value = in.readObject();
++	else
++	  node.value = Boolean.TRUE;	  
++	node = successor(node);
++      }
++  }
++     
++  /* Construct a perfectly balanced tree consisting of n "blank" nodes. 
++     This permits a tree to be generated from pre-sorted input in linear 
++     time. */
++  private void fabricateTree(int count)
++  {
++    if (count == 0)
++      return;
++    // Calculate the (maximum) depth of the perfectly balanced tree.
++    double ddepth = (Math.log (count + 1) / Math.log (2));
++    int maxdepth = (int) Math.ceil (ddepth);
++    
++    // The number of nodes which can fit in a perfectly-balanced tree of 
++    // height "depth - 1".
++    int max = (int) Math.pow (2, maxdepth - 1) - 1;
++    
++    // Number of nodes which spill over into the deepest row of the tree.
++    int overflow = (int) count - max;
++    
++    size = count;
++    // Make the root node.
++    root = new Node(null, null);
++    root.parent = nil;
++    root.left = nil;
++    root.right = nil;
++    
++    Node row = root;
++    for (int depth = 2; depth <= maxdepth; depth++)  // each row
++      {	
++	// Number of nodes at this depth
++	int rowcap = (int) Math.pow (2, depth - 1);
++	Node parent = row;
++	Node last = null;
++	
++	// Actual number of nodes to create in this row
++	int rowsize;
++	if (depth == maxdepth)
++	  rowsize = overflow;
++	else
++	  rowsize = rowcap;
++	
++	// The bottom most row of nodes is coloured red, as is every second row 
++	// going up, except the root node (row 1). I'm not sure if this is the 
++	// optimal configuration for the tree, but it seems logical enough.
++	// We just need to honour the black-height and red-parent rules here.
++	boolean colorRowRed = (depth % 2 == maxdepth % 2);
++	
++	int i;
++	for (i = 1; i <= rowsize; i++)  // each node in row
++	  {
++	    Node node = new Node(null, null);
++	    node.parent = parent;
++	    if (i % 2 == 1)
++	      parent.left = node;
++	    else
++	      {
++		Node nextparent = parent.right;
++		parent.right = node;
++		parent = nextparent;
++	      }
++
++	    // We use the "right" link to maintain a chain of nodes in 
++	    // each row until the parent->child links are established.
++	    if (last != null)
++	      last.right = node;
++	    last = node;
++	    
++	    if (colorRowRed)
++	      node.color = RED;
++	    
++	    if (i == 1)
++	      row = node;
++	  }
++
++        // Set nil child pointers on leaf nodes.
++	if (depth == maxdepth)
++	  {
++	    // leaf nodes at maxdepth-1.
++	    if (parent != null)
++	      {
++		if (i % 2 == 0)
++		  {
++	            // Current "parent" has "left" set already.
++		    Node next = parent.right;
++		    parent.right = nil;
++		    parent = next;
++		  }		  		  
++		while (parent != null)
++		  {
++		    parent.left = nil;
++		    Node next = parent.right;
++		    parent.right = nil;
++		    parent = next;
++		  }
++	      }
++	    // leaf nodes at maxdepth.
++	    Node node = row;
++	    Node next;
++	    while (node != null)
++	      {
++	        node.left = nil;
++		next = node.right;
++		node.right = nil;
++		node = next;
++	      }
++	  }
++      }
++  }
++  
++  private class VerifyResult
++  {
++    int count; // Total number of nodes.
++    int black; // Black height/depth.
++    int maxdepth; // Maximum depth of branch.
+   }
+ 
+-  /**
+-   * Serializes this object to the given stream.
+-   *
+-   * @param s the stream to write to
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the <i>size</i> (int), followed by key (Object) and value
+-   *             (Object) pairs in sorted order
+-   */
+-  private void writeObject(ObjectOutputStream s) throws IOException
++  /* Check that red-black properties are consistent for the tree. */
++  private void verifyTree()
+   {
+-    s.defaultWriteObject();
+-
+-    Node node = firstNode();
+-    s.writeInt(size);
+-    while (node != nil)
++    if (root == nil)
++      {
++        System.err.println ("Verify: empty tree");
++	if (size != 0)
++	  verifyError (this, "no root node but size=" + size);
++	return;
++      }
++    VerifyResult vr = verifySub (root);
++    if (vr.count != size)
++      {
++	verifyError (this, "Tree size not consistent with actual nodes counted. "
++                     + "counted " + vr.count + ", size=" + size);
++        System.exit(1);
++      }
++    System.err.println ("Verify: " + vr.count + " nodes, black height=" + vr.black
++                        + ", maxdepth=" + vr.maxdepth);
++  }
++  
++  /* Recursive call to check that rbtree rules hold. Returns total node count
++     and black height of the given branch. */
++  private VerifyResult verifySub(Node n)
++  {
++    VerifyResult vr1 = null;
++    VerifyResult vr2 = null;
++    
++    if (n.left == nil && n.right == nil)
++      {
++        // leaf node
++	VerifyResult r = new VerifyResult();
++	r.black = (n.color == BLACK ? 1 : 0);
++	r.count = 1;
++	r.maxdepth = 1;
++	return r;
++      }
++    
++    if (n.left != nil)
++      {
++        if (n.left.parent != n)
++	  verifyError(n.left, "Node's parent link does not point to " + n);
++	
++	if (n.color == RED && n.left.color == RED)
++	  verifyError(n, "Red node has red left child");
++	
++	vr1 = verifySub (n.left);
++	if (n.right == nil)
++	  {
++	    if (n.color == BLACK)
++	      vr1.black++;
++	    vr1.count++;
++	    vr1.maxdepth++;
++	    return vr1;
++	  }
++      }
++
++    if (n.right != nil)
++      {
++        if (n.right.parent != n)
++	  verifyError(n.right, "Node's parent link does not point to " + n);
++
++	if (n.color == RED && n.right.color == RED)
++	  verifyError(n, "Red node has red right child");
++
++	vr2 = verifySub (n.right);
++	if (n.left == nil)
++	  {
++	    if (n.color == BLACK)
++	      vr2.black++;
++	    vr2.count++;
++	    vr2.maxdepth++;
++	    return vr2;
++	  }
++      }
++    
++    if (vr1.black != vr2.black)
++      verifyError (n, "Black heights: " + vr1.black + "," + vr2.black + " don't match.");
++    vr1.count += vr2.count + 1;
++    vr1.maxdepth = Math.max(vr1.maxdepth, vr2.maxdepth) + 1;
++    if (n.color == BLACK)
++      vr1.black++;
++    return vr1;
++  }
++  
++  private void verifyError (Object obj, String msg)
++  {
++    System.err.print ("Verify error: ");
++    try
++      {
++        System.err.print (obj);
++      }
++    catch (Exception x)
+       {
+-        s.writeObject(node.key);
+-        s.writeObject(node.value);
+-        node = successor(node);
++        System.err.print ("(error printing obj): " + x);
+       }
++    System.err.println();
++    System.err.println (msg);
++    Thread.dumpStack();
++    System.exit(1);
+   }
+ 
+   /**
+-   * Iterate over HashMap's entries. This implementation is parameterized
+-   * to give a sequential view of keys, values, or entries.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private final class TreeIterator implements Iterator
+-  {
+-    /**
+-     * The type of this Iterator: {@link #KEYS}, {@link #VALUES},
+-     * or {@link #ENTRIES}.
+-     */
+-    private final int type;
+-    /** The number of modifications to the backing Map that we know about. */
+-    private int knownMod = modCount;
+-    /** The last Entry returned by a next() call. */
+-    private Node last;
+-    /** The next entry that should be returned by next(). */
+-    private Node next;
+-    /**
+-     * The last node visible to this iterator. This is used when iterating
+-     * on a SubMap.
+-     */
+-    private final Node max;
+-
+-    /**
+-     * Construct a new TreeIterator with the supplied type.
+-     * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
+-     */
++   * Iterate over HashMap's entries.
++   * This implementation is parameterized to give a sequential view of
++   * keys, values, or entries.
++   */   
++  class TreeIterator implements Iterator
++  {
++    static final int ENTRIES = 0,
++                     KEYS = 1,
++                     VALUES = 2;  
++  
++    // the type of this Iterator: KEYS, VALUES, or ENTRIES.
++    int type;
++    // the number of modifications to the backing Map that we know about.
++    int knownMod = TreeMap.this.modCount;
++    // The last Entry returned by a next() call.
++    Node last;
++    // The next entry that should be returned by next().
++    Node next;
++    // The last node visible to this iterator. This is used when iterating
++    // on a SubMap.
++    Node max;
++
++    /* Create Iterator with the supplied type: KEYS, VALUES, or ENTRIES */
+     TreeIterator(int type)
+     {
+-      // FIXME gcj cannot handle this. Bug java/4695
+-      // this(type, firstNode(), nil);
+       this.type = type;
+       this.next = firstNode();
+-      this.max = nil;
+     }
+-
+-    /**
+-     * Construct a new TreeIterator with the supplied type. Iteration will
+-     * be from "first" (inclusive) to "max" (exclusive).
+-     *
+-     * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
+-     * @param first where to start iteration, nil for empty iterator
+-     * @param max the cutoff for iteration, nil for all remaining nodes
+-     */
++    
++    /* Construct an interator for a SubMap. Iteration will begin at node
++       "first", and stop when "max" is reached. */    
+     TreeIterator(int type, Node first, Node max)
+     {
+       this.type = type;
+@@ -1413,351 +1192,263 @@
+       this.max = max;
+     }
+ 
+-    /**
+-     * Returns true if the Iterator has more elements.
+-     * @return true if there are more elements
+-     * @throws ConcurrentModificationException if the TreeMap was modified
+-     */
+     public boolean hasNext()
+     {
+-      if (knownMod != modCount)
+-        throw new ConcurrentModificationException();
+-      return next != max;
++      if (knownMod != TreeMap.this.modCount)
++	throw new ConcurrentModificationException();
++      return (next != nil);
+     }
+ 
+-    /**
+-     * Returns the next element in the Iterator's sequential view.
+-     * @return the next element
+-     * @throws ConcurrentModificationException if the TreeMap was modified
+-     * @throws NoSuchElementException if there is none
+-     */
+     public Object next()
+     {
+-      if (knownMod != modCount)
+-        throw new ConcurrentModificationException();
+-      if (next == max)
+-        throw new NoSuchElementException();
+-      last = next;
+-      next = successor(last);
+-
++      if (next == nil)
++	throw new NoSuchElementException();
++      if (knownMod != TreeMap.this.modCount)
++	throw new ConcurrentModificationException();
++      Node n = next;
++
++      // Check limit in case we are iterating through a submap.
++      if (n != max)
++	next = successor(n);
++      else
++        next = nil;
++      
++      last = n;
++      
+       if (type == VALUES)
+-        return last.value;
++        return n.value;
+       else if (type == KEYS)
+-        return last.key;
+-      return last;
++        return n.key;
++      return n;
+     }
+ 
+-    /**
+-     * Removes from the backing TreeMap the last element which was fetched
+-     * with the <code>next()</code> method.
+-     * @throws ConcurrentModificationException if the TreeMap was modified
+-     * @throws IllegalStateException if called when there is no last element
+-     */
+     public void remove()
+     {
+-      if (knownMod != modCount)
+-        throw new ConcurrentModificationException();
+       if (last == null)
+-        throw new IllegalStateException();
+-
+-      removeNode(last);
+-      last = null;
++	throw new IllegalStateException();
++      if (knownMod != TreeMap.this.modCount)
++	throw new ConcurrentModificationException();
++/*
++      Object key = null;
++      if (next != nil)
++        key = next.key;
++*/
++      TreeMap.this.removeNode(last);
+       knownMod++;
++/*
++      if (key != null)
++        next = getNode(key);
++*/	
++      last = null;
+     }
+-  } // class TreeIterator
++  }
+ 
+-  /**
+-   * Implementation of {@link #subMap(Object, Object)} and other map
+-   * ranges. This class provides a view of a portion of the original backing
+-   * map, and throws {@link IllegalArgumentException} for attempts to
+-   * access beyond that range.
+-   *
+-   * @author Eric Blake <ebb9@email.byu.edu>
+-   */
+-  private final class SubMap extends AbstractMap implements SortedMap
++  class SubMap extends AbstractMap implements SortedMap
+   {
+-    /**
+-     * The lower range of this view, inclusive, or nil for unbounded.
+-     * Package visible for use by nested classes.
+-     */
+-    final Object minKey;
+-
+-    /**
+-     * The upper range of this view, exclusive, or nil for unbounded.
+-     * Package visible for use by nested classes.
+-     */
+-    final Object maxKey;
+-
+-    /**
+-     * The cache for {@link #entrySet()}.
+-     */
+-    private Set entries;
+-
+-    /**
+-     * Create a SubMap representing the elements between minKey (inclusive)
+-     * and maxKey (exclusive). If minKey is nil, SubMap has no lower bound
+-     * (headMap). If maxKey is nil, the SubMap has no upper bound (tailMap).
+-     *
+-     * @param minKey the lower bound
+-     * @param maxKey the upper bound
+-     * @throws IllegalArgumentException if minKey &gt; maxKey
+-     */
++    Object minKey;
++    Object maxKey;
++
++    /* Create a SubMap representing the elements between minKey and maxKey
++       (inclusive). If minKey is nil, SubMap has no lower bound (headMap).
++       If maxKey is nil, the SubMap has no upper bound (tailMap). */
+     SubMap(Object minKey, Object maxKey)
+     {
+-      if (minKey != nil && maxKey != nil && compare(minKey, maxKey) > 0)
+-        throw new IllegalArgumentException("fromKey > toKey");
+       this.minKey = minKey;
+       this.maxKey = maxKey;
+     }
+ 
+-    /**
+-     * Check if "key" is in within the range bounds for this SubMap. The
+-     * lower ("from") SubMap range is inclusive, and the upper ("to") bound
+-     * is exclusive. Package visible for use by nested classes.
+-     *
+-     * @param key the key to check
+-     * @return true if the key is in range
+-     */
+-    final boolean keyInRange(Object key)
+-    {
+-      return ((minKey == nil || compare(key, minKey) >= 0)
+-              && (maxKey == nil || compare(key, maxKey) < 0));
+-    }
+-
+     public void clear()
+     {
+-      Node next = lowestGreaterThan(minKey, true);
+-      Node max = lowestGreaterThan(maxKey, false);
+-      while (next != max)
++      Node current;
++      Node next = lowestGreaterThan(minKey);
++      Node max = highestLessThan(maxKey);
++      
++      if (compare(next.key, max.key) > 0)
++        // Nothing to delete.
++	return;
++        
++      do
+         {
+-          Node current = next;
+-          next = successor(current);
+-          removeNode(current);
+-        }
+-    }
+-
+-    public Comparator comparator()
++	  current = next;
++	  next = successor(current);
++	  remove(current);
++	}
++      while (current != max);
++    }
++    
++    /* Check if "key" is in within the range bounds for this SubMap. 
++       The lower ("from") SubMap range is inclusive, and the upper (to) bound
++       is exclusive. */
++    private boolean keyInRange(Object key)
+     {
+-      return comparator;
++      return ((minKey == nil || compare(key, minKey) >= 0)
++	      && (maxKey == nil || compare(key, maxKey) < 0));
+     }
+ 
+     public boolean containsKey(Object key)
+     {
+-      return keyInRange(key) && TreeMap.this.containsKey(key);
++      return (keyInRange(key) && TreeMap.this.containsKey(key));
+     }
+ 
+     public boolean containsValue(Object value)
+     {
+-      Node node = lowestGreaterThan(minKey, true);
+-      Node max = lowestGreaterThan(maxKey, false);
+-      while (node != max)
+-        {
+-          if (equals(value, node.getValue()))
+-            return true;
+-          node = successor(node);
+-        }
+-      return false;
+-    }
+-
+-    public Set entrySet()
+-    {
+-      if (entries == null)
+-        // Create an AbstractSet with custom implementations of those methods
+-        // that can be overriden easily and efficiently.
+-        entries = new AbstractSet()
+-        {
+-          public int size()
+-          {
+-            return SubMap.this.size();
+-          }
+-
+-          public Iterator iterator()
+-          {
+-            Node first = lowestGreaterThan(minKey, true);
+-            Node max = lowestGreaterThan(maxKey, false);
+-            return new TreeIterator(ENTRIES, first, max);
+-          }
+-
+-          public void clear()
+-          {
+-            SubMap.this.clear();
+-          }
+-
+-          public boolean contains(Object o)
+-          {
+-            if (! (o instanceof Map.Entry))
+-              return false;
+-            Map.Entry me = (Map.Entry) o;
+-            Object key = me.getKey();
+-            if (! keyInRange(key))
+-              return false;
+-            Node n = getNode(key);
+-            return n != nil && AbstractSet.equals(me.getValue(), n.value);
+-          }
+-
+-          public boolean remove(Object o)
+-          {
+-            if (! (o instanceof Map.Entry))
+-              return false;
+-            Map.Entry me = (Map.Entry) o;
+-            Object key = me.getKey();
+-            if (! keyInRange(key))
+-              return false;
+-            Node n = getNode(key);
+-            if (n != nil && AbstractSet.equals(me.getValue(), n.value))
+-              {
+-                removeNode(n);
+-                return true;
+-              }
+-            return false;
+-          }
+-        };
+-      return entries;
+-    }
+-
+-    public Object firstKey()
+-    {
+-      Node node = lowestGreaterThan(minKey, true);
+-      if (node == nil || ! keyInRange(node.key))
+-        throw new NoSuchElementException();
+-      return node.key;
++      Node node = lowestGreaterThan(minKey);
++      Node max = highestLessThan(maxKey);
++      Object currentVal;
++
++      if (node == nil || max == nil || compare(node.key, max.key) > 0)
++        // Nothing to search.
++	return false;
++
++      while (true)
++	{
++	  currentVal = node.getValue();
++          if (value == null ? currentVal == null : value.equals (currentVal))
++	    return true;
++	  if (node == max)
++	    return false;
++	  node = successor(node);
++	}
+     }
+ 
+     public Object get(Object key)
+     {
+       if (keyInRange(key))
+-        return TreeMap.this.get(key);
++	return TreeMap.this.get(key);
+       return null;
+     }
+ 
+-    public SortedMap headMap(Object toKey)
++    public Object put(Object key, Object value)
+     {
+-      if (! keyInRange(toKey))
+-        throw new IllegalArgumentException("key outside range");
+-      return new SubMap(minKey, toKey);
++      if (keyInRange(key))
++	return TreeMap.this.put(key, value);
++      else
++	throw new IllegalArgumentException("Key outside range");
+     }
+ 
+-    public Set keySet()
++    public Object remove(Object key)
+     {
+-      if (this.keys == null)
+-        // Create an AbstractSet with custom implementations of those methods
+-        // that can be overriden easily and efficiently.
+-        this.keys = new AbstractSet()
+-        {
+-          public int size()
+-          {
+-            return SubMap.this.size();
+-          }
++      if (keyInRange(key))
++	return TreeMap.this.remove(key);
++      else
++        return null;
++    }
+ 
+-          public Iterator iterator()
+-          {
+-            Node first = lowestGreaterThan(minKey, true);
+-            Node max = lowestGreaterThan(maxKey, false);
+-            return new TreeIterator(KEYS, first, max);
+-          }
++    public int size()
++    {
++      Node node = lowestGreaterThan(minKey);
++      Node max = highestLessThan(maxKey);
+ 
+-          public void clear()
+-          {
+-            SubMap.this.clear();
+-          }
++      if (node == nil || max == nil || compare(node.key, max.key) > 0)
++	return 0;  // Empty.
+ 
+-          public boolean contains(Object o)
+-          {
+-            if (! keyInRange(o))
+-              return false;
+-            return getNode(o) != nil;
+-          }
++      int count = 1;
++      while (node != max)
++        {
++	  count++;
++	  node = successor(node);
++	}
+ 
+-          public boolean remove(Object o)
+-          {
+-            if (! keyInRange(o))
+-              return false;
+-            Node n = getNode(o);
+-            if (n != nil)
+-              {
+-                removeNode(n);
+-                return true;
+-              }
+-            return false;
+-          }
+-        };
+-      return this.keys;
++      return count;
+     }
+ 
+-    public Object lastKey()
++    public Set entrySet()
+     {
+-      Node node = highestLessThan(maxKey);
+-      if (node == nil || ! keyInRange(node.key))
+-        throw new NoSuchElementException();
+-      return node.key;
++      // Create an AbstractSet with custom implementations of those methods that 
++      // can be overriden easily and efficiently.
++      return new AbstractSet()
++      {
++	public int size()
++	{
++          return SubMap.this.size();
++	}
++
++	public Iterator iterator()
++	{
++	  Node first = lowestGreaterThan(minKey);
++	  Node max = highestLessThan(maxKey);
++          return new TreeIterator(TreeIterator.ENTRIES, first, max);
++	}
++
++	public void clear()
++	{
++          this.clear();
++	}
++
++	public boolean contains(Object o)
++	{
++          if (!(o instanceof Map.Entry))
++	    return false;
++	  Map.Entry me = (Map.Entry) o;
++	  Object key = me.getKey();
++	  if (!keyInRange(key))
++	    return false;
++	  Node n = getNode(key);
++	  return (n != nil && me.getValue().equals(n.value));
++	}
++
++	public boolean remove(Object o)
++	{
++          if (!(o instanceof Map.Entry))
++	    return false;
++	  Map.Entry me = (Map.Entry) o;
++	  Object key = me.getKey();
++	  if (!keyInRange(key))
++	    return false;
++	  Node n = getNode(key);
++	  if (n != nil && me.getValue().equals(n.value))
++	    {
++	      removeNode(n);
++	      return true;
++	    }
++	  return false;
++	}
++      };    
+     }
+ 
+-    public Object put(Object key, Object value)
++    public Comparator comparator()
+     {
+-      if (! keyInRange(key))
+-        throw new IllegalArgumentException("Key outside range");
+-      return TreeMap.this.put(key, value);
++      return comparator;
+     }
+ 
+-    public Object remove(Object key)
++    public Object firstKey()
+     {
+-      if (keyInRange(key))
+-        return TreeMap.this.remove(key);
+-      return null;
++      Node node = lowestGreaterThan(minKey);
++      if (node == nil || !keyInRange(node.key))
++        throw new NoSuchElementException ("empty");
++      return node.key;
+     }
+ 
+-    public int size()
++    public Object lastKey()
+     {
+-      Node node = lowestGreaterThan(minKey, true);
+-      Node max = lowestGreaterThan(maxKey, false);
+-      int count = 0;
+-      while (node != max)
+-        {
+-          count++;
+-          node = successor(node);
+-        }
+-      return count;
++      Node node = highestLessThan(maxKey);
++      if (node == nil || !keyInRange(node.key))
++        throw new NoSuchElementException ("empty");
++      return node.key;
+     }
+ 
+     public SortedMap subMap(Object fromKey, Object toKey)
+     {
+-      if (! keyInRange(fromKey) || ! keyInRange(toKey))
++      if (!keyInRange(fromKey) || !keyInRange(toKey))
+         throw new IllegalArgumentException("key outside range");
+-      return new SubMap(fromKey, toKey);
++
++      return TreeMap.this.subMap(fromKey, toKey);
+     }
+ 
+-    public SortedMap tailMap(Object fromKey)
++    public SortedMap headMap(Object toKey)
+     {
+-      if (! keyInRange(fromKey))
++      if (!keyInRange(toKey))
+         throw new IllegalArgumentException("key outside range");
+-      return new SubMap(fromKey, maxKey);
++
++      return TreeMap.this.subMap(minKey, toKey);
+     }
+ 
+-    public Collection values()
++    public SortedMap tailMap(Object fromKey)
+     {
+-      if (this.values == null)
+-        // Create an AbstractCollection with custom implementations of those
+-        // methods that can be overriden easily and efficiently.
+-        this.values = new AbstractCollection()
+-        {
+-          public int size()
+-          {
+-            return SubMap.this.size();
+-          }
+-
+-          public Iterator iterator()
+-          {
+-            Node first = lowestGreaterThan(minKey, true);
+-            Node max = lowestGreaterThan(maxKey, false);
+-            return new TreeIterator(VALUES, first, max);
+-          }
++      if (!keyInRange(fromKey))
++        throw new IllegalArgumentException("key outside range");
+ 
+-          public void clear()
+-          {
+-            SubMap.this.clear();
+-          }
+-        };
+-      return this.keys;
++      return TreeMap.this.subMap(fromKey, maxKey);
+     }
+-  } // class SubMap
+-} // class TreeMap
++  }
++}
Index: compare/java.util.TreeSet.diff
===================================================================
RCS file: java.util.TreeSet.diff
diff -N java.util.TreeSet.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.TreeSet.diff Tue Nov 6 17:21:37 2001
@@ -0,0 +1,480 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/TreeSet.java	Fri Oct 26 16:06:59 2001
++++ java/util/TreeSet.java	Tue Oct 16 09:14:35 2001
+@@ -1,4 +1,4 @@
+-/* TreeSet.java -- a class providing a TreeMap-backed SortedSet
++/* TreeSet.java -- a class providing a TreeMap-backet SortedSet
+    Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+@@ -33,90 +33,54 @@
+ import java.io.ObjectOutputStream;
+ 
+ /**
+- * This class provides a TreeMap-backed implementation of the SortedSet
+- * interface. The elements will be sorted according to their <i>natural
+- * order</i>, or according to the provided <code>Comparator</code>.<p>
++ * This class provides a TreeMap-backed implementation of the 
++ * SortedSet interface.
+  *
+- * Most operations are O(log n), but there is so much overhead that this
+- * makes small sets expensive. Note that the ordering must be <i>consistent
+- * with equals</i> to correctly implement the Set interface. If this
+- * condition is violated, the set is still well-behaved, but you may have
+- * suprising results when comparing it to other sets.<p>
++ * Each element in the Set is a key in the backing TreeMap; each key
++ * maps to a static token, denoting that the key does, in fact, exist.
+  *
+- * This implementation is not synchronized. If you need to share this between
+- * multiple threads, do something like:<br>
+- * <code>SortedSet s
+- *       = Collections.synchronizedSortedSet(new TreeSet(...));</code><p>
++ * Most operations are O(log n).
+  *
+- * The iterators are <i>fail-fast</i>, meaning that any structural
+- * modification, except for <code>remove()</code> called on the iterator
+- * itself, cause the iterator to throw a
+- * <code>ConcurrentModificationException</code> rather than exhibit
+- * non-deterministic behavior.
++ * TreeSet is a part of the JDK1.2 Collections API.
+  *
+- * @author Jon Zeppieri
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see Set
+- * @see HashSet
+- * @see LinkedHashSet
+- * @see Comparable
+- * @see Comparator
+- * @see Collections#synchronizedSortedSet(SortedSet)
+- * @see TreeMap
+- * @since 1.2
+- * @status updated to 1.4
++ * @author      Jon Zeppieri
+  */
++
+ public class TreeSet extends AbstractSet
+   implements SortedSet, Cloneable, Serializable
+ {
+-  /**
+-   * Compatible with JDK 1.2.
+-   */
+-  private static final long serialVersionUID = -2479143000061671589L;
++  /** The TreeMap which backs this Set */
++  transient SortedMap map;
+ 
+-  /**
+-   * The SortedMap which backs this Set.
+-   */
+-  // Not final because of readObject. This will always be one of TreeMap or
+-  // TreeMap.SubMap, which both extend AbstractMap.
+-  private transient SortedMap map;
++  static final long serialVersionUID = -2479143000061671589L;
+ 
+   /**
+-   * Construct a new TreeSet whose backing TreeMap using the "natural"
+-   * ordering of keys. Elements that are not mutually comparable will cause
+-   * ClassCastExceptions down the road.
+-   *
+-   * @see Comparable
++   * Construct a new TreeSet whose backing TreeMap using the "natural" 
++   * ordering of keys.
+    */
+   public TreeSet()
+   {
+     map = new TreeMap();
+   }
+ 
+-  /**
+-   * Construct a new TreeSet whose backing TreeMap uses the supplied
+-   * Comparator. Elements that are not mutually comparable will cause
+-   * ClassCastExceptions down the road.
++  /** 
++   * Construct a new TreeSet whose backing TreeMap uses the supplied 
++   * Comparator.
+    *
+-   * @param comparator the Comparator this Set will use
++   * @param     oComparator      the Comparator this Set will use
+    */
+   public TreeSet(Comparator comparator)
+   {
+     map = new TreeMap(comparator);
+   }
+ 
+-  /**
++  /** 
+    * Construct a new TreeSet whose backing TreeMap uses the "natural"
+    * orering of the keys and which contains all of the elements in the
+-   * supplied Collection. This runs in n*log(n) time.
++   * supplied Collection.
+    *
+-   * @param collection the new Set will be initialized with all
+-   *        of the elements in this Collection
+-   * @throws ClassCastException if the elements of the collection are not
+-   *         comparable
+-   * @throws NullPointerException if the collection is null
+-   * @see Comparable
++   * @param     oCollection      the new Set will be initialized with all
++   *                             of the elements in this Collection
+    */
+   public TreeSet(Collection collection)
+   {
+@@ -129,57 +93,54 @@
+    * SortedSet and containing all of the elements in the supplied SortedSet.
+    * This constructor runs in linear time.
+    *
+-   * @param sortedSet the new TreeSet will use this SortedSet's comparator
+-   *        and will initialize itself with all its elements
+-   * @throws NullPointerException if sortedSet is null
++   * @param     sortedSet       the new TreeSet will use this SortedSet's
++   *                            comparator and will initialize itself
++   *                            with all of the elements in this SortedSet
+    */
+   public TreeSet(SortedSet sortedSet)
+   {
+-    map = new TreeMap(sortedSet.comparator());
++    TreeMap map = new TreeMap(sortedSet.comparator());
++    int i = 0;
+     Iterator itr = sortedSet.iterator();
+-    ((TreeMap) map).putKeysLinear(itr, sortedSet.size());
++    map.putKeysLinear(itr, sortedSet.size());
++    this.map = map;
+   }
+-
+-  /**
+-   * This private constructor is used to implement the subSet() calls around
+-   * a backing TreeMap.SubMap.
+-   *
+-   * @param backingMap the submap
+-   */
+-  private TreeSet(SortedMap backingMap)
++  
++  /* This private constructor is used to implement the subSet() calls around
++    a backing TreeMap.SubMap. */
++  TreeSet(SortedMap backingMap)
+   {
+     map = backingMap;
+   }
+ 
+-  /**
++  /** 
+    * Adds the spplied Object to the Set if it is not already in the Set;
+-   * returns true if the element is added, false otherwise.
++   * returns true if the element is added, false otherwise
+    *
+-   * @param obj the Object to be added to this Set
+-   * @throws ClassCastException if the element cannot be compared with objects
+-   *         already in the set
++   * @param       obj       the Object to be added to this Set
+    */
+   public boolean add(Object obj)
+   {
+-    return map.put(obj, "") == null;
++    return (map.put(obj, Boolean.TRUE) == null);
+   }
+ 
+   /**
+    * Adds all of the elements in the supplied Collection to this TreeSet.
+    *
+-   * @param c The collection to add
+-   * @return true if the Set is altered, false otherwise
+-   * @throws NullPointerException if c is null
+-   * @throws ClassCastException if an element in c cannot be compared with
+-   *         objects already in the set
++   * @param        c         All of the elements in this Collection
++   *                         will be added to the Set.
++   *
++   * @return       true if the Set is altered, false otherwise
+    */
+   public boolean addAll(Collection c)
+   {
+     boolean result = false;
+-    int pos = c.size();
++    int size = c.size();
+     Iterator itr = c.iterator();
+-    while (--pos >= 0)
+-      result |= (map.put(itr.next(), "") == null);
++
++    for (int i = 0; i < size; i++)
++      result |= (map.put(itr.next(), Boolean.TRUE) == null);
++
+     return result;
+   }
+ 
+@@ -191,214 +152,137 @@
+     map.clear();
+   }
+ 
+-  /**
+-   * Returns a shallow copy of this Set. The elements are not cloned.
+-   *
+-   * @return the cloned set
+-   */
++  /** Returns a shallow copy of this Set. */
+   public Object clone()
+   {
+     TreeSet copy = null;
+     try
+       {
+         copy = (TreeSet) super.clone();
+-        // Map may be either TreeMap or TreeMap.SubMap, hence the ugly casts.
+-        copy.map = (SortedMap) ((AbstractMap) map).clone();
+       }
+     catch (CloneNotSupportedException x)
+-      {
+-        // Impossible result.
++      {      
+       }
++    copy.map = (SortedMap) ((TreeMap) map).clone();
+     return copy;
+   }
+ 
+-  /**
+-   * Returns this Set's comparator.
+-   *
+-   * @return the comparator, or null if the set uses natural ordering
+-   */
++  /** Returns this Set's comparator */
+   public Comparator comparator()
+   {
+     return map.comparator();
+   }
+ 
+-  /**
+-   * Returns true if this Set contains the supplied Object, false otherwise.
++  /** 
++   * Returns true if this Set contains the supplied Object, 
++   * false otherwise 
+    *
+-   * @param obj the Object to check for
+-   * @return true if it is in the set
+-   * @throws ClassCastException if obj cannot be compared with objects
+-   *         already in the set
++   * @param       oObject        the Object whose existence in the Set is
++   *                             being tested
+    */
+   public boolean contains(Object obj)
+   {
+     return map.containsKey(obj);
+   }
+ 
+-  /**
+-   * Returns the first (by order) element in this Set.
+-   *
+-   * @return the first element
+-   * @throws NoSuchElementException if the set is empty
+-   */
+-  public Object first()
++  /** Returns true if this Set has size 0, false otherwise */
++  public boolean isEmpty()
+   {
+-    return map.firstKey();
++    return map.isEmpty();
+   }
+ 
+-  /**
+-   * Returns a view of this Set including all elements less than
+-   * <code>to</code>. The returned set is backed by the original, so changes
+-   * in one appear in the other. The subset will throw an
+-   * {@link IllegalArgumentException} for any attempt to access or add an
+-   * element beyond the specified cutoff. The returned set does not include
+-   * the endpoint; if you want inclusion, pass the successor element.
+-   *
+-   * @param to the (exclusive) cutoff point
+-   * @return a view of the set less than the cutoff
+-   * @throws ClassCastException if <code>to</code> is not compatible with
+-   *         the comparator (or is not Comparable, for natural ordering)
+-   * @throws NullPointerException if to is null, but the comparator does not
+-   *         tolerate null elements
+-   */
+-  public SortedSet headSet(Object to)
++  /** Returns the number of elements in this Set */
++  public int size()
+   {
+-    return new TreeSet(map.headMap(to));
++    return map.size();
+   }
+ 
+-  /**
+-   * Returns true if this Set has size 0, false otherwise.
++  /** 
++   * If the supplied Object is in this Set, it is removed, and true is
++   * returned; otherwise, false is returned.
+    *
+-   * @return true if the set is empty
++   * @param         obj        the Object we are attempting to remove
++   *                           from this Set
+    */
+-  public boolean isEmpty()
++  public boolean remove(Object obj)
+   {
+-    return map.isEmpty();
++    return (map.remove(obj) != null);
+   }
+ 
+-  /**
+-   * Returns in Iterator over the elements in this TreeSet, which traverses
+-   * in ascending order.
+-   *
+-   * @return an iterator
+-   */
+-  public Iterator iterator()
++  /** Returns the first (by order) element in this Set */
++  public Object first()
+   {
+-    return map.keySet().iterator();
++    return map.firstKey();
+   }
+ 
+-  /**
+-   * Returns the last (by order) element in this Set.
+-   *
+-   * @return the last element
+-   * @throws NoSuchElementException if the set is empty
+-   */
++  /** Returns the last (by order) element in this Set */
+   public Object last()
+   {
+     return map.lastKey();
+   }
+ 
+   /**
+-   * If the supplied Object is in this Set, it is removed, and true is
+-   * returned; otherwise, false is returned.
++   * Returns a view of this Set including all elements in the interval
++   * [oFromElement, oToElement).
+    *
+-   * @param obj the Object to remove from this Set
+-   * @return true if the set was modified
+-   * @throws ClassCastException if obj cannot be compared to set elements
++   * @param       from  the resultant view will contain all
++   *                    elements greater than or equal to this element
++   * @param       to    the resultant view will contain all
++   *                    elements less than this element
+    */
+-  public boolean remove(Object obj)
++  public SortedSet subSet(Object from, Object to)
+   {
+-    return map.remove(obj) != null;
++    return new TreeSet(map.subMap(from, to));
+   }
+ 
+   /**
+-   * Returns the number of elements in this Set
++   * Returns a view of this Set including all elements less than oToElement
+    *
+-   * @return the set size
++   * @param       toElement    the resultant view will contain all
++   *                            elements less than this element
+    */
+-  public int size()
++  public SortedSet headSet(Object to)
+   {
+-    return map.size();
++    return new TreeSet(map.headMap(to));
+   }
+ 
+   /**
+-   * Returns a view of this Set including all elements greater or equal to
+-   * <code>from</code> and less than <code>to</code> (a half-open interval).
+-   * The returned set is backed by the original, so changes in one appear in
+-   * the other. The subset will throw an {@link IllegalArgumentException}
+-   * for any attempt to access or add an element beyond the specified cutoffs.
+-   * The returned set includes the low endpoint but not the high; if you want
+-   * to reverse this behavior on either end, pass in the successor element.
+-   *
+-   * @param from the (inclusive) low cutoff point
+-   * @param to the (exclusive) high cutoff point
+-   * @return a view of the set between the cutoffs
+-   * @throws ClassCastException if either cutoff is not compatible with
+-   *         the comparator (or is not Comparable, for natural ordering)
+-   * @throws NullPointerException if from or to is null, but the comparator
+-   *         does not tolerate null elements
+-   * @throws IllegalArgumentException if from is greater than to
++   * Returns a view of this Set including all elements greater than or
++   * equal to oFromElement.
++   *
++   * @param       from  the resultant view will contain all
++   *              elements greater than or equal to this element
+    */
+-  public SortedSet subSet(Object from, Object to)
++  public SortedSet tailSet(Object from)
+   {
+-    return new TreeSet(map.subMap(from, to));
++    return new TreeSet(map.tailMap(from));
+   }
+ 
+-  /**
+-   * Returns a view of this Set including all elements greater or equal to
+-   * <code>from</code>. The returned set is backed by the original, so
+-   * changes in one appear in the other. The subset will throw an
+-   * {@link IllegalArgumentException} for any attempt to access or add an
+-   * element beyond the specified cutoff. The returned set includes the
+-   * endpoint; if you want to exclude it, pass in the successor element.
+-   *
+-   * @param from the (inclusive) low cutoff point
+-   * @return a view of the set above the cutoff
+-   * @throws ClassCastException if <code>from</code> is not compatible with
+-   *         the comparator (or is not Comparable, for natural ordering)
+-   * @throws NullPointerException if from is null, but the comparator
+-   *         does not tolerate null elements
+-   */
+-  public SortedSet tailSet(Object from)
++  /** Returns in Iterator over the elements in this TreeSet */
++  public Iterator iterator()
+   {
+-    return new TreeSet(map.tailMap(from));
++    return map.keySet().iterator();
+   }
+ 
+-  /**
+-   * Serializes this object to the given stream.
+-   *
+-   * @param s the stream to write to
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the <i>comparator</i> (Object), followed by the set size
+-   *             (int), the the elements in sorted order (Object)
+-   */
+-  private void writeObject(ObjectOutputStream s) throws IOException
++  private void writeObject(ObjectOutputStream out) throws IOException
+   {
+-    s.defaultWriteObject();
+     Iterator itr = map.keySet().iterator();
+-    int pos = map.size();
+-    s.writeObject(map.comparator());
+-    s.writeInt(pos);
+-    while (--pos >= 0)
+-      s.writeObject(itr.next());
++    int size = map.size();
++
++    out.writeObject(map.comparator());
++    out.writeInt(size);
++
++    for (int i = 0; i < size; i++)
++      out.writeObject(itr.next());
+   }
+ 
+-  /**
+-   * Deserializes this object from the given stream.
+-   *
+-   * @param s the stream to read from
+-   * @throws ClassNotFoundException if the underlying stream fails
+-   * @throws IOException if the underlying stream fails
+-   * @serialData the <i>comparator</i> (Object), followed by the set size
+-   *             (int), the the elements in sorted order (Object)
+-   */
+-  private void readObject(ObjectInputStream s)
++  private void readObject(ObjectInputStream in)
+     throws IOException, ClassNotFoundException
+   {
+-    s.defaultReadObject();
+-    Comparator comparator = (Comparator) s.readObject();
+-    int size = s.readInt();
+-    map = new TreeMap(comparator);
+-    ((TreeMap) map).putFromObjStream(s, size, false);
++    Comparator comparator = (Comparator) in.readObject();
++    int size = in.readInt();
++    TreeMap map = new TreeMap(comparator);    
++    map.putFromObjStream(in, size, false);
++    this.map = map;
+   }
+ }
Index: compare/java.util.Vector.diff
===================================================================
RCS file: java.util.Vector.diff
diff -N java.util.Vector.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.Vector.diff Tue Nov 6 17:21:38 2001
@@ -0,0 +1,1208 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/Vector.java	Fri Nov  2 09:28:56 2001
++++ java/util/Vector.java	Fri Nov  2 21:44:52 2001
+@@ -1,5 +1,5 @@
+ /* Vector.java -- Class that provides growable arrays.
+-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
++   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -30,72 +30,51 @@
+ import java.io.Serializable;
+ 
+ /**
+- * The <code>Vector</code> classes implements growable arrays of Objects.
++ * the <b>Vector</b> classes implements growable arrays of Objects.
+  * You can access elements in a Vector with an index, just as you
+  * can in a built in array, but Vectors can grow and shrink to accommodate
+- * more or fewer objects.<p>
++ * more or fewer objects.  
+  *
+  * Vectors try to mantain efficiency in growing by having a
+- * <code>capacityIncrement</code> that can be specified at instantiation.
++ * <b>capacityIncrement</b> that can be specified at instantiation.
+  * When a Vector can no longer hold a new Object, it grows by the amount
+- * in <code>capacityIncrement</code>. If this value is 0, the vector doubles in
+- * size.<p>
++ * in <b>capacityIncrement</b>.  
+  *
+- * Vector implements the JDK 1.2 List interface, and is therefore a fully
+- * compliant Collection object. The iterators are fail-fast - if external
+- * code structurally modifies the vector, any operation on the iterator will
+- * then throw a {@link ConcurrentModificationException}. The Vector class is
+- * fully synchronized, but the iterators are not. So, when iterating over a
+- * vector, be sure to synchronize on the vector itself.  If you don't want the
+- * expense of synchronization, use ArrayList instead. On the other hand, the
+- * Enumeration of elements() is not thread-safe, nor is it fail-fast; so it
+- * can lead to undefined behavior even in a single thread if you modify the
+- * vector during iteration.<p>
+- *
+- * Note: Some methods, especially those specified by List, specify throwing
+- * {@link IndexOutOfBoundsException}, but it is easier to implement by
+- * throwing the subclass {@link ArrayIndexOutOfBoundsException}. Others
+- * directly specify this subclass.
++ * Vector implements the JDK 1.2 List interface, and is therefor a fully
++ * compliant Collection object.
+  *
++ * @specnote The JCL claims that various methods in this class throw
++ * IndexOutOfBoundsException, which would be consistent with other collections
++ * classes. ArrayIndexOutOfBoundsException is actually thrown, per the online 
++ * docs, even for List method implementations.
++ * 
+  * @author Scott G. Miller
+- * @author Eric Blake <ebb9@email.byu.edu>
+- * @see Collection
+- * @see List
+- * @see ArrayList
+- * @see LinkedList
+- * @since 1.0
+- * @status updated to 1.4
+  */
+-public class Vector extends AbstractList
+-  implements List, RandomAccess, Cloneable, Serializable
++public class Vector extends AbstractList 
++  implements List, Cloneable, Serializable
+ {
+   /**
+-   * Compatible with JDK 1.0+.
++   * The amount the Vector's internal array should be increased in size when
++   * a new element is added that exceeds the current size of the array,
++   * or when {@link #ensureCapacity} is called.
++   * @serial
+    */
+-  private static final long serialVersionUID = -2767605614048989439L;
+-
+-  /**
+-   * The internal array used to hold members of a Vector. The elements are
+-   * in positions 0 through elementCount - 1, and all remaining slots are null.
+-   * @serial the elements
+-   */
+-  protected Object[] elementData;
++  protected int capacityIncrement = 0;
+ 
+   /**
+    * The number of elements currently in the vector, also returned by
+    * {@link #size}.
+-   * @serial the size
++   * @serial
+    */
+-  protected int elementCount;
++  protected int elementCount = 0;
+ 
+   /**
+-   * The amount the Vector's internal array should be increased in size when
+-   * a new element is added that exceeds the current size of the array,
+-   * or when {@link #ensureCapacity} is called. If &lt;= 0, the vector just
+-   * doubles in size.
+-   * @serial the amount to grow the vector by
++   * The internal array used to hold members of a Vector
++   * @serial
+    */
+-  protected int capacityIncrement;
++  protected Object[] elementData;
++
++  private static final long serialVersionUID = -2767605614048989439L;
+ 
+   /**
+    * Constructs an empty vector with an initial size of 10, and
+@@ -103,31 +82,36 @@
+    */
+   public Vector()
+   {
+-    this(10, 0);
++    this(10);
+   }
+ 
+   /**
+    * Constructs a vector containing the contents of Collection, in the
+-   * order given by the collection.
++   * order given by the collection
+    *
+-   * @param c collection of elements to add to the new vector
+-   * @throws NullPointerException if c is null
+-   * @since 1.2
++   * @param c A collection of elements to be added to the newly constructed
++   * vector
+    */
+   public Vector(Collection c)
+   {
+-    elementCount = c.size();
+-    elementData = c.toArray(new Object[elementCount]);
++    int csize = c.size();
++    elementData = new Object[csize];
++    elementCount = csize;
++    Iterator itr = c.iterator();
++    for (int i = 0; i < csize; i++)
++      {
++	elementData[i] = itr.next();
++      }
+   }
+ 
+   /**
+-   * Constructs a Vector with the initial capacity and capacity
+-   * increment specified.
++   * Constructs a Vector with the initial capacity and capacity 
++   * increment specified
+    *
+-   * @param initialCapacity the initial size of the Vector's internal array
+-   * @param capacityIncrement the amount the internal array should be
+-   *        increased by when necessary, 0 to double the size
+-   * @throws IllegalArgumentException if initialCapacity &lt; 0
++   * @param initialCapacity The initial size of the Vector's internal
++   * array
++   * @param capacityIncrement The amount the internal array should be
++   * increased if necessary
+    */
+   public Vector(int initialCapacity, int capacityIncrement)
+   {
+@@ -138,37 +122,37 @@
+   }
+ 
+   /**
+-   * Constructs a Vector with the initial capacity specified, and a capacity
+-   * increment of 0 (double in size).
++   * Constructs a Vector with the initial capacity specified
+    *
+-   * @param initialCapacity the initial size of the Vector's internal array
+-   * @throws IllegalArgumentException if initialCapacity &lt; 0
++   * @param initialCapacity The initial size of the Vector's internal array
+    */
+   public Vector(int initialCapacity)
+   {
+-    this(initialCapacity, 0);
++    if (initialCapacity < 0)
++      throw new IllegalArgumentException();
++    elementData = new Object[initialCapacity];
+   }
+ 
+   /**
+-   * Copies the contents of a provided array into the Vector.  If the
+-   * array is too large to fit in the Vector, an IndexOutOfBoundsException
+-   * is thrown without modifying the array.  Old elements in the Vector are
+-   * overwritten by the new elements.
+-   *
+-   * @param a target array for the copy
+-   * @throws IndexOutOfBoundsException the array is not large enough
+-   * @throws NullPointerException the array is null
+-   * @see #toArray(Object[])
++   * Copies the contents of a provided array into the Vector.  If the 
++   * array is too large to fit in the Vector, an ArrayIndexOutOfBoundsException
++   * is thrown.  Old elements in the Vector are overwritten by the new
++   * elements
++   *
++   * @param anArray An array from which elements will be copied into the Vector
++   * 
++   * @throws ArrayIndexOutOfBoundsException the array being copied
++   * is larger than the Vectors internal data array
+    */
+-  public synchronized void copyInto(Object[] a)
++  public synchronized void copyInto(Object[] anArray)
+   {
+-    System.arraycopy(elementData, 0, a, 0, elementCount);
++    System.arraycopy(elementData, 0, anArray, 0, elementCount);
+   }
+ 
+   /**
+    * Trims the Vector down to size.  If the internal data array is larger
+    * than the number of Objects its holding, a new array is constructed
+-   * that precisely holds the elements. Otherwise this does nothing.
++   * that precisely holds the elements.  
+    */
+   public synchronized void trimToSize()
+   {
+@@ -182,70 +166,68 @@
+   }
+ 
+   /**
+-   * Ensures that <code>minCapacity</code> elements can fit within this Vector.
+-   * If <code>elementData</code> is too small, it is expanded as follows:
+-   * If the <code>elementCount + capacityIncrement</code> is adequate, that
+-   * is the new size. If <code>capacityIncrement</code> is non-zero, the
+-   * candidate size is double the current. If that is not enough, the new
+-   * size is <code>minCapacity</code>.
++   * Ensures that <b>minCapacity</b> elements can fit within this Vector.
++   * If it cannot hold this many elements, the internal data array is expanded
++   * in the following manner.  If the current size plus the capacityIncrement
++   * is sufficient, the internal array is expanded by capacityIncrement.  
++   * If capacityIncrement is non-positive, the size is doubled.  If 
++   * neither is sufficient, the internal array is expanded to size minCapacity
+    *
+-   * @param minCapacity the desired minimum capacity, negative values ignored
++   * @param minCapacity The minimum capacity the internal array should be
++   * able to handle after executing this method
+    */
+   public synchronized void ensureCapacity(int minCapacity)
+   {
+     if (elementData.length >= minCapacity)
+       return;
+ 
+-    int newCapacity;
++    int newCapacity; 
+     if (capacityIncrement <= 0)
+       newCapacity = elementData.length * 2;
+     else
+       newCapacity = elementData.length + capacityIncrement;
+-
++      
+     Object[] newArray = new Object[Math.max(newCapacity, minCapacity)];
+ 
+-    System.arraycopy(elementData, 0, newArray, 0, elementCount);
++    System.arraycopy(elementData, 0, newArray, 0, elementData.length);
+     elementData = newArray;
+   }
+ 
+   /**
+-   * Explicitly sets the size of the vector (but not necessarily the size of
+-   * the internal data array). If the new size is smaller than the old one,
+-   * old values that don't fit are lost. If the new size is larger than the
+-   * old one, the vector is padded with null entries.
++   * Explicitly sets the size of the internal data array, copying the 
++   * old values to the new internal array.  If the new array is smaller
++   * than the old one, old values that don't fit are lost. If the new size
++   * is larger than the old one, the vector is padded with null entries.
+    *
+    * @param newSize The new size of the internal array
+-   * @throws ArrayIndexOutOfBoundsException if the new size is negative
+    */
+   public synchronized void setSize(int newSize)
+   {
+-    // Don't bother checking for the case where size() == the capacity of the
+-    // vector since that is a much less likely case; it's more efficient to
+-    // not do the check and lose a bit of performance in that infrequent case
+     modCount++;
+-    ensureCapacity(newSize);
+-    if (newSize < elementCount)
+-      Arrays.fill(elementData, newSize, elementCount, null);
++    Object[] newArray = new Object[newSize];
++    System.arraycopy(elementData, 0, newArray, 0, 
++                     Math.min(newSize, elementCount));
+     elementCount = newSize;
++    elementData = newArray;
+   }
+ 
+   /**
+    * Returns the size of the internal data array (not the amount of elements
+-   * contained in the Vector).
++   * contained in the Vector)
+    *
+-   * @return capacity of the internal data array
++   * @returns capacity of the internal data array
+    */
+-  public synchronized int capacity()
++  public int capacity()
+   {
+     return elementData.length;
+   }
+ 
+   /**
+-   * Returns the number of elements stored in this Vector.
++   * Returns the number of elements stored in this Vector
+    *
+-   * @return the number of elements in this Vector
++   * @returns the number of elements in this Vector
+    */
+-  public synchronized int size()
++  public int size()
+   {
+     return elementCount;
+   }
+@@ -253,89 +235,85 @@
+   /**
+    * Returns true if this Vector is empty, false otherwise
+    *
+-   * @return true if the Vector is empty, false otherwise
++   * @returns true if the Vector is empty, false otherwise
+    */
+-  public synchronized boolean isEmpty()
++  public boolean isEmpty()
+   {
+     return elementCount == 0;
+   }
+ 
+   /**
+-   * Returns an Enumeration of the elements of this Vector. The enumeration
+-   * visits the elements in increasing index order, but is NOT thread-safe.
+-   *
+-   * @return an Enumeration
+-   * @see #iterator()
++   * Searches the vector starting at <b>index</b> for object <b>elem</b>
++   * and returns the index of the first occurrence of this Object.  If
++   * the object is not found, -1 is returned
++   *
++   * @param e The Object to search for
++   * @param index Start searching at this index
++   * @returns The index of the first occurrence of <b>elem</b>, or -1
++   * if it is not found
+    */
+-  // No need to synchronize as the Enumeration is not thread-safe!
+-  public Enumeration elements()
++  public synchronized int indexOf(Object e, int index)
+   {
+-    return new Enumeration()
+-    {
+-      private int i = 0;
+-
+-      public boolean hasMoreElements()
+-      {
+-        return i < elementCount;
+-      }
+-
+-      public Object nextElement()
++    for (int i = index; i < elementCount; i++)
+       {
+-        if (i >= elementCount)
+-          throw new NoSuchElementException();
+-        return elementData[i++];
++	if (e == null ? elementData[i] == null : e.equals(elementData[i]))
++	  return i;
+       }
+-    };
++    return -1;
+   }
+ 
+   /**
+-   * Returns true when <code>elem</code> is contained in this Vector.
++   * Returns the first occurrence of <b>elem</b> in the Vector, or -1 if
++   * <b>elem</b> is not found.
+    *
+-   * @param elem the element to check
+-   * @return true if the object is contained in this Vector, false otherwise
++   * @param elem The object to search for
++   * @returns The index of the first occurrence of <b>elem</b> or -1 if 
++   * not found
+    */
+-  public boolean contains(Object elem)
++  public int indexOf(Object elem)
+   {
+-    return indexOf(elem, 0) >= 0;
++    return indexOf(elem, 0);
+   }
+ 
+   /**
+-   * Returns the first occurrence of <code>elem</code> in the Vector, or -1 if
+-   * <code>elem</code> is not found.
++   * Returns true if <b>elem</b> is contained in this Vector, false otherwise.
+    *
+-   * @param elem the object to search for
+-   * @return the index of the first occurrence, or -1 if not found
++   * @param elem The element to check
++   * @returns true if the object is contained in this Vector, false otherwise
+    */
+-  public int indexOf(Object elem)
++  public boolean contains(Object elem)
+   {
+-    return indexOf(elem, 0);
++    return indexOf(elem, 0) != -1;
+   }
+ 
+   /**
+-   * Searches the vector starting at <code>index</code> for object
+-   * <code>elem</code> and returns the index of the first occurrence of this
+-   * Object.  If the object is not found, or index is larger than the size
+-   * of the vector, -1 is returned.
+-   *
+-   * @param e the Object to search for
+-   * @param index start searching at this index
+-   * @return the index of the next occurrence, or -1 if it is not found
+-   * @throws IndexOutOfBoundsException if index &lt; 0
++   * Returns the index of the first occurrence of <b>elem</b>, when searching
++   * backwards from <b>index</b>.  If the object does not occur in this Vector,
++   * -1 is returned.
++   *
++   * @param eThe object to search for
++   * @param index The index to start searching in reverse from
++   * @returns The index of the Object if found, -1 otherwise
+    */
+-  public synchronized int indexOf(Object e, int index)
++  public synchronized int lastIndexOf(Object e, int index)
+   {
+-    for (int i = index; i < elementCount; i++)
+-      if (equals(e, elementData[i]))
+-        return i;
++    if (index >= elementCount)
++      throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
++
++    for (int i = index; i >= 0; i--)
++      {
++	if (e == null ? elementData[i] == null : e.equals(elementData[i]))
++	  return i;
++      }
+     return -1;
+   }
+ 
+   /**
+-   * Returns the last index of <code>elem</code> within this Vector, or -1
+-   * if the object is not within the Vector.
++   * Returns the last index of <b>elem</b> within this Vector, or -1
++   * if the object is not within the Vector
+    *
+-   * @param elem the object to search for
+-   * @return the last index of the object, or -1 if not found
++   * @param elem The object to search for
++   * @returns the last index of the object, or -1 if not found
+    */
+   public int lastIndexOf(Object elem)
+   {
+@@ -343,42 +321,29 @@
+   }
+ 
+   /**
+-   * Returns the index of the first occurrence of <code>elem</code>, when
+-   * searching backwards from <code>index</code>.  If the object does not
+-   * occur in this Vector, or index is less than 0, -1 is returned.
+-   *
+-   * @param e the object to search for
+-   * @param index the index to start searching in reverse from
+-   * @return the index of the Object if found, -1 otherwise
+-   * @throws IndexOutOfBoundsException if index &gt;= size()
+-   */
+-  public synchronized int lastIndexOf(Object e, int index)
+-  {
+-    checkBoundExclusive(index);
+-    for (int i = index; i >= 0; i--)
+-      if (equals(e, elementData[i]))
+-        return i;
+-    return -1;
+-  }
+-
+-  /**
+-   * Returns the Object stored at <code>index</code>.
++   * Returns the Object stored at <b>index</b>.  If index is out of range
++   * an ArrayIndexOutOfBoundsException is thrown.
+    *
+    * @param index the index of the Object to retrieve
+-   * @return the object at <code>index</code>
+-   * @throws ArrayIndexOutOfBoundsException index &lt; 0 || index &gt;= size()
+-   * @see #get(int)
++   * @returns The object at <b>index</b>
++   * @throws ArrayIndexOutOfBoundsException <b>index</b> is
++   * larger than the Vector
+    */
+   public synchronized Object elementAt(int index)
+   {
+-    checkBoundExclusive(index);
++    //Within the bounds of this Vector does not necessarily mean within 
++    //the bounds of the internal array
++    if (index >= elementCount)
++      throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
++
+     return elementData[index];
+   }
+ 
+   /**
+-   * Returns the first element (index 0) in the Vector.
++   * Returns the first element in the Vector.  If there is no first Object 
++   * (The vector is empty), a NoSuchElementException is thrown.
+    *
+-   * @return the first Object in the Vector
++   * @returns The first Object in the Vector
+    * @throws NoSuchElementException the Vector is empty
+    */
+   public synchronized Object firstElement()
+@@ -386,13 +351,14 @@
+     if (elementCount == 0)
+       throw new NoSuchElementException();
+ 
+-    return elementData[0];
++    return elementAt(0);
+   }
+ 
+   /**
+-   * Returns the last element in the Vector.
++   * Returns the last element in the Vector.  If the Vector has no last element
++   * (The vector is empty), a NoSuchElementException is thrown.
+    *
+-   * @return the last Object in the Vector
++   * @returns The last Object in the Vector
+    * @throws NoSuchElementException the Vector is empty
+    */
+   public synchronized Object lastElement()
+@@ -400,61 +366,95 @@
+     if (elementCount == 0)
+       throw new NoSuchElementException();
+ 
+-    return elementData[elementCount - 1];
++    return elementAt(elementCount - 1);
++  }
++
++  /**
++   * Places <b>obj</b> at <b>index</b> within the Vector.  If <b>index</b>
++   * refers to an index outside the Vector, an ArrayIndexOutOfBoundsException
++   * is thrown.  
++   * 
++   * @param obj The object to store
++   * @param index The position in the Vector to store the object
++   * @throws ArrayIndexOutOfBoundsException the index is out of range
++   */
++  public synchronized void setElementAt(Object obj, int index)
++  {
++    if (index >= elementCount)
++      throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
++
++    elementData[index] = obj;
+   }
+ 
+   /**
+-   * Changes the element at <code>index</code> to be <code>obj</code>
++   * Puts <b>element</b> into the Vector at position <b>index</b> and returns
++   * the Object that previously occupied that position.
+    *
+-   * @param obj the object to store
+-   * @param index the position in the Vector to store the object
++   * @param index The index within the Vector to place the Object
++   * @param element The Object to store in the Vector
++   * @returns The previous object at the specified index
+    * @throws ArrayIndexOutOfBoundsException the index is out of range
+-   * @see #set(int, Object)
++   *
+    */
+-  public void setElementAt(Object obj, int index)
++  public synchronized Object set(int index, Object element)
+   {
+-    set(index, obj);
++    if (index >= elementCount)
++      throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
++
++    Object temp = elementData[index];
++    elementData[index] = element;
++    return temp;
+   }
+ 
+   /**
+-   * Removes the element at <code>index</code>, and shifts all elements at
+-   * positions greater than index to their index - 1.
++   * Removes the element at <b>index</b>, and shifts all elements at
++   * positions greater than index to their index - 1.  
+    *
+-   * @param index the index of the element to remove
+-   * @throws ArrayIndexOutOfBoundsException index &lt; 0 || index &gt;= size();
+-   * @see #remove(int)
++   * @param index The index of the element to remove
+    */
+-  public void removeElementAt(int index)
++  public synchronized void removeElementAt(int index)
+   {
+-    remove(index);
++    if (index >= elementCount)
++      throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
++
++    modCount++;
++    elementCount--;
++    if (index < elementCount)
++      System.arraycopy(elementData, index + 1, elementData, index,
++		       elementCount - index);
++    //Delete the last element (which has been copied back one index)
++    //so it can be garbage collected;
++    elementData[elementCount] = null;
+   }
+ 
+   /**
+-   * Inserts a new element into the Vector at <code>index</code>.  Any elements
++   * Inserts a new element into the Vector at <b>index</b>.  Any elements
+    * at or greater than index are shifted up one position.
+    *
+-   * @param obj the object to insert
+-   * @param index the index at which the object is inserted
+-   * @throws ArrayIndexOutOfBoundsException index &lt; 0 || index &gt; size()
+-   * @see #add(int, Object)
++   * @param obj The object to insert
++   * @param index The index at which the object is inserted
+    */
+-  public synchronized void insertElementAt(Object obj, int index)
++  public void insertElementAt(Object obj, int index)
+   {
+-    checkBoundInclusive(index);
++    if (index > elementCount)
++      throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount);
++
+     if (elementCount == elementData.length)
+       ensureCapacity(elementCount + 1);
+-    modCount++;
++    ++modCount;
++    ++elementCount;
+     System.arraycopy(elementData, index, elementData, index + 1,
+-                     elementCount - index);
+-    elementCount++;
++		     elementCount - 1 - index);
+     elementData[index] = obj;
+   }
+ 
+   /**
+-   * Adds an element to the Vector at the end of the Vector.  The vector
+-   * is increased by ensureCapacity(size() + 1) if needed.
++   * Adds an element to the Vector at the end of the Vector.  If the vector
++   * cannot hold the element with its present capacity, its size is increased
++   * based on the same rules followed if ensureCapacity was called with the
++   * argument currentSize+1.
+    *
+-   * @param obj the object to add to the Vector
++   * @param obj The object to add to the Vector
+    */
+   public synchronized void addElement(Object obj)
+   {
+@@ -465,21 +465,20 @@
+   }
+ 
+   /**
+-   * Removes the first (the lowestindex) occurance of the given object from
+-   * the Vector. If such a remove was performed (the object was found), true
+-   * is returned. If there was no such object, false is returned.
+-   *
+-   * @param obj the object to remove from the Vector
+-   * @return true if the Object was in the Vector, false otherwise
+-   * @see #remove(Object)
++   * Removes the first occurrence of the given object from the Vector.
++   * If such a remove was performed (the object was found), true is returned.
++   * If there was no such object, false is returned.
++   *
++   * @param obj The object to remove from the Vector
++   * @returns true if the Object was in the Vector, false otherwise
+    */
+   public synchronized boolean removeElement(Object obj)
+   {
+-    int idx = indexOf(obj, 0);
+-    if (idx >= 0)
++    int idx = indexOf(obj);
++    if (idx != -1)
+       {
+-        remove(idx);
+-        return true;
++	removeElementAt(idx);
++	return true;
+       }
+     return false;
+   }
+@@ -487,49 +486,46 @@
+   /**
+    * Removes all elements from the Vector.  Note that this does not
+    * resize the internal data array.
+-   *
+-   * @see #clear()
+    */
+   public synchronized void removeAllElements()
+   {
++    modCount++;
+     if (elementCount == 0)
+       return;
+ 
+-    modCount++;
+-    Arrays.fill(elementData, 0, elementCount, null);
++    for (int i = elementCount - 1; i >= 0; --i)
++      {
++	elementData[i] = null;
++      }
+     elementCount = 0;
+   }
+ 
+   /**
+-   * Creates a new Vector with the same contents as this one. The clone is
+-   * shallow; elements are not cloned.
+-   *
+-   * @return the clone of this vector
++   * Creates a new Vector with the same contents as this one.
+    */
+   public synchronized Object clone()
+   {
+     try
+       {
+-        Vector clone = (Vector) super.clone();
+-        clone.elementData = (Object[]) elementData.clone();
+-        return clone;
++	Vector clone = (Vector) super.clone();
++	clone.elementData = (Object[]) elementData.clone();
++	return clone;
+       }
+     catch (CloneNotSupportedException ex)
+       {
+-        // Impossible to get here.
+-        throw new InternalError(ex.toString());
++	throw new InternalError(ex.toString());
+       }
+   }
+ 
+   /**
+    * Returns an Object array with the contents of this Vector, in the order
+-   * they are stored within this Vector.  Note that the Object array returned
+-   * is not the internal data array, and that it holds only the elements
+-   * within the Vector.  This is similar to creating a new Object[] with the
++   * they are stored within this Vector.  Note that the Object array returned 
++   * is not the internal data array, and that it holds only the elements 
++   * within the Vector.  This is similar to creating a new Object[] with the 
+    * size of this Vector, then calling Vector.copyInto(yourArray).
+    *
+-   * @return an Object[] containing the contents of this Vector in order
+-   * @since 1.2
++   * @returns An Object[] containing the contents of this Vector in order
++   *
+    */
+   public synchronized Object[] toArray()
+   {
+@@ -539,97 +535,76 @@
+   }
+ 
+   /**
+-   * Returns an array containing the contents of this Vector.
++   * Returns an array containing the contents of this Vector.  
+    * If the provided array is large enough, the contents are copied
+-   * into that array, and a null is placed in the position size().
++   * into that array, and a null is placed in the position size(). 
+    * In this manner, you can obtain the size of a Vector by the position
+-   * of the null element, if you know the vector does not itself contain
+-   * null entries.  If the array is not large enough, reflection is used
+-   * to create a bigger one of the same runtime type.
++   * of the null element.  If the type of the provided array cannot 
++   * hold the elements, an ArrayStoreException is thrown.
++   * 
++   * If the provided array is not large enough,
++   * a new one is created with the contents of the Vector, and no null 
++   * element.  The new array is of the same runtime type as the provided
++   * array.
++   *
+    *
+-   * @param a an array to copy the Vector into if large enough
+-   * @return an array with the contents of this Vector in order
++   * @param array An array to copy the Vector into if large enough
++   * @returns An array with the contents of this Vector in order
+    * @throws ArrayStoreException the runtime type of the provided array
+-   *         cannot hold the elements of the Vector
+-   * @throws NullPointerException if <code>a</code> is null
+-   * @since 1.2
++   * cannot hold the elements of the Vector
+    */
+-  public synchronized Object[] toArray(Object[] a)
++  public synchronized Object[] toArray(Object[] array)
+   {
+-    if (a.length < elementCount)
+-      a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
+-                                       elementCount);
+-    else if (a.length > elementCount)
+-      a[elementCount] = null;
+-    System.arraycopy(elementData, 0, a, 0, elementCount);
+-    return a;
++    if (array.length < elementCount)
++      array = (Object[]) Array.newInstance(array.getClass().getComponentType(), 
++        				   elementCount);
++    else if (array.length > elementCount)
++      array[elementCount] = null;
++    System.arraycopy(elementData, 0, array, 0, elementCount);
++    return array;
+   }
+ 
+   /**
+-   * Returns the element at position <code>index</code>.
++   * Returns the element at position <b>index</b>
+    *
+    * @param index the position from which an element will be retrieved
+-   * @return the element at that position
+-   * @throws ArrayIndexOutOfBoundsException index &lt; 0 || index &gt;= size()
+-   * @since 1.2
++   * @throws ArrayIndexOutOfBoundsException the index is not within the 
++   * range of the Vector
+    */
+-  public Object get(int index)
++  public synchronized Object get(int index)
+   {
+     return elementAt(index);
+   }
+ 
+   /**
+-   * Puts <code>element</code> into the Vector at position <code>index</code>
+-   * and returns the Object that previously occupied that position.
++   * Removes the given Object from the Vector.  If it exists, true
++   * is returned, if not, false is returned.
+    *
+-   * @param index the index within the Vector to place the Object
+-   * @param element the Object to store in the Vector
+-   * @return the previous object at the specified index
+-   * @throws ArrayIndexOutOfBoundsException index &lt; 0 || index &gt;= size()
+-   * @since 1.2
++   * @param o The object to remove from the Vector
++   * @returns true if the Object existed in the Vector, false otherwise
+    */
+-  public synchronized Object set(int index, Object element)
++  public boolean remove(Object o)
+   {
+-    checkBoundExclusive(index);
+-    Object temp = elementData[index];
+-    elementData[index] = element;
+-    return temp;
++    return removeElement(o);
+   }
+ 
+   /**
+    * Adds an object to the Vector.
+    *
+-   * @param o the element to add to the Vector
+-   * @return true, as specified by List
+-   * @since 1.2
++   * @param o The element to add to the Vector
+    */
+-  public boolean add(Object o)
++  public synchronized boolean add(Object o)
+   {
+     addElement(o);
+     return true;
+   }
+ 
+   /**
+-   * Removes the given Object from the Vector.  If it exists, true
+-   * is returned, if not, false is returned.
+-   *
+-   * @param o the object to remove from the Vector
+-   * @return true if the Object existed in the Vector, false otherwise
+-   * @since 1.2
+-   */
+-  public boolean remove(Object o)
+-  {
+-    return removeElement(o);
+-  }
+-
+-  /**
+    * Adds an object at the specified index.  Elements at or above
+    * index are shifted up one position.
+    *
+-   * @param index the index at which to add the element
+-   * @param element the element to add to the Vector
+-   * @throws ArrayIndexOutOfBoundsException index &lt; 0 || index &gt; size()
+-   * @since 1.2
++   * @param index The index at which to add the element
++   * @param element The element to add to the Vector
+    */
+   public void add(int index, Object element)
+   {
+@@ -639,253 +614,153 @@
+   /**
+    * Removes the element at the specified index, and returns it.
+    *
+-   * @param index the position from which to remove the element
+-   * @return the object removed
+-   * @throws ArrayIndexOutOfBoundsException index &lt; 0 || index &gt;= size()
+-   * @since 1.2
++   * @param index The position from which to remove the element
++   * @returns The object removed
++   * @throws ArrayIndexOutOfBoundsException the index was out of the range
++   * of the Vector
+    */
+   public synchronized Object remove(int index)
+   {
+-    checkBoundExclusive(index);
++    if (index >= elementCount)
++      throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
++  
+     Object temp = elementData[index];
+-    modCount++;
+-    elementCount--;
+-    if (index < elementCount)
+-      System.arraycopy(elementData, index + 1, elementData, index,
+-                       elementCount - index);
+-    elementData[elementCount] = null;
++    removeElementAt(index);
+     return temp;
+   }
+ 
+   /**
+-   * Clears all elements in the Vector and sets its size to 0.
++   * Clears all elements in the Vector and sets its size to 0
+    */
+   public void clear()
+   {
+     removeAllElements();
+   }
+ 
+-  /**
+-   * Returns true if this Vector contains all the elements in c.
+-   *
+-   * @param c the collection to compare to
+-   * @return true if this vector contains all elements of c
+-   * @throws NullPointerException if c is null
+-   * @since 1.2
+-   */
+   public synchronized boolean containsAll(Collection c)
+   {
+-    // Here just for the sychronization.
+-    return super.containsAll(c);
++    Iterator itr = c.iterator();
++    int size = c.size();
++    for (int pos = 0; pos < size; pos++)
++      {
++	if (!contains(itr.next()))
++	  return false;
++      }
++    return true;
+   }
+ 
+-  /**
+-   * Appends all elements of the given collection to the end of this Vector.
+-   * Behavior is undefined if the collection is modified during this operation
+-   * (for example, if this == c).
+-   *
+-   * @param c the collection to append
+-   * @return true if this vector changed, in other words c was not empty
+-   * @throws NullPointerException if c is null
+-   * @since 1.2
+-   */
+   public synchronized boolean addAll(Collection c)
+   {
+     return addAll(elementCount, c);
+   }
+-
+-  /**
+-   * Remove from this vector all elements contained in the given collection.
+-   *
+-   * @param c the collection to filter out
+-   * @return true if this vector changed
+-   * @throws NullPointerException if c is null
+-   * @since 1.2
+-   */
++  
+   public synchronized boolean removeAll(Collection c)
+   {
+-    int i;
+-    int j;
+-    for (i = 0; i < elementCount; i++)
+-      if (c.contains(elementData[i]))
+-        break;
+-    if (i == elementCount)
+-      return false;
+-
+-    modCount++;
+-    for (j = i++; i < elementCount; i++)
+-      if (! c.contains(elementData[i]))
+-        elementData[j++] = elementData[i];
+-    elementCount -= i - j;
+-    return true;
++    return super.removeAll(c);
+   }
+-
+-  /**
+-   * Retain in this vector only the elements contained in the given collection.
+-   *
+-   * @param c the collection to filter by
+-   * @return true if this vector changed
+-   * @throws NullPointerException if c is null
+-   * @since 1.2
+-   */
++  
+   public synchronized boolean retainAll(Collection c)
+   {
+-    int i;
+-    int j;
+-    for (i = 0; i < elementCount; i++)
+-      if (! c.contains(elementData[i]))
+-        break;
+-    if (i == elementCount)
+-      return false;
+-
+-    modCount++;
+-    for (j = i++; i < elementCount; i++)
+-      if (c.contains(elementData[i]))
+-        elementData[j++] = elementData[i];
+-    elementCount -= i - j;
+-    return true;
++    return super.retainAll(c);
+   }
+ 
+-  /**
+-   * Inserts all elements of the given collection at the given index of
+-   * this Vector. Behavior is undefined if the collection is modified during
+-   * this operation (for example, if this == c).
+-   *
+-   * @param c the collection to append
+-   * @return true if this vector changed, in other words c was not empty
+-   * @throws NullPointerException if c is null
+-   * @throws ArrayIndexOutOfBoundsException index &lt; 0 || index &gt; size()
+-   * @since 1.2
+-   */
+   public synchronized boolean addAll(int index, Collection c)
+   {
+-    checkBoundInclusive(index);
++    if (index < 0 || index > elementCount)
++      throw new ArrayIndexOutOfBoundsException(index);
++    modCount++;
+     Iterator itr = c.iterator();
+     int csize = c.size();
+ 
+-    modCount++;
+     ensureCapacity(elementCount + csize);
+     int end = index + csize;
+     if (elementCount > 0 && index != elementCount)
+       System.arraycopy(elementData, index, elementData, end, csize);
+     elementCount += csize;
+-    for ( ; index < end; index++)
+-      elementData[index] = itr.next();
+-    return (csize > 0);
++    for (; index < end; index++)
++      {
++        elementData[index] = itr.next();
++      }
++    return (csize > 0);  
+   }
+ 
+-  /**
+-   * Compares this to the given object.
+-   *
+-   * @param o the object to compare to
+-   * @return true if the two are equal
+-   * @since 1.2
+-   */
+-  public synchronized boolean equals(Object o)
++  public synchronized boolean equals(Object c)
+   {
+-    // Here just for the sychronization.
+-    return super.equals(o);
++    return super.equals(c);
+   }
+ 
+-  /**
+-   * Computes the hashcode of this object.
+-   *
+-   * @return the hashcode
+-   * @since 1.2
+-   */
+   public synchronized int hashCode()
+   {
+-    // Here just for the sychronization.
+     return super.hashCode();
+   }
+ 
+   /**
+-   * Returns a string representation of this Vector in the form
+-   * "[element0, element1, ... elementN]".
++   * Returns a string representation of this Vector in the form 
++   * [element0, element1, ... elementN]
+    *
+-   * @return the String representation of this Vector
++   * @returns the String representation of this Vector
+    */
+   public synchronized String toString()
+   {
+-    // Here just for the sychronization.
+-    return super.toString();
+-  }
+-
+-  /**
+-   * Obtain a List view of a subsection of this list, from fromIndex
+-   * (inclusive) to toIndex (exclusive). If the two indices are equal, the
+-   * sublist is empty. The returned list is modifiable, and changes in one
+-   * reflect in the other. If this list is structurally modified in
+-   * any way other than through the returned list, the result of any subsequent
+-   * operations on the returned list is undefined.
+-   * <p>
+-   *
+-   * @param fromIndex the index that the returned list should start from
+-   *        (inclusive)
+-   * @param toIndex the index that the returned list should go to (exclusive)
+-   * @return a List backed by a subsection of this vector
+-   * @throws IndexOutOfBoundsException if fromIndex &lt; 0
+-   *         || toIndex &gt; size()
+-   * @throws IllegalArgumentException if fromIndex &gt; toIndex
+-   * @see ConcurrentModificationException
+-   * @since 1.2
+-   */
+-  public synchronized List subList(int fromIndex, int toIndex)
+-  {
+-    List sub = super.subList(fromIndex, toIndex);
+-    // We must specify the correct object to synchronize upon, hence the
+-    // use of a non-public API
+-    return new Collections.SynchronizedList(this, sub);
++    String r = "[";
++    for (int i = 0; i < elementCount; i++)
++      {
++	r += elementData[i];
++	if (i < elementCount - 1)
++	  r += ", ";
++      }
++    r += "]";
++    return r;
+   }
+ 
+   /**
+-   * Removes a range of elements from this list.
++   * Returns an Enumeration of the elements of this List.
++   * The Enumeration returned is compatible behavior-wise with
++   * the 1.1 elements() method, in that it does not check for
++   * concurrent modification.
+    *
+-   * @param fromIndex the index to start deleting from (inclusive)
+-   * @param toIndex the index to delete up to (exclusive)
++   * @returns an Enumeration
+    */
+-  // This does not need to be synchronized, because it is only called through
+-  // clear() of a sublist, and clear() had already synchronized.
+-  protected void removeRange(int fromIndex, int toIndex)
++  public synchronized Enumeration elements()
+   {
+-    if (fromIndex != toIndex)
++    return new Enumeration()
++    {
++      int i = 0;
++      public boolean hasMoreElements()
++      {
++	return (i < elementCount);
++      }
++      public Object nextElement()
+       {
+-        modCount++;
+-        System.arraycopy(elementData, toIndex, elementData, fromIndex,
+-                         elementCount - toIndex);
+-        int save = elementCount;
+-        elementCount -= toIndex - fromIndex;
+-        Arrays.fill(elementData, elementCount, save, null);
++	if (i >= elementCount)
++	  throw new NoSuchElementException();
++	return (elementAt(i++));
+       }
++    };
+   }
+-
+-  /**
+-   * Checks that the index is in the range of possible elements (inclusive).
+-   *
+-   * @param index the index to check
+-   * @throws ArrayIndexOutOfBoundsException if index &gt; size
+-   */
+-  private void checkBoundInclusive(int index)
++  
++  public List subList(int fromIndex, int toIndex)
+   {
+-    // Implementation note: we do not check for negative ranges here, since
+-    // use of a negative index will cause an ArrayIndexOutOfBoundsException
+-    // with no effort on our part.
+-    if (index > elementCount)
+-      throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount);
++    List sub = super.subList(fromIndex, toIndex);
++    return Collections.synchronizedList(sub);
+   }
+-
+-  /**
+-   * Checks that the index is in the range of existing elements (exclusive).
+-   *
+-   * @param index the index to check
+-   * @throws ArrayIndexOutOfBoundsException if index &gt;= size
+-   */
+-  private void checkBoundExclusive(int index)
++  
++  /** @specnote This is not specified as synchronized in the JCL, but it seems
++    * to me that is should be. If it isn't, a clear() operation on a sublist
++    * will not be synchronized w.r.t. the Vector object.
++    */
++  protected synchronized void removeRange(int fromIndex, int toIndex)
+   {
+-    // Implementation note: we do not check for negative ranges here, since
+-    // use of a negative index will cause an ArrayIndexOutOfBoundsException
+-    // with no effort on our part.
+-    if (index >= elementCount)
+-      throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
++    modCount++;
++    if (fromIndex != toIndex)
++      {
++	System.arraycopy(elementData, toIndex, elementData, fromIndex, 
++	                 elementCount - toIndex);
++	// Clear unused elements so objects can be collected.
++	int save = elementCount;
++	elementCount -= (toIndex - fromIndex);
++	for (int i = elementCount; i < save; ++i)
++	  elementData[i] = null;
++      }
+   }
+ }
Index: compare/java.util.WeakHashMap.diff
===================================================================
RCS file: java.util.WeakHashMap.diff
diff -N java.util.WeakHashMap.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.WeakHashMap.diff Tue Nov 6 17:21:38 2001
@@ -0,0 +1,1036 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/WeakHashMap.java	Fri Nov  2 09:28:56 2001
++++ java/util/WeakHashMap.java	Fri Nov  2 21:44:52 2001
+@@ -1,6 +1,5 @@
+-/* java.util.WeakHashMap -- a hashtable that keeps only weak references
+-   to its keys, allowing the virtual machine to reclaim them
+-   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
++/* java.util.WeakHashMap
++   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+@@ -27,7 +26,6 @@
+ 
+ 
+ package java.util;
+-
+ import java.lang.ref.WeakReference;
+ import java.lang.ref.ReferenceQueue;
+ 
+@@ -52,80 +50,53 @@
+  * has similar phenomenons: The size may spontaneously shrink, or an
+  * entry, that was in the set before, suddenly disappears. <br>
+  *
+- * A weak hash map is not meant for caches; use a normal map, with
+- * soft references as values instead, or try {@link LinkedHashMap}.  <br>
++ * A weak hash map is not meant for caches; use a normal map, with 
++ * soft references as values instead.  <br>
+  *
+- * The weak hash map supports null values and null keys.  The null key
+- * is never deleted from the map (except explictly of course).
++ * The weak hash map supports null values and null keys.  Null keys
++ * are never deleted from the map (except explictly of course). 
+  * The performance of the methods are similar to that of a hash map. <br>
+  *
+- * The value objects are strongly referenced by this table.  So if a
++ * The value object are strongly referenced by this table.  So if a
+  * value object maintains a strong reference to the key (either direct
+  * or indirect) the key will never be removed from this map.  According
+- * to Sun, this problem may be fixed in a future release.  It is not
++ * to Sun, this problem may be fixed in a future release.  It is not 
+  * possible to do it with the jdk 1.2 reference model, though.
+  *
+- * @author Jochen Hoenicke
+- * @author Eric Blake <ebb9@email.byu.edu>
++ * @since jdk1.2
++ * @author Jochen Hoenicke 
+  * @see HashMap
+- * @see WeakReference
+- * @see LinkedHashMap
+- * @since 1.2
+- * @status updated to 1.4
+- */
++ * @see WeakReference */
+ public class WeakHashMap extends AbstractMap implements Map
+ {
+-  /**
+-   * The default capacity for an instance of HashMap.
++  /** 
++   * The default capacity for an instance of HashMap.  
+    * Sun's documentation mildly suggests that this (11) is the correct
+-   * value.
++   * value.  
+    */
+   private static final int DEFAULT_CAPACITY = 11;
+ 
+-  /**
+-   * The default load factor of a HashMap.
++  /** 
++   * The default load factor of a HashMap 
+    */
+   private static final float DEFAULT_LOAD_FACTOR = 0.75F;
+ 
+   /**
+    * This is used instead of the key value <i>null</i>.  It is needed
+-   * to distinguish between an null key and a removed key.
++   * to distinguish between an null key and a removed key.  
+    */
+-  // Package visible for use by nested classes.
+-  static final Object NULL_KEY = new Object()
+-  {
+-    /**
+-     * Sets the hashCode to 0, since that's what null would map to.
+-     * @return the hash code 0
+-     */
+-    public int hashCode()
+-    {
+-      return 0;
+-    }
+-
+-    /**
+-     * Compares this key to the given object. Normally, an object should
+-     * NEVER compare equal to null, but since we don't publicize NULL_VALUE,
+-     * it saves bytecode to do so here.
+-     * @return true iff o is this or null
+-     */
+-    public boolean equals(Object o)
+-    {
+-      return null == o || this == o;
+-    }
+-  };
++  private static final Object NULL_KEY = new Object();
+ 
+   /**
+    * The reference queue where our buckets (which are WeakReferences) are
+    * registered to.
+    */
+-  private final ReferenceQueue queue;
++  private ReferenceQueue queue;
+ 
+   /**
+    * The number of entries in this hash map.
+    */
+-  // Package visible for use by nested classes.
+-  int size;
++  private int size;
+ 
+   /**
+    * The load factor of this WeakHashMap.  This is the maximum ratio of
+@@ -137,7 +108,7 @@
+   /**
+    * The rounded product of the capacity (i.e. number of buckets) and
+    * the load factor. When the number of elements exceeds the
+-   * threshold, the HashMap calls <pre>rehash()</pre>.
++   * threshold, the HashMap calls <pre>rehash()</pre>.  
+    */
+   private int threshold;
+ 
+@@ -148,20 +119,17 @@
+    * by the garbage collection.  Instead the iterators must make
+    * sure to have strong references to the entries they rely on.
+    */
+-  // Package visible for use by nested classes.
+-  int modCount;
++  private int modCount;
+ 
+-  /**
++  /** 
+    * The entry set.  There is only one instance per hashmap, namely
+    * theEntrySet.  Note that the entry set may silently shrink, just
+    * like the WeakHashMap.
+    */
+-  private final class WeakEntrySet extends AbstractSet
++  private class WeakEntrySet extends AbstractSet
+   {
+     /**
+-     * Returns the size of this set.
+-     *
+-     * @return the set size
++     * Returns the size of this set. 
+      */
+     public int size()
+     {
+@@ -170,150 +138,151 @@
+ 
+     /**
+      * Returns an iterator for all entries.
+-     *
+-     * @return an Entry iterator
+      */
+     public Iterator iterator()
+     {
+       return new Iterator()
+       {
+-        /**
+-         * The entry that was returned by the last
+-         * <code>next()</code> call.  This is also the entry whose
+-         * bucket should be removed by the <code>remove</code> call. <br>
+-         *
+-         * It is null, if the <code>next</code> method wasn't
+-         * called yet, or if the entry was already removed.  <br>
+-         *
+-         * Remembering this entry here will also prevent it from
+-         * being removed under us, since the entry strongly refers
+-         * to the key.
+-         */
+-        WeakBucket.WeakEntry lastEntry;
+-
+-        /**
+-         * The entry that will be returned by the next
+-         * <code>next()</code> call.  It is <code>null</code> if there
+-         * is no further entry. <br>
+-         *
+-         * Remembering this entry here will also prevent it from
+-         * being removed under us, since the entry strongly refers
+-         * to the key.
+-         */
+-        WeakBucket.WeakEntry nextEntry = findNext(null);
+-
+-        /**
+-         * The known number of modification to the list, if it differs
+-         * from the real number, we throw an exception.
+-         */
+-        int knownMod = modCount;
+-
+-        /**
+-         * Check the known number of modification to the number of
+-         * modifications of the table.  If it differs from the real
+-         * number, we throw an exception.
+-         * @throws ConcurrentModificationException if the number
+-         *         of modifications doesn't match.
+-         */
+-        private void checkMod()
+-        {
+-          // This method will get inlined.
+-          cleanQueue();
+-          if (knownMod != modCount)
+-            throw new ConcurrentModificationException();
+-        }
+-
+-        /**
+-         * Get a strong reference to the next entry after
+-         * lastBucket.
+-         * @param lastEntry the previous bucket, or null if we should
+-         * get the first entry.
+-         * @return the next entry.
+-         */
+-        private WeakBucket.WeakEntry findNext(WeakBucket.WeakEntry lastEntry)
+-        {
+-          int slot;
+-          WeakBucket nextBucket;
+-          if (lastEntry != null)
+-            {
+-              nextBucket = lastEntry.getBucket().next;
+-              slot = lastEntry.getBucket().slot;
+-            }
+-          else
+-            {
+-              nextBucket = buckets[0];
+-              slot = 0;
+-            }
+-
+-          while (true)
+-            {
+-              while (nextBucket != null)
+-                {
+-                  WeakBucket.WeakEntry entry = nextBucket.getEntry();
+-                  if (entry != null)
+-                    // This is the next entry.
+-                    return entry;
+-
+-                  // Entry was cleared, try next.
+-                  nextBucket = nextBucket.next;
+-                }
+-
+-              slot++;
+-              if (slot == buckets.length)
+-                // No more buckets, we are through.
+-                return null;
+-
+-              nextBucket = buckets[slot];
+-            }
+-        }
+-
+-        /**
+-         * Checks if there are more entries.
+-         * @return true, iff there are more elements.
+-         * @throws ConcurrentModificationException if the hash map was
+-         *         modified.
+-         */
+-        public boolean hasNext()
+-        {
+-          checkMod();
+-          return nextEntry != null;
+-        }
+-
+-        /**
+-         * Returns the next entry.
+-         * @return the next entry.
+-         * @throws ConcurrentModificationException if the hash map was
+-         *         modified.
+-         * @throws NoSuchElementException if there is no entry.
+-         */
+-        public Object next()
+-        {
+-          checkMod();
+-          if (nextEntry == null)
+-            throw new NoSuchElementException();
+-          lastEntry = nextEntry;
+-          nextEntry = findNext(lastEntry);
+-          return lastEntry;
+-        }
+-
+-        /**
+-         * Removes the last returned entry from this set.  This will
+-         * also remove the bucket of the underlying weak hash map.
+-         * @throws ConcurrentModificationException if the hash map was
+-         *         modified.
+-         * @throws IllegalStateException if <code>next()</code> was
+-         *         never called or the element was already removed.
+-         */
+-        public void remove()
+-        {
+-          checkMod();
+-          if (lastEntry == null)
+-            throw new IllegalStateException();
+-          modCount++;
+-          internalRemove(lastEntry.getBucket());
+-          lastEntry = null;
+-          knownMod++;
+-        }
++	/** 
++	 * The entry that was returned by the last
++	 * <code>next()</code> call.  This is also the entry whose
++	 * bucket should be removed by the <code>remove</code> call. <br>
++	 *
++	 * It is null, if the <code>next</code> method wasn't 
++	 * called yet, or if the entry was already removed.  <br>
++	 *
++	 * Remembering this entry here will also prevent it from
++	 * being removed under us, since the entry strongly refers
++	 * to the key.
++	 */
++	WeakBucket.Entry lastEntry;
++
++	/** 
++	 * The entry that will be returned by the next
++	 * <code>next()</code> call.  It is <code>null</code> if there
++	 * is no further entry. <br>
++	 *
++	 * Remembering this entry here will also prevent it from
++	 * being removed under us, since the entry strongly refers
++	 * to the key.
++	 */
++	WeakBucket.Entry nextEntry = findNext(null);
++
++	/**
++	 * The known number of modification to the list, if it differs
++	 * from the real number, we through an exception.
++	 */
++	int knownMod = modCount;
++
++	/** 
++	 * Check the known number of modification to the number of
++	 * modifications of the table.  If it differs from the real
++	 * number, we throw an exception.
++	 * @exception ConcurrentModificationException if the number
++	 * of modifications doesn't match.
++	 */
++	private void checkMod()
++	{
++	  /* This method will get inlined */
++	  if (knownMod != modCount)
++	    throw new ConcurrentModificationException();
++	}
++
++	/**
++	 * Get a strong reference to the next entry after
++	 * lastBucket.
++	 * @param lastBucket the previous bucket, or null if we should
++	 * get the first entry.
++	 * @return the next entry.
++	 */
++	private WeakBucket.Entry findNext(WeakBucket.Entry lastEntry)
++	{
++	  int slot;
++	  WeakBucket nextBucket;
++	  if (lastEntry != null)
++	    {
++	      nextBucket = lastEntry.getBucket().next;
++	      slot = lastEntry.getBucket().slot;
++	    }
++	  else
++	    {
++	      nextBucket = buckets[0];
++	      slot = 0;
++	    }
++
++	  while (true)
++	    {
++	      while (nextBucket != null)
++		{
++		  WeakBucket.Entry entry = nextBucket.getEntry();
++		  if (entry != null)
++		    /* This is the next entry */
++		    return entry;
++
++		  /* entry was cleared, try next */
++		  nextBucket = nextBucket.next;
++		}
++
++	      slot++;
++	      if (slot == buckets.length)
++		/* No more buckets, we are through */
++		return null;
++
++	      nextBucket = buckets[slot];
++	    }
++	}
++
++
++	/**
++	 * Checks if there are more entries.
++	 * @return true, iff there are more elements.
++	 * @exception IllegalModificationException if the hash map was
++	 * modified.
++	 */
++	public boolean hasNext()
++	{
++	  cleanQueue();
++	  checkMod();
++	  return (nextEntry != null);
++	}
++
++	/**
++	 * Returns the next entry.
++	 * @return the next entry.
++	 * @exception IllegalModificationException if the hash map was
++	 * modified.
++	 * @exception NoSuchElementException if there is no entry.
++	 */
++	public Object next()
++	{
++	  cleanQueue();
++	  checkMod();
++	  if (nextEntry == null)
++	    throw new NoSuchElementException();
++	  lastEntry = nextEntry;
++	  nextEntry = findNext(lastEntry);
++	  return lastEntry;
++	}
++
++	/**
++	 * Removes the last returned entry from this set.  This will
++	 * also remove the bucket of the underlying weak hash map.
++	 * @exception IllegalModificationException if the hash map was
++	 * modified.
++	 * @exception IllegalStateException if <code>next()</code> was
++	 * never called or the element was already removed. 
++	 */
++	public void remove()
++	{
++	  cleanQueue();
++	  checkMod();
++	  if (lastEntry == null)
++	    throw new IllegalStateException();
++	  internalRemove(lastEntry.getBucket());
++	  lastEntry = null;
++	  modCount++;
++	  knownMod = modCount;
++	}
+       };
+     }
+   }
+@@ -324,28 +293,28 @@
+    * number. <br>
+    *
+    * It would be cleaner to have a WeakReference as field, instead of
+-   * extending it, but if a weak reference gets cleared, we only get
++   * extending it, but if a weak reference get cleared, we only get
+    * the weak reference (by queue.poll) and wouldn't know where to
+    * look for this reference in the hashtable, to remove that entry.
+    *
+-   * @author Jochen Hoenicke
++   * @author Jochen Hoenicke 
+    */
+   private static class WeakBucket extends WeakReference
+   {
+     /**
+      * The value of this entry.  The key is stored in the weak
+-     * reference that we extend.
++     * reference that we extend.  
+      */
+     Object value;
+ 
+     /**
+      * The next bucket describing another entry that uses the same
+-     * slot.
++     * slot.  
+      */
+     WeakBucket next;
+ 
+     /**
+-     * The slot of this entry. This should be
++     * The slot of this entry. This should be 
+      * <pre>
+      *  Math.abs(key.hashCode() % buckets.length)
+      * </pre>
+@@ -360,13 +329,12 @@
+      * Creates a new bucket for the given key/value pair and the specified
+      * slot.
+      * @param key the key
+-     * @param queue the queue the weak reference belongs to
+      * @param value the value
+      * @param slot the slot.  This must match the slot where this bucket
+-     *        will be enqueued.
++     * will be enqueued.
+      */
+     public WeakBucket(Object key, ReferenceQueue queue, Object value,
+-                      int slot)
++		      int slot)
+     {
+       super(key, queue);
+       this.value = value;
+@@ -374,11 +342,11 @@
+     }
+ 
+     /**
+-     * This class gives the <code>Entry</code> representation of the
++     * This class gives the <code>Entry</code> representation of the 
+      * current bucket.  It also keeps a strong reference to the
+      * key; bad things may happen otherwise.
+      */
+-    class WeakEntry implements Map.Entry
++    class Entry implements Map.Entry
+     {
+       /**
+        * The strong ref to the key.
+@@ -387,105 +355,93 @@
+ 
+       /**
+        * Creates a new entry for the key.
+-       * @param key the key
+        */
+-      public WeakEntry(Object key)
++      public Entry(Object key)
+       {
+-        this.key = key;
++	this.key = key;
+       }
+ 
+       /**
+        * Returns the underlying bucket.
+-       * @return the owning bucket
+        */
+       public WeakBucket getBucket()
+       {
+-        return WeakBucket.this;
++	return WeakBucket.this;
+       }
+ 
+       /**
+        * Returns the key.
+-       * @return the key
+        */
+       public Object getKey()
+       {
+-        return key == NULL_KEY ? null : key;
++	return key == NULL_KEY ? null : key;
+       }
+ 
+       /**
+        * Returns the value.
+-       * @return the value
+        */
+       public Object getValue()
+       {
+-        return value;
++	return value;
+       }
+ 
+       /**
+-       * This changes the value.  This change takes place in
++       * This changes the value.  This change takes place in 
+        * the underlying hash map.
+-       * @param newVal the new value
+-       * @return the old value
+        */
+       public Object setValue(Object newVal)
+       {
+-        Object oldVal = value;
+-        value = newVal;
+-        return oldVal;
++	Object oldVal = value;
++	value = newVal;
++	return oldVal;
+       }
+ 
+       /**
+        * The hashCode as specified in the Entry interface.
+-       * @return the hash code
+        */
+       public int hashCode()
+       {
+-        return key.hashCode() ^ WeakHashMap.hashCode(value);
++	return (key == NULL_KEY ? 0 : key.hashCode())
++	  ^ (value == null ? 0 : value.hashCode());
+       }
+ 
+       /**
+        * The equals method as specified in the Entry interface.
+-       * @param o the object to compare to
+-       * @return true iff o represents the same key/value pair
+        */
+       public boolean equals(Object o)
+       {
+-        if (o instanceof Map.Entry)
+-          {
+-            Map.Entry e = (Map.Entry) o;
+-            return key.equals(e.getKey())
+-              && WeakHashMap.equals(value, e.getValue());
+-          }
+-        return false;
+-      }
+-
+-      public String toString()
+-      {
+-        return key + "=" + value;
++	if (o instanceof Map.Entry)
++	  {
++	    Map.Entry e = (Map.Entry) o;
++	    return (key == NULL_KEY
++		    ? e.getKey() == null : key.equals(e.getKey()))
++	      && (value == null
++		  ? e.getValue() == null : value.equals(e.getValue()));
++	  }
++	return false;
+       }
+     }
+ 
+     /**
+      * This returns the entry stored in this bucket, or null, if the
+      * bucket got cleared in the mean time.
+-     * @return the Entry for this bucket, if it exists
+      */
+-    WeakEntry getEntry()
++    Entry getEntry()
+     {
+-      final Object key = get();
++      final Object key = this.get();
+       if (key == null)
+-        return null;
+-      return new WeakEntry(key);
++	return null;
++      return new Entry(key);
+     }
+   }
+ 
+   /**
+    * The entry set returned by <code>entrySet()</code>.
+    */
+-  private final WeakEntrySet theEntrySet;
++  private WeakEntrySet theEntrySet;
+ 
+   /**
+-   * The hash buckets.  These are linked lists.
++   * The hash buckets.  This are linked lists.
+    */
+   private WeakBucket[] buckets;
+ 
+@@ -501,8 +457,7 @@
+   /**
+    * Creates a new weak hash map with default load factor and the given
+    * capacity.
+-   * @param initialCapacity the initial capacity
+-   * @throws IllegalArgumentException if initialCapacity is negative
++   * @param initialCapacity the initial capacity 
+    */
+   public WeakHashMap(int initialCapacity)
+   {
+@@ -511,16 +466,13 @@
+ 
+   /**
+    * Creates a new weak hash map with the given initial capacity and
+-   * load factor.
++   * load factor.  
+    * @param initialCapacity the initial capacity.
+    * @param loadFactor the load factor (see class description of HashMap).
+-   * @throws IllegalArgumentException if initialCapacity is negative, or
+-   *         loadFactor is non-positive
+    */
+   public WeakHashMap(int initialCapacity, float loadFactor)
+   {
+-    // Check loadFactor for NaN as well.
+-    if (initialCapacity < 0 || ! (loadFactor > 0))
++    if (initialCapacity < 0 || loadFactor <= 0 || loadFactor > 1)
+       throw new IllegalArgumentException();
+     this.loadFactor = loadFactor;
+     threshold = (int) (initialCapacity * loadFactor);
+@@ -529,24 +481,8 @@
+     buckets = new WeakBucket[initialCapacity];
+   }
+ 
+-  /**
+-   * Construct a new WeakHashMap with the same mappings as the given map.
+-   * The WeakHashMap has a default load factor of 0.75.
+-   *
+-   * @param m the map to copy
+-   * @throws NullPointerException if m is null
+-   * @since 1.3
+-   */
+-  public WeakHashMap(Map m)
+-  {
+-    this(m.size(), DEFAULT_LOAD_FACTOR);
+-    putAll(m);
+-  }
+-
+-  /**
+-   * Simply hashes a non-null Object to its array index.
+-   * @param key the key to hash
+-   * @return its slot number
++  /** 
++   * simply hashes a non-null Object to its array index 
+    */
+   private int hash(Object key)
+   {
+@@ -562,68 +498,68 @@
+    * Currently the iterator maintains a strong reference to the key, so
+    * that is no problem.
+    */
+-  // Package visible for use by nested classes.
+-  void cleanQueue()
++  private void cleanQueue()
+   {
+     Object bucket = queue.poll();
+     while (bucket != null)
+       {
+-        internalRemove((WeakBucket) bucket);
+-        bucket = queue.poll();
++	internalRemove((WeakBucket) bucket);
++	bucket = queue.poll();
+       }
+   }
+ 
+   /**
+    * Rehashes this hashtable.  This will be called by the
+-   * <code>add()</code> method if the size grows beyond the threshold.
++   * <code>add()</code> method if the size grows beyond the threshold.  
+    * It will grow the bucket size at least by factor two and allocates
+    * new buckets.
+    */
+   private void rehash()
+   {
+     WeakBucket[] oldBuckets = buckets;
+-    int newsize = buckets.length * 2 + 1; // XXX should be prime.
++    int newsize = buckets.length * 2 + 1;	// XXX should be prime.
+     threshold = (int) (newsize * loadFactor);
+     buckets = new WeakBucket[newsize];
+ 
+-    // Now we have to insert the buckets again.
++    /* Now we have to insert the buckets again.
++     */
+     for (int i = 0; i < oldBuckets.length; i++)
+       {
+-        WeakBucket bucket = oldBuckets[i];
+-        WeakBucket nextBucket;
+-        while (bucket != null)
+-          {
+-            nextBucket = bucket.next;
+-
+-            Object key = bucket.get();
+-            if (key == null)
+-              {
+-                // This bucket should be removed; it is probably
+-                // already on the reference queue.  We don't insert it
+-                // at all, and mark it as cleared.
+-                bucket.slot = -1;
+-                size--;
+-              }
+-            else
+-              {
+-                // Add this bucket to its new slot.
+-                int slot = hash(key);
+-                bucket.slot = slot;
+-                bucket.next = buckets[slot];
+-                buckets[slot] = bucket;
+-              }
+-            bucket = nextBucket;
+-          }
++	WeakBucket bucket = oldBuckets[i];
++	WeakBucket nextBucket;
++	while (bucket != null)
++	  {
++	    nextBucket = bucket.next;
++
++	    Object key = bucket.get();
++	    if (key == null)
++	      {
++		/* This bucket should be removed; it is probably
++		 * already on the reference queue.  We don't insert it
++		 * at all, and mark it as cleared.  */
++		bucket.slot = -1;
++		size--;
++	      }
++	    else
++	      {
++		/* add this bucket to its new slot */
++		int slot = hash(key);
++		bucket.slot = slot;
++		bucket.next = buckets[slot];
++		buckets[slot] = bucket;
++	      }
++	    bucket = nextBucket;
++	  }
+       }
+   }
+ 
+   /**
+    * Finds the entry corresponding to key.  Since it returns an Entry
+    * it will also prevent the key from being removed under us.
+-   * @param key the key, may be null
+-   * @return The WeakBucket.WeakEntry or null, if the key wasn't found.
++   * @param key the key. It may be null.
++   * @return The WeakBucket.Entry or null, if the key wasn't found.
+    */
+-  private WeakBucket.WeakEntry internalGet(Object key)
++  private WeakBucket.Entry internalGet(Object key)
+   {
+     if (key == null)
+       key = NULL_KEY;
+@@ -631,11 +567,11 @@
+     WeakBucket bucket = buckets[slot];
+     while (bucket != null)
+       {
+-        WeakBucket.WeakEntry entry = bucket.getEntry();
+-        if (entry != null && key.equals(entry.key))
+-          return entry;
++	WeakBucket.Entry entry = bucket.getEntry();
++	if (entry != null && key.equals(entry.key))
++	  return entry;
+ 
+-        bucket = bucket.next;
++	bucket = bucket.next;
+       }
+     return null;
+   }
+@@ -659,40 +595,41 @@
+   /**
+    * Removes a bucket from this hash map, if it wasn't removed before
+    * (e.g. one time through rehashing and one time through reference queue)
+-   * @param bucket the bucket to remove.
++   * @param bucket the bucket to remove.  
+    */
+   private void internalRemove(WeakBucket bucket)
+   {
+     int slot = bucket.slot;
+     if (slot == -1)
+-      // This bucket was already removed.
++      /* this bucket was already removed. */
+       return;
+ 
+-    // Mark the bucket as removed.  This is necessary, since the
+-    // bucket may be enqueued later by the garbage collection, and
+-    // internalRemove will be called a second time.
++    /* mark the bucket as removed.  This is necessary, since the
++     * bucket may be enqueued later by the garbage collection and
++     * internalRemove, will be called a second time.  
++     */
+     bucket.slot = -1;
+     if (buckets[slot] == bucket)
+       buckets[slot] = bucket.next;
+     else
+       {
+-        WeakBucket prev = buckets[slot];
+-        /* This may throw a NullPointerException.  It shouldn't but if
+-         * a race condition occurred (two threads removing the same
+-         * bucket at the same time) it may happen.  <br>
+-         * But with race condition many much worse things may happen
+-         * anyway.
+-         */
+-        while (prev.next != bucket)
+-          prev = prev.next;
+-        prev.next = bucket.next;
++	WeakBucket prev = buckets[slot];
++	/* This may throw a NullPointerException.  It shouldn't but if
++	 * a race condition occurred (two threads removing the same
++	 * bucket at the same time) it may happen.  <br>
++	 * But with race condition many much worse things may happen
++	 * anyway.
++	 */
++	while (prev.next != bucket)
++	  prev = prev.next;
++	prev.next = bucket.next;
+       }
+     size--;
+   }
+ 
+   /**
+    * Returns the size of this hash map.  Note that the size() may shrink
+-   * spontaneously, if the some of the keys were only weakly reachable.
++   * spontanously, if the some of the keys were only weakly reachable.
+    * @return the number of entries in this hash map.
+    */
+   public int size()
+@@ -714,10 +651,9 @@
+ 
+   /**
+    * Tells if the map contains the given key.  Note that the result
+-   * may change spontanously, if the key was only weakly
+-   * reachable.
+-   * @param key the key to look for
+-   * @return true, iff the map contains an entry for the given key.
++   * may change spontanously, if all the key was only weakly
++   * reachable.  
++   * @return true, iff the map contains an entry for the given key. 
+    */
+   public boolean containsKey(Object key)
+   {
+@@ -726,38 +662,38 @@
+   }
+ 
+   /**
+-   * Gets the value the key is mapped to.
++   * Gets the value the key will be mapped to.
+    * @return the value the key was mapped to.  It returns null if
+-   *         the key wasn't in this map, or if the mapped value was
+-   *         explicitly set to null.
++   * the key wasn't in this map, or if the mapped value was explicitly
++   * set to null.  
+    */
+   public Object get(Object key)
+   {
+     cleanQueue();
+-    WeakBucket.WeakEntry entry = internalGet(key);
++    WeakBucket.Entry entry = internalGet(key);
+     return entry == null ? null : entry.getValue();
+   }
+ 
+   /**
+    * Adds a new key/value mapping to this map.
+-   * @param key the key, may be null
+-   * @param value the value, may be null
++   * @param key the key. This may be null.
++   * @param value the value. This may be null.
+    * @return the value the key was mapped to previously.  It returns
+-   *         null if the key wasn't in this map, or if the mapped value
+-   *         was explicitly set to null.
++   * null if the key wasn't in this map, or if the mapped value was
++   * explicitly set to null.  
+    */
+   public Object put(Object key, Object value)
+   {
+     cleanQueue();
+-    WeakBucket.WeakEntry entry = internalGet(key);
++    WeakBucket.Entry entry = internalGet(key);
+     if (entry != null)
+       return entry.setValue(value);
+ 
+-    modCount++;
+     if (size >= threshold)
+       rehash();
+ 
+     internalAdd(key, value);
++    modCount++;
+     return null;
+   }
+ 
+@@ -765,18 +701,18 @@
+    * Removes the key and the corresponding value from this map.
+    * @param key the key. This may be null.
+    * @return the value the key was mapped to previously.  It returns
+-   *         null if the key wasn't in this map, or if the mapped value was
+-   *         explicitly set to null.
+-   */
++   * null if the key wasn't in this map, or if the mapped value was
++   * explicitly set to null.  */
+   public Object remove(Object key)
+   {
+     cleanQueue();
+-    WeakBucket.WeakEntry entry = internalGet(key);
++    WeakBucket.Entry entry = internalGet(key);
+     if (entry == null)
+-      return null;
+-
+-    modCount++;
++      {
++	return null;
++      }
+     internalRemove(entry.getBucket());
++    modCount++;
+     return entry.getValue();
+   }
+ 
+@@ -785,71 +721,11 @@
+    * set will not have strong references to the keys, so they can be
+    * silently removed.  The returned set has therefore the same
+    * strange behaviour (shrinking size(), disappearing entries) as
+-   * this weak hash map.
+-   * @return a set representation of the entries.
+-   */
++   * this weak hash map.  
++   * @return a set representation of the entries.  */
+   public Set entrySet()
+   {
+     cleanQueue();
+     return theEntrySet;
+-  }
+-
+-  /**
+-   * Clears all entries from this map.
+-   */
+-  public void clear()
+-  {
+-    super.clear();
+-  }
+-
+-  /**
+-   * Returns true if the map contains at least one key which points to
+-   * the specified object as a value.  Note that the result
+-   * may change spontanously, if its key was only weakly reachable.
+-   * @param value the value to search for
+-   * @return true if it is found in the set.
+-   */
+-  public boolean containsValue(Object value)
+-  {
+-    cleanQueue();
+-    return super.containsValue(value);
+-  }
+-
+-  /**
+-   * Returns a set representation of the keys in this map.  This
+-   * set will not have strong references to the keys, so they can be
+-   * silently removed.  The returned set has therefore the same
+-   * strange behaviour (shrinking size(), disappearing entries) as
+-   * this weak hash map.
+-   * @return a set representation of the keys.
+-   */
+-  public Set keySet()
+-  {
+-    cleanQueue();
+-    return super.keySet();
+-  }
+-
+-  /**
+-   * Puts all of the mappings from the given map into this one. If the
+-   * key already exists in this map, its value is replaced.
+-   * @param m the map to copy in
+-   */
+-  public void putAll(Map m)
+-  {
+-    super.putAll(m);
+-  }
+-
+-  /**
+-   * Returns a collection representation of the values in this map.  This
+-   * collection will not have strong references to the keys, so mappings
+-   * can be silently removed.  The returned collection has therefore the same
+-   * strange behaviour (shrinking size(), disappearing entries) as
+-   * this weak hash map.
+-   * @return a collection representation of the values.
+-   */
+-  public Collection values()
+-  {
+-    cleanQueue();
+-    return super.values();
+   }
+ }
Index: compare/java.util.jar.Attributes.diff
===================================================================
RCS file: java.util.jar.Attributes.diff
diff -N java.util.jar.Attributes.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.jar.Attributes.diff Tue Nov 6 17:21:38 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/jar/Attributes.java	Fri Nov 17 19:29:20 2000
++++ java/util/jar/Attributes.java	Fri Nov  2 21:44:52 2001
+@@ -45,7 +45,7 @@
+  * manipulating the Attributes more or less type safe.
+  * <p>
+  * Most of the methods are wrappers to implement the Map interface. The really
+- * usefull and often used methods are <code>getValue(Name)</code> and
++ * useful and often used methods are <code>getValue(Name)</code> and
+  * <code>getValue(String)</code>. If you actually want to set attributes you
+  * may want to use the <code>putValue(String, String)</code> method
+  * (sorry there is no public type safe <code>putValue(Name, String)</code>
Index: compare/java.util.jar.JarEntry.diff
===================================================================
RCS file: java.util.jar.JarEntry.diff
diff -N java.util.jar.JarEntry.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.jar.JarEntry.diff Tue Nov 6 17:21:38 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/jar/JarEntry.java	Tue Nov  7 10:43:04 2000
++++ java/util/jar/JarEntry.java	Fri Nov  2 21:44:52 2001
+@@ -46,7 +46,7 @@
+ 
+ public class JarEntry extends ZipEntry
+ {
+-  // (Packge local) fields
++  // (Package local) fields
+ 
+   Attributes attr;
+   Certificate certs[];
Index: compare/java.util.jar.JarInputStream.diff
===================================================================
RCS file: java.util.jar.JarInputStream.diff
diff -N java.util.jar.JarInputStream.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.jar.JarInputStream.diff Tue Nov 6 17:21:38 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/jar/JarInputStream.java	Tue Nov  7 10:43:04 2000
++++ java/util/jar/JarInputStream.java	Fri Nov  2 21:44:52 2001
+@@ -75,7 +75,7 @@
+    * tries to verify all the entry signatures while reading.
+    *
+    * @param in InputStream to read the jar from
+-   * @param verify wheter or not to verify the manifest entries
++   * @param verify whether or not to verify the manifest entries
+    * @exception IOException when an error occurs when opening or reading
+    */
+   public JarInputStream(InputStream in, boolean verify) throws IOException
Index: compare/java.util.jar.JarOutputStream.diff
===================================================================
RCS file: java.util.jar.JarOutputStream.diff
diff -N java.util.jar.JarOutputStream.diff
--- /dev/null	Tue May  5 13:32:27 1998
+++ compare/java.util.jar.JarOutputStream.diff Tue Nov 6 17:21:38 2001
@@ -0,0 +1,11 @@
+--- /home/tromey/gnu/egcs/classpath/classpath/java/util/jar/JarOutputStream.java	Tue Nov  7 10:43:04 2000
++++ java/util/jar/JarOutputStream.java	Fri Nov  2 21:44:52 2001
+@@ -93,7 +93,7 @@
+    * This implementation just calls <code>super.putNextEntre()</code>.
+    *
+    * @param entry The information for the next entry
+-   * @exception IOException when some unexpected I/O exception occured
++   * @exception IOException when some unexpected I/O exception occurred
+    */
+   public void putNextEntry(ZipEntry entry) throws IOException
+   {
Index: compare/java.util.zip.GZIPOutputStream.diff
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/java/compare/java.util.zip.GZIPOutputStream.diff,v
retrieving revision 1.2
diff -u -r1.2 java.util.zip.GZIPOutputStream.diff
--- compare/java.util.zip.GZIPOutputStream.diff 2001/09/26 17:37:44 1.2
+++ compare/java.util.zip.GZIPOutputStream.diff 2001/11/07 01:21:39
@@ -1,10 +1,10 @@
 --- /home/tromey/gnu/egcs/classpath/classpath/java/util/zip/GZIPOutputStream.java	Wed Sep 26 08:18:48 2001
-+++ java/util/zip/GZIPOutputStream.java	Fri Nov 17 14:42:28 2000
++++ java/util/zip/GZIPOutputStream.java	Mon Oct 29 14:48:01 2001
 @@ -1,5 +1,5 @@
 -/* java.util.zip.GZIPOutputStream
 -   Copyright (C) 2001 Free Software Foundation, Inc.
 +/* GZIPOutputStream.java - Create a file in gzip format
-+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
++   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
  
  This file is part of GNU Classpath.
  
@@ -17,7 +17,7 @@
  GNU Classpath is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-@@ -26,116 +26,84 @@
+@@ -26,116 +26,90 @@
  
  package java.util.zip;
  
@@ -98,26 +98,30 @@
 -	/* The OS type (unknown) */
 -	(byte) 255
 -      };
--
--    out.write(gzipHeader);
--    //    System.err.println("wrote GZIP header (" + gzipHeader.length + " bytes )");
 +public class GZIPOutputStream extends DeflaterOutputStream
 +{
 +  public void close () throws IOException
 +  {
 +    finish ();
 +    out.close ();
++  }
+ 
+-    out.write(gzipHeader);
+-    //    System.err.println("wrote GZIP header (" + gzipHeader.length + " bytes )");
++  public void finish () throws IOException
++  {
++    super.finish();
++    put4 ((int) crc.getValue());
++    put4 (def.getTotalIn());
    }
 -  
 -  public void write(byte[] buf, int off, int len) throws IOException
 +
-+  public void finish () throws IOException
++  public GZIPOutputStream (OutputStream out) throws IOException
    {
 -    crc.update(buf, off, len);
 -    super.write(buf, off, len);
-+    super.finish();
-+    put4 ((int) crc.getValue());
-+    put4 (def.getTotalIn());
++    this (out, 512);
    }
 -  
 -  /** Writes remaining compressed output data to the output stream
@@ -125,19 +129,12 @@
 -   */
 -  public void close() throws IOException
 +
-+  public GZIPOutputStream (OutputStream out) throws IOException
++  public GZIPOutputStream (OutputStream out, int readsize) throws IOException
    {
 -    finish();
 -    out.close();
-+    this (out, 512);
-   }
- 
--  public void finish() throws IOException
-+  public GZIPOutputStream (OutputStream out, int readsize) throws IOException
-   {
 +    super (out, new Deflater (Deflater.DEFAULT_COMPRESSION, true), readsize);
- 
--    super.finish();
++
 +    put2 (GZIPInputStream.GZIP_MAGIC);
 +    out.write (GZIPInputStream.Z_DEFLATED);
 +    // No flags for now.
@@ -151,15 +148,23 @@
 +    out.write (255);
 +
 +    crc = new CRC32 ();
+   }
+ 
+-  public void finish() throws IOException
++  public synchronized void write (int bval) throws IOException
+   {
++    super.write (bval);
++    crc.update (bval);
 +  }
  
--    int totalin = def.getTotalIn();
--    int crcval = (int) (crc.getValue() & 0xffffffff);
+-    super.finish();
 +  public synchronized void write (byte[] buf) throws IOException
 +  {
 +    write (buf, 0, buf.length);
 +  }
-+
+ 
+-    int totalin = def.getTotalIn();
+-    int crcval = (int) (crc.getValue() & 0xffffffff);
 +  public synchronized void write (byte[] buf, int off, int len)
 +    throws IOException
 +  {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]