In trying to get classpath to work with Sun's javac, I came across a few
issues with
the Collections framework. The current implementation does not have the
correct
behavior with respect to concurrent modification. The spec says that
only
"structural modifications" cause a modification to be registered.
As it stands, Vector registers a modification when setElementAt() is
called. It should
only do this when there is the possibility of the size of the array
changing (the insert,
remove commands).
Similarly, HashMap registers a modification when a value is put that
already exists.
Since the size and structure of the map does not change, it should not
just register
a modification. I changed it to just update the value in the bucket,
rather than
replacing the entire bucket.
Another funny thing: The Enumeration returned by Vector.elements()
should not
throw a ConcurrentModificationException, rather it should act like it
does in
the 1.1 API. Nice of Sun to rely on all of these esoteric features in
their
compiler :-p
I probably should write some tests for this ... but I'm waiting to see
what
HP donates to Mauve first.
So... enough talk, here's the patch (do "patch -R" because I goofed up
the order of the diff's)
*** ArrayList.java Tue Feb 29 20:25:27 2000
--- ArrayList.java Sat Apr 24 20:51:22 1999
***************
*** 403,410 ****
String.valueOf(_iSize) + "; " +
"index=" + String.valueOf(iIndex));
oResult = _arData[iIndex];
! // SEH: no structural change, so don't update modCount
! //modCount++;
_arData[iIndex] = oElement;
return oResult;
--- 403,409 ----
String.valueOf(_iSize) + "; " +
"index=" + String.valueOf(iIndex));
oResult = _arData[iIndex];
! modCount++;
_arData[iIndex] = oElement;
return oResult;
*** Bucket.java Tue Feb 29 15:34:28 2000
--- Bucket.java Mon Oct 12 20:38:34 1998
***************
*** 61,68 ****
if ((oKey == null) ? (oTestKey == null) :
oKey.equals(oTestKey))
{
! it.value = newNode.getValue();
! return it;
}
prev = it;
it = it.next;
--- 61,72 ----
if ((oKey == null) ? (oTestKey == null) :
oKey.equals(oTestKey))
{
! if (prev != null)
! prev.next = newNode;
! else
! first = newNode;
! newNode.next = it.next;
! return it;
}
prev = it;
it = it.next;
*** Vector.java Tue Feb 29 19:50:54 2000
--- Vector.java Sat Aug 14 10:52:38 1999
***************
*** 337,342 ****
--- 336,342 ----
(index >= elementCount))
throw new ArrayIndexOutOfBoundsException(index);
+ modCount++;
elementData[index] = obj;
}
***************
*** 353,358 ****
--- 353,359 ----
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
+ modCount++;
Object temp = elementData[index];
elementData[index] = element;
return temp;
***************
*** 669,693 ****
}
/**
! * 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.
*
* @returns an Enumeration
*/
public Enumeration elements() {
! return new Enumeration() {
! int i=0;
! public final boolean hasMoreElements() {
! return (i<size());
! }
! public final Object nextElement() {
! if (i>=size())
! throw new NoSuchElementException();
! return (elementAt(i++));
! }
! };
}
} // Vector
--- 670,681 ----
}
/**
! * Returns an Enumeration of the elements of this List
*
* @returns an Enumeration
*/
public Enumeration elements() {
! return java.util.Collections.enumeration(this);
}
} // Vector
*** HashMap.java Tue Feb 29 20:25:35 2000
--- HashMap.java Fri Jun 25 09:12:38 1999
***************
*** 365,370 ****
--- 365,373 ----
Object oResult;
Object oRealKey = ((key == null) ? NULL_KEY : key);
+ modCount++;
+ if (size == threshold)
+ rehash();
entry = new HashMapEntry(oRealKey, value);
hashIndex = hash(oRealKey);
list = buckets[hashIndex];
***************
*** 376,393 ****
oResult = list.add(entry);
if (oResult == null)
{
! if (size == threshold) {
! rehash();
! } else {
! modCount++;
! size++;
! }
return null;
}
else
{
- // SEH: if key already exists, we don't rehash & we don't update the
modCount
- // because it is not a "structural" modification
return ((Map.Entry) oResult).getValue();
}
}
--- 379,389 ----
oResult = list.add(entry);
if (oResult == null)
{
! size++;
return null;
}
else
{
return ((Map.Entry) oResult).getValue();
}
}