scolebourne    2004/07/17 14:02:48

  Modified:    collections/src/test/org/apache/commons/collections/iterators
                        TestAll.java
               collections RELEASE-NOTES.html
  Added:       collections/src/test/org/apache/commons/collections/iterators
                        TestLoopingListIterator.java
               collections/src/java/org/apache/commons/collections/iterators
                        LoopingListIterator.java
  Log:
  Add LoopingListIterator

  bug 30166, from Eric Crampton
  
  Revision  Changes    Path
  1.16      +2 -1      
jakarta-commons/collections/src/test/org/apache/commons/collections/iterators/TestAll.java
  
  Index: TestAll.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/iterators/TestAll.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- TestAll.java      9 Apr 2004 14:38:47 -0000       1.15
  +++ TestAll.java      17 Jul 2004 21:02:47 -0000      1.16
  @@ -47,6 +47,7 @@
           suite.addTest(TestIteratorChain.suite());
           suite.addTest(TestListIteratorWrapper.suite());
           suite.addTest(TestLoopingIterator.suite());
  +        suite.addTest(TestLoopingListIterator.suite());
           suite.addTest(TestSingletonIterator.suite());
           suite.addTest(TestSingletonIterator2.suite());
           suite.addTest(TestSingletonListIterator.suite());
  
  
  
  1.1                  
jakarta-commons/collections/src/test/org/apache/commons/collections/iterators/TestLoopingListIterator.java
  
  Index: TestLoopingListIterator.java
  ===================================================================
  /*
   *  Copyright 2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   */
  package org.apache.commons.collections.iterators;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.NoSuchElementException;
  
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestSuite;
  
  /**
   * Tests the LoopingListIterator class.
   *
   * @version $Revision: 1.1 $ $Date: 2004/07/17 21:02:47 $
   *
   * @author Eric Crampton <[EMAIL PROTECTED]>
   */
  public class TestLoopingListIterator extends TestCase {
  
      public TestLoopingListIterator(String testName) {
          super(testName);
      }
      
      public static Test suite() {
          return new TestSuite(TestLoopingListIterator.class);
      }
  
      /**
       * Tests constructor exception.
       */
      public void testConstructorEx() throws Exception {
          try {
              new LoopingListIterator(null);
              fail();
          } catch (NullPointerException ex) {
          }
      }
  
      /**
       * Tests whether an empty looping list iterator works.
       */
      public void testLooping0() throws Exception {
          List list = new ArrayList();
          LoopingListIterator loop = new LoopingListIterator(list);
          assertFalse(loop.hasNext());
          assertFalse(loop.hasPrevious());
          
          try {
              loop.next();
              fail();
          } catch (NoSuchElementException ex) {
          }
  
          try {
              loop.previous();
              fail();
          } catch (NoSuchElementException ex) {
          }
      }
  
      /**
       * Tests whether a looping list iterator works on a list with only
       * one element.
       */
      public void testLooping1() throws Exception {
          List list = new ArrayList(Arrays.asList(new String[] { "a" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <a>
  
          assertTrue(loop.hasNext());
          assertEquals("a", loop.next());     // <a>
  
          assertTrue(loop.hasNext());
          assertEquals("a", loop.next());     // <a>
  
          assertTrue(loop.hasNext());
          assertEquals("a", loop.next());     // <a>
  
          assertTrue(loop.hasPrevious());
          assertEquals("a", loop.previous()); // <a>
  
          assertTrue(loop.hasPrevious());
          assertEquals("a", loop.previous()); // <a>
  
          assertTrue(loop.hasPrevious());
          assertEquals("a", loop.previous()); // <a>
      }
  
      /**
       * Tests whether a looping list iterator works on a list with two
       * elements.
       */
      public void testLooping2() throws Exception {
          List list = new ArrayList(Arrays.asList(new String[] { "a", "b" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <a> b
  
          assertTrue(loop.hasNext());
          assertEquals("a", loop.next());     // a <b>
  
          assertTrue(loop.hasNext());
          assertEquals("b", loop.next());     // <a> b
  
          assertTrue(loop.hasNext());
          assertEquals("a", loop.next());     // a <b>
  
          // Reset the iterator and try using previous.
          loop.reset();                       // <a> b
  
          assertTrue(loop.hasPrevious());
          assertEquals("b", loop.previous()); // a <b>
  
          assertTrue(loop.hasPrevious());
          assertEquals("a", loop.previous()); // <a> b
  
          assertTrue(loop.hasPrevious());
          assertEquals("b", loop.previous()); // a <b>
      }
  
      /**
       * Tests jogging back and forth between two elements, but not over
       * the begin/end boundary of the list.
       */
      public void testJoggingNotOverBoundary() {
          List list = new ArrayList(Arrays.asList(new String[] { "a", "b" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <a> b
      
          // Try jogging back and forth between the elements, but not
          // over the begin/end boundary.
          loop.reset();
          assertEquals("a", loop.next());     // a <b>
          assertEquals("a", loop.previous()); // <a> b
          assertEquals("a", loop.next());     // a <b>
  
          assertEquals("b", loop.next());     // <a> b
          assertEquals("b", loop.previous()); // a <b>
          assertEquals("b", loop.next());     // <a> b
      }
  
      /**
       * Tests jogging back and forth between two elements over the
       * begin/end boundary of the list.
       */
      public void testJoggingOverBoundary() {
          List list = new ArrayList(Arrays.asList(new String[] { "a", "b" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <a> b
      
          // Try jogging back and forth between the elements, but not
          // over the begin/end boundary.
          assertEquals("b", loop.previous()); // a <b>
          assertEquals("b", loop.next());     // <a> b
          assertEquals("b", loop.previous()); // a <b>
  
          assertEquals("a", loop.previous()); // <a> b
          assertEquals("a", loop.next());     // a <b>
          assertEquals("a", loop.previous()); // <a> b
      }
  
      /**
       * Tests removing an element from a wrapped ArrayList.
       */
      public void testRemovingElementsAndIteratingForward() {
          List list = new ArrayList(Arrays.asList(new String[] { "a", "b", "c" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <a> b c
  
          assertTrue(loop.hasNext());
          assertEquals("a", loop.next()); // a <b> c
          loop.remove();                  // <b> c
          assertEquals(2, list.size());
  
          assertTrue(loop.hasNext());
          assertEquals("b", loop.next()); // b <c>
          loop.remove();                  // <c>
          assertEquals(1, list.size());
  
          assertTrue(loop.hasNext());
          assertEquals("c", loop.next()); // <c>
          loop.remove();                  // ---
          assertEquals(0, list.size());
  
          assertFalse(loop.hasNext());
          try {
              loop.next();
              fail();
          } catch (NoSuchElementException ex) {
          }
      }
  
      /**
       * Tests removing an element from a wrapped ArrayList.
       */
      public void testRemovingElementsAndIteratingBackwards() {
          List list = new ArrayList(Arrays.asList(new String[] { "a", "b", "c" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <a> b c
  
          assertTrue(loop.hasPrevious());
          assertEquals("c", loop.previous()); // a b <c>
          loop.remove();                      // <a> b
          assertEquals(2, list.size());
  
          assertTrue(loop.hasPrevious());
          assertEquals("b", loop.previous()); // a <b>
          loop.remove();                      // <a>
          assertEquals(1, list.size());
  
          assertTrue(loop.hasPrevious());
          assertEquals("a", loop.previous()); // <a>
          loop.remove();                      // ---
          assertEquals(0, list.size());
  
          assertFalse(loop.hasPrevious());
          try {
              loop.previous();
              fail();
          } catch (NoSuchElementException ex) {
          }
      }
  
      /**
       * Tests the reset method.
       */
      public void testReset() {
          List list = new ArrayList(Arrays.asList(new String[] { "a", "b", "c" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <a> b c
  
          assertEquals("a", loop.next()); // a <b> c
          assertEquals("b", loop.next()); // a b <c>
          loop.reset();                   // <a> b c
          assertEquals("a", loop.next()); // a <b> c
          loop.reset();                   // <a> b c
          assertEquals("a", loop.next()); // a <b> c
          assertEquals("b", loop.next()); // a b <c>
          assertEquals("c", loop.next()); // <a> b c
          loop.reset();                   // <a> b c
  
          assertEquals("c", loop.previous()); // a b <c>
          assertEquals("b", loop.previous()); // a <b> c
          loop.reset();                       // <a> b c
          assertEquals("c", loop.previous()); // a b <c>
          loop.reset();                       // <a> b c
          assertEquals("c", loop.previous()); // a b <c>
          assertEquals("b", loop.previous()); // a <b> c
          assertEquals("a", loop.previous()); // <a> b c
      }
  
      /**
       * Tests the add method.
       */
      public void testAdd() {
          List list = new ArrayList(Arrays.asList(new String[] { "b", "e", "f" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <b> e f
  
          loop.add("a");                      // <a> b e f
          assertEquals("b", loop.next());     // a <b> e f
          loop.reset();                       // <a> b e f
          assertEquals("a", loop.next());     // a <b> e f
          assertEquals("b", loop.next());     // a b <e> f
  
          loop.add("c");                      // a b c <e> f
          assertEquals("e", loop.next());     // a b c e <f>
          assertEquals("e", loop.previous()); // a b c <e> f
          assertEquals("c", loop.previous()); // a b <c> e f
          assertEquals("c", loop.next());     // a b c <e> f
          
          loop.add("d");                      // a b c d <e> f
          loop.reset();                       // <a> b c d e f
          assertEquals("a", loop.next());     // a <b> c d e f
          assertEquals("b", loop.next());     // a b <c> d e f
          assertEquals("c", loop.next());     // a b c <d> e f
          assertEquals("d", loop.next());     // a b c d <e> f
          assertEquals("e", loop.next());     // a b c d e <f>
          assertEquals("f", loop.next());     // <a> b c d e f
          assertEquals("a", loop.next());     // a <b> c d e f
  
          list = new ArrayList(Arrays.asList(new String[] { "b", "e", "f" }));
          loop = new LoopingListIterator(list); // <b> e f        
  
          loop.add("a");                      // a <b> e f
          assertEquals("a", loop.previous()); // a b e <f>
          loop.reset();                       // <a> b e f
          assertEquals("f", loop.previous()); // a b e <f>
          assertEquals("e", loop.previous()); // a b <e> f
  
          loop.add("d");                      // a b d <e> f
          assertEquals("d", loop.previous()); // a b <d> e f
  
          loop.add("c");                      // a b c <d> e f
          assertEquals("c", loop.previous()); // a b <c> d e f
  
          loop.reset();
          assertEquals("a", loop.next());     // a <b> c d e f
          assertEquals("b", loop.next());     // a b <c> d e f
          assertEquals("c", loop.next());     // a b c <d> e f
          assertEquals("d", loop.next());     // a b c d <e> f
          assertEquals("e", loop.next());     // a b c d e <f>
          assertEquals("f", loop.next());     // <a> b c d e f
          assertEquals("a", loop.next());     // a <b> c d e f
      }
  
      /**
       * Tests nextIndex and previousIndex.
       */
      public void testNextAndPreviousIndex() {
          List list = new ArrayList(Arrays.asList(new String[] { "a", "b", "c" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <a> b c
  
          assertEquals(0, loop.nextIndex());
          assertEquals(2, loop.previousIndex());
  
          assertEquals("a", loop.next());        // a <b> c
          assertEquals(1, loop.nextIndex());
          assertEquals(0, loop.previousIndex());
  
          assertEquals("a", loop.previous());    // <a> b c
          assertEquals(0, loop.nextIndex());
          assertEquals(2, loop.previousIndex());
  
          assertEquals("c", loop.previous());    // a b <c>
          assertEquals(2, loop.nextIndex());
          assertEquals(1, loop.previousIndex());
  
          assertEquals("b", loop.previous());    // a <b> c
          assertEquals(1, loop.nextIndex());
          assertEquals(0, loop.previousIndex());
  
          assertEquals("a", loop.previous());    // <a> b c
          assertEquals(0, loop.nextIndex());
          assertEquals(2, loop.previousIndex());
      }
  
      /**
       * Tests using the set method to change elements.
       */
      public void testSet() {
          List list = new ArrayList(Arrays.asList(new String[] { "q", "r", "z" }));
          LoopingListIterator loop = new LoopingListIterator(list); // <q> r z
  
          assertEquals("z", loop.previous()); // q r <z>
          loop.set("c");                      // q r <c>
  
          loop.reset();                       // <q> r c
          assertEquals("q", loop.next());     // q <r> c
          loop.set("a");                      // a <r> c
          
          assertEquals("r", loop.next());     // a r <c>
          loop.set("b");                      // a b <c>
  
          loop.reset();                       // <a> b c
          assertEquals("a", loop.next());     // a <b> c
          assertEquals("b", loop.next());     // a b <c>
          assertEquals("c", loop.next());     // <a> b c
      }
      
  }
  
  
  
  1.68      +1 -1      jakarta-commons/collections/RELEASE-NOTES.html
  
  Index: RELEASE-NOTES.html
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/RELEASE-NOTES.html,v
  retrieving revision 1.67
  retrieving revision 1.68
  diff -u -r1.67 -r1.68
  --- RELEASE-NOTES.html        28 Jun 2004 23:26:33 -0000      1.67
  +++ RELEASE-NOTES.html        17 Jul 2004 21:02:47 -0000      1.68
  @@ -34,7 +34,7 @@
   
   <center><h3>NEW CLASSES</h3></center>
   <ul>
  -<li>........</li>
  +<li>LoopingListIterator - When the end of the list is reached the iteration 
continues from the start</li>
   </ul>
   
   <center><h3>ENHANCEMENTS</h3></center>
  
  
  
  1.1                  
jakarta-commons/collections/src/java/org/apache/commons/collections/iterators/LoopingListIterator.java
  
  Index: LoopingListIterator.java
  ===================================================================
  /*
   *  Copyright 2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   */
  package org.apache.commons.collections.iterators;
  
  import java.util.List;
  import java.util.ListIterator;
  import java.util.NoSuchElementException;
  
  import org.apache.commons.collections.ResettableIterator;
  
  /**
   * A ListIterator that restarts when it reaches the end or when it
   * reaches the beginning.
   * <p>
   * The iterator will loop continuously around the provided list,
   * unless there are no elements in the collection to begin with, or
   * all of the elements have been [EMAIL PROTECTED] #remove removed}.
   * <p>
   * Concurrent modifications are not directly supported, and for most
   * collection implementations will throw a
   * ConcurrentModificationException.
   *
   * @since Commons Collections 3.2
   * @version $Revision: 1.1 $ $Date: 2004/07/17 21:02:47 $
   *
   * @author Eric Crampton <[EMAIL PROTECTED]>
   */
  public class LoopingListIterator implements ResettableIterator {
  
      /** The list to base the iterator on */
      private List list;
      /** The current list iterator */
      private ListIterator iterator;
  
      /**
       * Constructor that wraps a list.
       * <p>
       * There is no way to reset a ListIterator instance without
       * recreating it from the original source, so the List must be
       * passed in and a reference to it held.
       *
       * @param list the list to wrap
       * @throws NullPointerException if the list it null
       */
      public LoopingListIterator(List list) {
          if (list == null) {
              throw new NullPointerException("The list must not be null");
          }
          this.list = list;
          reset();
      }
  
      /**
       * Returns whether this iterator has any more elements.
       * <p>
       * Returns false only if the list originally had zero elements, or
       * all elements have been [EMAIL PROTECTED] #remove removed}.
       *
       * @return <code>true</code> if there are more elements
       */
      public boolean hasNext() {
          return !list.isEmpty();
      }
  
      /**
       * Returns the next object in the list.
       * <p>
       * If at the end of the list, returns the first element.
       *
       * @return the object after the last element returned
       * @throws NoSuchElementException if there are no elements in the list
       */
      public Object next() {
          if (list.isEmpty()) {
              throw new NoSuchElementException(
                  "There are no elements for this iterator to loop on");
          }
          if (iterator.hasNext() == false) {
              reset();
          }
          return iterator.next();
      }
  
      /**
       * Returns the index of the element that would be returned by a
       * subsequent call to [EMAIL PROTECTED] #next}.
       * <p>
       * As would be expected, if the iterator is at the physical end of
       * the underlying list, 0 is returned, signifying the beginning of
       * the list.
       *
       * @return the index of the element that would be returned if next() were called
       * @throws NoSuchElementException if there are no elements in the list
       */
      public int nextIndex() {
          if (list.isEmpty()) {
              throw new NoSuchElementException(
                  "There are no elements for this iterator to loop on");
          }
          if (iterator.hasNext() == false) {
              return 0;
          } else {
              return iterator.nextIndex();
          }
      }
  
      /**
       * Returns whether this iterator has any more previous elements.
       * <p>
       * Returns false only if the list originally had zero elements, or
       * all elements have been [EMAIL PROTECTED] #remove removed}.
       *
       * @return <code>true</code> if there are more elements
       */
      public boolean hasPrevious() {
          return !list.isEmpty();
      }
  
      /**
       * Returns the previous object in the list.
       * <p>
       * If at the beginning of the list, return the last element. Note
       * that in this case, traversal to find that element takes linear time.
       *
       * @return the object before the last element returned
       * @throws NoSuchElementException if there are no elements in the list
       */
      public Object previous() {
          if (list.isEmpty()) {
              throw new NoSuchElementException(
                  "There are no elements for this iterator to loop on");
          }
          if (iterator.hasPrevious() == false) {
              Object result = null;
              while (iterator.hasNext()) {
                  result = iterator.next();
              }
              iterator.previous();
              return result;
          } else {
              return iterator.previous();
          }
      }
  
      /**
       * Returns the index of the element that would be returned by a
       * subsequent call to [EMAIL PROTECTED] #previous}.
       * <p>
       * As would be expected, if at the iterator is at the physical
       * beginning of the underlying list, the list's size minus one is
       * returned, signifying the end of the list.
       *
       * @return the index of the element that would be returned if previous() were 
called
       * @throws NoSuchElementException if there are no elements in the list
       */
      public int previousIndex() {
          if (list.isEmpty()) {
              throw new NoSuchElementException(
                  "There are no elements for this iterator to loop on");
          }
          if (iterator.hasPrevious() == false) {
              return list.size() - 1;
          } else {
              return iterator.previousIndex();
          }
      }
  
      /**
       * Removes the previously retrieved item from the underlying list.
       * <p>
       * This feature is only supported if the underlying list's
       * [EMAIL PROTECTED] List#iterator iterator} method returns an implementation
       * that supports it.
       * <p>
       * This method can only be called after at least one [EMAIL PROTECTED] #next}
       * or [EMAIL PROTECTED] #previous} method call. After a removal, the remove
       * method may not be called again until another [EMAIL PROTECTED] #next} or
       * [EMAIL PROTECTED] #previous} has been performed. If the [EMAIL PROTECTED] 
#reset} is
       * called, then remove may not be called until [EMAIL PROTECTED] #next} or
       * [EMAIL PROTECTED] #previous} is called again.
       *
       * @throws UnsupportedOperationException if the remove method is
       * not supported by the iterator implementation of the underlying
       * list
       */
      public void remove() {
          iterator.remove();
      }
  
      /**
       * Inserts the specified element into the underlying list.
       * <p>
       * The element is inserted before the next element that would be
       * returned by [EMAIL PROTECTED] #next}, if any, and after the next element
       * that would be returned by [EMAIL PROTECTED] #previous}, if any.
       * <p>
       * This feature is only supported if the underlying list's
       * [EMAIL PROTECTED] List#listIterator} method returns an implementation
       * that supports it.
       *
       * @param obj  the element to insert
       * @throws UnsupportedOperationException if the add method is not
       *  supported by the iterator implementation of the underlying list
       */
      public void add(Object obj) {
          iterator.add(obj);
      }
  
      /**
       * Replaces the last element that was returned by [EMAIL PROTECTED] #next} or
       * [EMAIL PROTECTED] #previous}.
       * <p>
       * This feature is only supported if the underlying list's
       * [EMAIL PROTECTED] List#listIterator} method returns an implementation
       * that supports it.
       *
       * @param obj  the element with which to replace the last element returned
       * @throws UnsupportedOperationException if the set method is not
       *  supported by the iterator implementation of the underlying list
       */
      public void set(Object obj) {
          iterator.set(obj);
      }
  
      /**
       * Resets the iterator back to the start of the list.
       */
      public void reset() {
          iterator = list.listIterator();
      }
  
      /**
       * Gets the size of the list underlying the iterator.
       *
       * @return the current list size
       */
      public int size() {
          return list.size();
      }
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to