This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: FYI: Updated Classpath comparison page
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Subject: Patch: FYI: Updated Classpath comparison page
- From: Tom Tromey <tromey at redhat dot com>
- Date: 06 Nov 2001 18:44:01 -0700
- Cc: Gcc Patch List <gcc-patches at gcc dot gnu dot org>
- Reply-To: tromey at redhat dot com
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><public|private|protected> 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 < 0 || index >= 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 < 0 || index > 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 < 0 || index > 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 < 0 || index > 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 < 0 || index >= 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 < 0 || index >= 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 < 0
+- * || toIndex > size()
+- * @throws IllegalArgumentException if fromIndex > 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 < 0 || index > 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 < 0 || index > 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 < 0 || index > 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 < 0 || index >= 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 < 0 || index >= 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 < 0 || index >= 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 < 0 || index >= 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 < 0 || index >= 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 < 0 || index > 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 < 0 || index >= 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 < 0 || index > 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 > 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 >= 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 < 0, 0, or > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 < 0, 0, or > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 > toIndex
+- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
+- * || toIndex > 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 < 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 < 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 < 0 || from > 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 > to || from < 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 > to || from < 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 < 0 || from > 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 < 0 || from > 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() > 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() > 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 < 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 < 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 <, ==, or > 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 < 0 or >=
+- * 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 (>=0)
+- * @throws IllegalArgumentException if (initialCapacity < 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 (>=0)
+- * @param loadFactor the load factor (> 0, not NaN)
+- * @throws IllegalArgumentException if (initialCapacity < 0) ||
+- * ! (loadFactor > 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 (>= 0)
+- * @throws IllegalArgumentException if (initialCapacity < 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 (>= 0)
+- * @param loadFactor the load factor (> 0, not NaN)
+- * @throws IllegalArgumentException if (initialCapacity < 0) ||
+- * ! (loadFactor > 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 (>= 0)
+- * @throws IllegalArgumentException if (initialCapacity < 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 (>= 0)
+- * @param loadFactor the load factor (> 0, not NaN)
+- * @throws IllegalArgumentException if (initialCapacity < 0) ||
+- * ! (loadFactor > 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 < 0 || index > 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 < 0 || index >= 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 < 0 || index > 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 < 0 || index >= 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 < 0 || index >= 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 < 0 || index > 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 < 0 || index > 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 < 0 || index > 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 < 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 >= 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 > 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 <= 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 < 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 < 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 < 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 >= 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 < 0 || index >= 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 < 0 || index >= 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 < 0 || index > 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 < 0 || index >= 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 < 0 || index >= 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 < 0 || index > 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 < 0 || index >= 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 < 0 || index > 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 < 0
+- * || toIndex > size()
+- * @throws IllegalArgumentException if fromIndex > 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 > 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 >= 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
+ {