You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ma...@apache.org on 2002/05/09 05:20:59 UTC

cvs commit: jakarta-commons/collections/src/test/org/apache/commons/collections TestLRUMap.java TestSequencedHashMap.java

mas         02/05/08 20:20:59

  Modified:    collections/src/java/org/apache/commons/collections
                        SequencedHashMap.java
               collections/src/test/org/apache/commons/collections
                        TestLRUMap.java TestSequencedHashMap.java
  Log:
  Fixed to have SequencedHashMap throw a ConcurrentModificationException
  from its iterators if the map is modified through something other than
  the iterator.
  
  Revision  Changes    Path
  1.9       +47 -6     jakarta-commons/collections/src/java/org/apache/commons/collections/SequencedHashMap.java
  
  Index: SequencedHashMap.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/SequencedHashMap.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- SequencedHashMap.java	22 Feb 2002 04:58:17 -0000	1.8
  +++ SequencedHashMap.java	9 May 2002 03:20:59 -0000	1.9
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/SequencedHashMap.java,v 1.8 2002/02/22 04:58:17 mas Exp $
  - * $Revision: 1.8 $
  - * $Date: 2002/02/22 04:58:17 $
  + * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/SequencedHashMap.java,v 1.9 2002/05/09 03:20:59 mas Exp $
  + * $Revision: 1.9 $
  + * $Date: 2002/05/09 03:20:59 $
    *
    * ====================================================================
    *
  @@ -77,6 +77,7 @@
   import java.util.Map;
   import java.util.Set;
   import java.util.NoSuchElementException;
  +import java.util.ConcurrentModificationException;
   
   /**
    *  A map of objects whose mapping entries are sequenced based on the order in
  @@ -192,6 +193,14 @@
     private HashMap entries;
   
     /**
  +   *  Holds the number of modifications that have occurred to the map,
  +   *  excluding modifications made through a collection view's iterator
  +   *  (e.g. entrySet().iterator().remove()).  This is used to create a
  +   *  fail-fast behavior with the iterators.
  +   **/
  +  private transient long modCount = 0;
  +
  +  /**
      *  Construct a new sequenced hash map with default initial size and load
      *  factor.
      **/
  @@ -434,6 +443,7 @@
   
     // per Map.put(Object,Object)
     public Object put(Object key, Object value) {
  +    modCount++;
   
       Object oldValue = null;
   
  @@ -468,6 +478,15 @@
   
     // per Map.remove(Object)
     public Object remove(Object key) {
  +    modCount++;
  +    return removeImpl(key);
  +  }
  +  
  +  /**
  +   *  Removed an entry without changing the map's modification count.  This
  +   *  method should only be called from a collection view's iterator
  +   **/
  +  private Object removeImpl(Object key) {
       Entry e = (Entry)entries.remove(key);
       if(e == null) return null;
       removeEntry(e);
  @@ -494,6 +513,8 @@
   
     // per Map.clear()
     public void clear() {
  +    modCount++;
  +
       // remove all from the underlying map
       entries.clear();
   
  @@ -633,10 +654,17 @@
       private int returnType;
   
       /**
  -     *  Holds the "current" position in the iterator.  when pos.next is the
  +     *  Holds the "current" position in the iterator.  When pos.next is the
        *  sentinel, we've reached the end of the list.
        **/
       private Entry pos = sentinel;
  +
  +    /**
  +     *  Holds the expected modification count.  If the actual modification
  +     *  count of the map differs from this value, then a concurrent
  +     *  modification has occurred.
  +     **/
  +    private transient long expectedModCount = modCount;
       
       /**
        *  Construct an iterator over the sequenced elements in the order in which
  @@ -676,8 +704,14 @@
        *
        *  @exception NoSuchElementException if there are no more elements in the
        *  iterator.
  +     *
  +     *  @exception ConcurrentModificationException if a modification occurs in
  +     *  the underlying map.
        **/
       public Object next() {
  +      if(modCount != expectedModCount) {
  +        throw new ConcurrentModificationException();
  +      }
         if(pos.next == sentinel) {
           throw new NoSuchElementException();
         }
  @@ -707,14 +741,21 @@
        *  @exception IllegalStateException if there isn't a "last element" to be
        *  removed.  That is, if {@link #next()} has never been called, or if
        *  {@link #remove()} was already called on the element.
  +     *
  +     *  @exception ConcurrentModificationException if a modification occurs in
  +     *  the underlying map.
        **/
       public void remove() {
         if((returnType & REMOVED_MASK) != 0) {
           throw new IllegalStateException("remove() must follow next()");
         }
  +      if(modCount != expectedModCount) {
  +        throw new ConcurrentModificationException();
  +      }
   
  -      // remove the entry
  -      SequencedHashMap.this.remove(pos.getKey());
  +      // remove the entry by calling the removeImpl method which does not
  +      // update the mod count.  This allows the iterator to remain valid.
  +      SequencedHashMap.this.removeImpl(pos.getKey());
   
         // set the removed flag
         returnType = returnType | REMOVED_MASK;
  
  
  
  1.20      +4 -11     jakarta-commons/collections/src/test/org/apache/commons/collections/TestLRUMap.java
  
  Index: TestLRUMap.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestLRUMap.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- TestLRUMap.java	8 May 2002 17:34:17 -0000	1.19
  +++ TestLRUMap.java	9 May 2002 03:20:59 -0000	1.20
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestLRUMap.java,v 1.19 2002/05/08 17:34:17 morgand Exp $
  - * $Revision: 1.19 $
  - * $Date: 2002/05/08 17:34:17 $
  + * $Header: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestLRUMap.java,v 1.20 2002/05/09 03:20:59 mas Exp $
  + * $Revision: 1.20 $
  + * $Date: 2002/05/09 03:20:59 $
    *
    * ====================================================================
    *
  @@ -73,7 +73,7 @@
    * 
    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
    * @author <a href="mailto:morgand@apache.org">Morgan Delagrange</a>
  - * @version $Id: TestLRUMap.java,v 1.19 2002/05/08 17:34:17 morgand Exp $
  + * @version $Id: TestLRUMap.java,v 1.20 2002/05/09 03:20:59 mas Exp $
    */
   public class TestLRUMap extends TestSequencedHashMap
   {
  @@ -93,13 +93,6 @@
       public Map makeEmptyMap() {
           LRUMap map = new LRUMap();
           return map;
  -    }
  -
  -    // had to override from TestSequencedHashMap, because the test performs a get
  -    // inside a loop.  Since get() alter the Map in this class, an infinite loop
  -    // is produced
  -    public void testSequenceMap() {
  -        fail("trying to work out an infinite loop bug");
       }
   
       public void testRemoveLRU() {
  
  
  
  1.11      +11 -9     jakarta-commons/collections/src/test/org/apache/commons/collections/TestSequencedHashMap.java
  
  Index: TestSequencedHashMap.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestSequencedHashMap.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- TestSequencedHashMap.java	26 Feb 2002 00:08:07 -0000	1.10
  +++ TestSequencedHashMap.java	9 May 2002 03:20:59 -0000	1.11
  @@ -137,18 +137,20 @@
           SequencedHashMap clone = (SequencedHashMap) labRat.clone();
           assertEquals("Size of clone does not match original",
                        labRat.size(), clone.size());
  -        Iterator origKeys = labRat.keySet().iterator();
  -        Iterator copiedKeys = clone.keySet().iterator();
  -        while (origKeys.hasNext()) {
  -            Object origKey = origKeys.next();
  -            Object copiedKey = copiedKeys.next();
  -            assertEquals("Cloned key does not match orginal",
  -                         origKey, copiedKey);
  +        Iterator origEntries = labRat.entrySet().iterator();
  +        Iterator copiedEntries = clone.entrySet().iterator();
  +        while (origEntries.hasNext()) {
  +            Map.Entry origEntry = (Map.Entry)origEntries.next();
  +            Map.Entry copiedEntry = (Map.Entry)copiedEntries.next();
  +            assertEquals("Cloned key does not match original",
  +                         origEntry.getKey(), copiedEntry.getKey());
               assertEquals("Cloned value does not match original",
  -                         labRat.get(origKey), clone.get(copiedKey));
  +                         origEntry.getValue(), copiedEntry.getValue());
  +            assertEquals("Cloned entry does not match orginal",
  +                         origEntry, copiedEntry);
           }
           assertTrue("iterator() returned different number of elements than keys()",
  -               !copiedKeys.hasNext());
  +               !copiedEntries.hasNext());
   
           // Test sequence()
           List seq = labRat.sequence();
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>