Add ReverseListIterator
rfe 39224, including code from Serge Knystautas git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@400329 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2b0a51fd95
commit
324ef991a6
|
@ -58,6 +58,7 @@ If this causes major headaches to anyone please contact commons-dev at jakarta.a
|
|||
<li>DefaultedMap - Returns a default value when the key is not found, without adding the default value to the map itself [30911]</li>
|
||||
<li>GrowthList - Decorator that causes set and indexed add to expand the list rather than throw IndexOutOfBoundsException [34171]</li>
|
||||
<li>LoopingListIterator - When the end of the list is reached the iteration continues from the start [30166]</li>
|
||||
<li>ReverseListIterator - A list iterator that returns the elements from the list in reverse order [39224]</li>
|
||||
<li>BoundedBuffer - A new wrapper class which can make any buffer bounded [37473]</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright 2006 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 org.apache.commons.collections.ResettableListIterator;
|
||||
|
||||
/**
|
||||
* Iterates backwards through a List, starting with the last element
|
||||
* and continuing to the first. This is useful for looping around
|
||||
* a list in reverse order without needing to actually reverse the list.
|
||||
* <p>
|
||||
* The first call to <code>next()</code> will return the last element
|
||||
* from the list, and so on. The <code>hasNext()</code> method works
|
||||
* in concert with the <code>next()</code> method as expected.
|
||||
* However, the <code>nextIndex()</code> method returns the correct
|
||||
* index in the list, thus it starts high and reduces as the iteration
|
||||
* continues. The previous methods work similarly.
|
||||
*
|
||||
* @author Serge Knystautas
|
||||
* @author Stephen Colebourne
|
||||
* @version $Revision: $ $Date$
|
||||
*/
|
||||
public class ReverseListIterator implements ResettableListIterator {
|
||||
|
||||
/** The list being wrapped. */
|
||||
private final List list;
|
||||
/** The list iterator being wrapped. */
|
||||
private ListIterator iterator;
|
||||
/** Flag to indicate if updating is possible at the moment. */
|
||||
private boolean validForUpdate = true;
|
||||
|
||||
/**
|
||||
* Constructor that wraps a list.
|
||||
*
|
||||
* @param list the list to create a reversed iterator for
|
||||
* @throws NullPointerException if the list is null
|
||||
*/
|
||||
public ReverseListIterator(List list) {
|
||||
super();
|
||||
this.list = list;
|
||||
iterator = list.listIterator(list.size());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks whether there is another element.
|
||||
*
|
||||
* @return true if there is another element
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return iterator.hasPrevious();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next element.
|
||||
* The next element is the previous in the list.
|
||||
*
|
||||
* @return the next element in the iterator
|
||||
*/
|
||||
public Object next() {
|
||||
Object obj = iterator.previous();
|
||||
validForUpdate = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the next element.
|
||||
*
|
||||
* @return the index of the next element in the iterator
|
||||
*/
|
||||
public int nextIndex() {
|
||||
return iterator.previousIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there is a previous element.
|
||||
*
|
||||
* @return true if there is a previous element
|
||||
*/
|
||||
public boolean hasPrevious() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous element.
|
||||
* The next element is the previous in the list.
|
||||
*
|
||||
* @return the previous element in the iterator
|
||||
*/
|
||||
public Object previous() {
|
||||
Object obj = iterator.next();
|
||||
validForUpdate = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the previous element.
|
||||
*
|
||||
* @return the index of the previous element in the iterator
|
||||
*/
|
||||
public int previousIndex() {
|
||||
return iterator.nextIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last returned element.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the list is unmodifiable
|
||||
* @throws IllegalStateException if there is no element to remove
|
||||
*/
|
||||
public void remove() {
|
||||
if (validForUpdate == false) {
|
||||
throw new IllegalStateException("Cannot remove from list until next() or previous() called");
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the last returned element.
|
||||
*
|
||||
* @param obj the object to set
|
||||
* @throws UnsupportedOperationException if the list is unmodifiable
|
||||
* @throws IllegalStateException if the iterator is not in a valid state for set
|
||||
*/
|
||||
public void set(Object obj) {
|
||||
if (validForUpdate == false) {
|
||||
throw new IllegalStateException("Cannot set to list until next() or previous() called");
|
||||
}
|
||||
iterator.set(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new element to the list between the next and previous elements.
|
||||
*
|
||||
* @param obj the object to add
|
||||
* @throws UnsupportedOperationException if the list is unmodifiable
|
||||
* @throws IllegalStateException if the iterator is not in a valid state for set
|
||||
*/
|
||||
public void add(Object obj) {
|
||||
// the validForUpdate flag is needed as the necessary previous()
|
||||
// method call re-enables remove and add
|
||||
if (validForUpdate == false) {
|
||||
throw new IllegalStateException("Cannot add to list until next() or previous() called");
|
||||
}
|
||||
validForUpdate = false;
|
||||
iterator.add(obj);
|
||||
iterator.previous();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the iterator back to the start (which is the
|
||||
* end of the list as this is a reversed iterator)
|
||||
*/
|
||||
public void reset() {
|
||||
iterator = list.listIterator(list.size());
|
||||
}
|
||||
|
||||
}
|
|
@ -48,6 +48,7 @@ public class TestAll extends TestCase {
|
|||
suite.addTest(TestListIteratorWrapper.suite());
|
||||
suite.addTest(TestLoopingIterator.suite());
|
||||
suite.addTest(TestLoopingListIterator.suite());
|
||||
suite.addTest(TestReverseListIterator.suite());
|
||||
suite.addTest(TestSingletonIterator.suite());
|
||||
suite.addTest(TestSingletonIterator2.suite());
|
||||
suite.addTest(TestSingletonListIterator.suite());
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright 2006 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.ListIterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
import org.apache.commons.collections.ResettableListIterator;
|
||||
|
||||
/**
|
||||
* Tests the ReverseListIterator.
|
||||
*
|
||||
* @version $Revision: $ $Date$
|
||||
*/
|
||||
public class TestReverseListIterator extends AbstractTestListIterator {
|
||||
|
||||
protected String[] testArray = { "One", "Two", "Three", "Four" };
|
||||
|
||||
public static void main(String args[]) {
|
||||
String[] testCaseName = { TestReverseListIterator.class.getName() };
|
||||
TestRunner.main(testCaseName);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return new TestSuite(TestReverseListIterator.class);
|
||||
}
|
||||
|
||||
public TestReverseListIterator(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
public ListIterator makeEmptyListIterator() {
|
||||
List list = new ArrayList();
|
||||
return new ReverseListIterator(list);
|
||||
}
|
||||
|
||||
public ListIterator makeFullListIterator() {
|
||||
List list = new ArrayList(Arrays.asList(testArray));
|
||||
return new ReverseListIterator(list);
|
||||
}
|
||||
|
||||
// overrides
|
||||
//-----------------------------------------------------------------------
|
||||
public void testEmptyListIteratorIsIndeedEmpty() {
|
||||
ListIterator it = makeEmptyListIterator();
|
||||
|
||||
assertEquals(false, it.hasNext());
|
||||
assertEquals(-1, it.nextIndex()); // reversed index
|
||||
assertEquals(false, it.hasPrevious());
|
||||
assertEquals(0, it.previousIndex()); // reversed index
|
||||
|
||||
// next() should throw a NoSuchElementException
|
||||
try {
|
||||
it.next();
|
||||
fail("NoSuchElementException must be thrown from empty ListIterator");
|
||||
} catch (NoSuchElementException e) {
|
||||
}
|
||||
|
||||
// previous() should throw a NoSuchElementException
|
||||
try {
|
||||
it.previous();
|
||||
fail("NoSuchElementException must be thrown from empty ListIterator");
|
||||
} catch (NoSuchElementException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testWalkForwardAndBack() {
|
||||
ArrayList list = new ArrayList();
|
||||
ListIterator it = makeFullListIterator();
|
||||
while (it.hasNext()) {
|
||||
list.add(it.next());
|
||||
}
|
||||
|
||||
// check state at end
|
||||
assertEquals(false, it.hasNext());
|
||||
assertEquals(true, it.hasPrevious());
|
||||
|
||||
// this had to be commented out, as there is a bug in the JDK before JDK1.5
|
||||
// where calling previous at the start of an iterator would push the cursor
|
||||
// back to an invalid negative value
|
||||
// try {
|
||||
// it.next();
|
||||
// fail("NoSuchElementException must be thrown from next at end of ListIterator");
|
||||
// } catch (NoSuchElementException e) {
|
||||
// }
|
||||
|
||||
// loop back through comparing
|
||||
for (int i = list.size() - 1; i >= 0; i--) {
|
||||
assertEquals("" + i, list.size() - i - 2, it.nextIndex()); // reversed index
|
||||
assertEquals(list.size() - i - 1, it.previousIndex()); // reversed index
|
||||
|
||||
Object obj = list.get(i);
|
||||
assertEquals(obj, it.previous());
|
||||
}
|
||||
|
||||
// check state at start
|
||||
assertEquals(true, it.hasNext());
|
||||
assertEquals(false, it.hasPrevious());
|
||||
try {
|
||||
it.previous();
|
||||
fail("NoSuchElementException must be thrown from previous at start of ListIterator");
|
||||
} catch (NoSuchElementException e) {
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public void testReverse() {
|
||||
ListIterator it = makeFullListIterator();
|
||||
assertEquals(true, it.hasNext());
|
||||
assertEquals(3, it.nextIndex());
|
||||
assertEquals(false, it.hasPrevious());
|
||||
assertEquals(4, it.previousIndex());
|
||||
assertEquals("Four", it.next());
|
||||
assertEquals(2, it.nextIndex());
|
||||
assertEquals(true, it.hasNext());
|
||||
assertEquals(3, it.previousIndex());
|
||||
assertEquals(true, it.hasPrevious());
|
||||
assertEquals("Three", it.next());
|
||||
assertEquals(true, it.hasNext());
|
||||
assertEquals(1, it.nextIndex());
|
||||
assertEquals(true, it.hasPrevious());
|
||||
assertEquals(2, it.previousIndex());
|
||||
assertEquals("Two", it.next());
|
||||
assertEquals(true, it.hasNext());
|
||||
assertEquals(0, it.nextIndex());
|
||||
assertEquals(true, it.hasPrevious());
|
||||
assertEquals(1, it.previousIndex());
|
||||
assertEquals("One", it.next());
|
||||
assertEquals(false, it.hasNext());
|
||||
assertEquals(-1, it.nextIndex());
|
||||
assertEquals(true, it.hasPrevious());
|
||||
assertEquals(0, it.previousIndex());
|
||||
assertEquals("One", it.previous());
|
||||
assertEquals("Two", it.previous());
|
||||
assertEquals("Three", it.previous());
|
||||
assertEquals("Four", it.previous());
|
||||
}
|
||||
|
||||
public void testReset() {
|
||||
ResettableListIterator it = (ResettableListIterator) makeFullListIterator();
|
||||
assertEquals("Four", it.next());
|
||||
it.reset();
|
||||
assertEquals("Four", it.next());
|
||||
it.next();
|
||||
it.next();
|
||||
it.reset();
|
||||
assertEquals("Four", it.next());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue