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();
            }
      }

Reply via email to