scolebourne 2003/10/03 17:50:35
Modified: collections/src/test/org/apache/commons/collections/decorators
TestSetList.java
collections/src/java/org/apache/commons/collections/decorators
SetList.java
Log:
Refactor SetList to be a subclass of the abstract decorator
Revision Changes Path
1.2 +153 -13
jakarta-commons/collections/src/test/org/apache/commons/collections/decorators/TestSetList.java
Index: TestSetList.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/decorators/TestSetList.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TestSetList.java 2 Oct 2003 22:34:44 -0000 1.1
+++ TestSetList.java 4 Oct 2003 00:50:35 -0000 1.2
@@ -59,13 +59,16 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
import java.util.ListIterator;
import junit.framework.Test;
-import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
+import org.apache.commons.collections.AbstractTestList;
+
/**
* JUnit tests.
*
@@ -74,7 +77,7 @@
*
* @author Matthew Hawthorne
*/
-public class TestSetList extends TestCase {
+public class TestSetList extends AbstractTestList {
public static void main(String[] args) {
TestRunner.run(suite());
@@ -89,16 +92,153 @@
}
//-----------------------------------------------------------------------
- public void testConstructor() {
- final SetList lset =
- new SetList(
- Arrays.asList(new Integer[] { new Integer(1), new Integer(1)}));
+ protected List makeEmptyList() {
+ return new SetList(new ArrayList(), new HashSet());
+ }
- assertEquals("Duplicate element was added.", 1, lset.size());
+ public void testListIteratorSet() {
+ // override to block
+ resetFull();
+ ListIterator it = getList().listIterator();
+ it.next();
+ try {
+ it.set(null);
+ fail();
+ } catch (UnsupportedOperationException ex) {}
+ }
+
+ protected Object[] getFullNonNullElements() {
+ // override to avoid duplicate "One"
+ return new Object[] {
+ new String(""),
+ new String("One"),
+ new Integer(2),
+ "Three",
+ new Integer(4),
+ new Double(5),
+ new Float(6),
+ "Seven",
+ "Eight",
+ new String("Nine"),
+ new Integer(10),
+ new Short((short)11),
+ new Long(12),
+ "Thirteen",
+ "14",
+ "15",
+ new Byte((byte)16)
+ };
+ }
+
+ public void testListIteratorAdd() {
+ // override to cope with Set behaviour
+ resetEmpty();
+ List list1 = getList();
+ List list2 = getConfirmedList();
+
+ Object[] elements = getOtherElements(); // changed here
+ ListIterator iter1 = list1.listIterator();
+ ListIterator iter2 = list2.listIterator();
+
+ for (int i = 0; i < elements.length; i++) {
+ iter1.add(elements[i]);
+ iter2.add(elements[i]);
+ super.verify(); // changed here
+ }
+
+ resetFull();
+ iter1 = getList().listIterator();
+ iter2 = getConfirmedList().listIterator();
+ for (int i = 0; i < elements.length; i++) {
+ iter1.next();
+ iter2.next();
+ iter1.add(elements[i]);
+ iter2.add(elements[i]);
+ super.verify(); // changed here
+ }
+ }
+
+ public void testCollectionAddAll() {
+ // override for set behaviour
+ resetEmpty();
+ Object[] elements = getFullElements();
+ boolean r = collection.addAll(Arrays.asList(elements));
+ confirmed.addAll(Arrays.asList(elements));
+ verify();
+ assertTrue("Empty collection should change after addAll", r);
+ for (int i = 0; i < elements.length; i++) {
+ assertTrue("Collection should contain added element",
+ collection.contains(elements[i]));
+ }
+
+ resetFull();
+ int size = collection.size();
+ elements = getOtherElements();
+ r = collection.addAll(Arrays.asList(elements));
+ confirmed.addAll(Arrays.asList(elements));
+ verify();
+ assertTrue("Full collection should change after addAll", r);
+ for (int i = 0; i < elements.length; i++) {
+ assertTrue("Full collection should contain added element " + i,
+ collection.contains(elements[i]));
+ }
+ assertEquals("Size should increase after addAll",
+ size + elements.length, collection.size());
+ }
+
+ public void testListSetByIndex() {
+ // override for set behaviour
+ resetFull();
+ int size = collection.size();
+ getList().set(0, new Long(1000));
+ assertEquals(size, collection.size());
+
+ getList().set(2, new Long(1000));
+ assertEquals(size - 1, collection.size());
+ assertEquals(new Long(1000), getList().get(1)); // set into 2, but shifted
down to 1
+ }
+
+ boolean extraVerify = true;
+ public void testCollectionIteratorRemove() {
+ try {
+ extraVerify = false;
+ super.testCollectionIteratorRemove();
+ } finally {
+ extraVerify = true;
+ }
+ }
+
+ protected void verify() {
+ super.verify();
+
+ if (extraVerify) {
+ int size = collection.size();
+ getList().add(new Long(1000));
+ assertEquals(size + 1, collection.size());
+
+ getList().add(new Long(1000));
+ assertEquals(size + 1, collection.size());
+ assertEquals(new Long(1000), getList().get(size));
+
+ getList().remove(size);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ public void testFactory() {
+ Integer[] array = new Integer[] {new Integer(1), new Integer(2), new
Integer(1)};
+ ArrayList list = new ArrayList(Arrays.asList(array));
+ final SetList lset = SetList.decorate(list);
+
+ assertEquals("Duplicate element was added.", 2, lset.size());
+ assertEquals(new Integer(1), lset.get(0));
+ assertEquals(new Integer(2), lset.get(1));
+ assertEquals(new Integer(1), list.get(0));
+ assertEquals(new Integer(2), list.get(1));
}
public void testAdd() {
- final SetList lset = new SetList(new ArrayList());
+ final SetList lset = new SetList(new ArrayList(), new HashSet());
// Duplicate element
final Object obj = new Integer(1);
@@ -112,7 +252,7 @@
}
public void testAddAll() {
- final SetList lset = new SetList(new ArrayList());
+ final SetList lset = new SetList(new ArrayList(), new HashSet());
lset.addAll(
Arrays.asList(new Integer[] { new Integer(1), new Integer(1)}));
@@ -121,7 +261,7 @@
}
public void testSet() {
- final SetList lset = new SetList(new ArrayList());
+ final SetList lset = new SetList(new ArrayList(), new HashSet());
// Duplicate element
final Object obj1 = new Integer(1);
@@ -159,7 +299,7 @@
}
public void testListIterator() {
- final SetList lset = new SetList(new ArrayList());
+ final SetList lset = new SetList(new ArrayList(), new HashSet());
final Object obj1 = new Integer(1);
final Object obj2 = new Integer(2);
1.2 +178 -33
jakarta-commons/collections/src/java/org/apache/commons/collections/decorators/SetList.java
Index: SetList.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/decorators/SetList.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SetList.java 2 Oct 2003 22:34:44 -0000 1.1
+++ SetList.java 4 Oct 2003 00:50:35 -0000 1.2
@@ -57,12 +57,13 @@
*/
package org.apache.commons.collections.decorators;
-import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.ListIterator;
import java.util.Set;
/**
@@ -78,11 +79,6 @@
* class provides an alternative approach, by wrapping an existing Set and
* retaining insertion order in the iterator. This class offers the
<code>List</code>
* interface implementation as well.
- * <p>
- * If the <code>Set</code> aspects are important to you (fast add/contains/remove)
- * then <code>OrderedSet</code> is a better choice.
- * This implementation is based solely on <code>ArrayList</code>, and so has
- * slow add/contains/remove operations for all except small lists.
*
* @since Commons Collections 3.0
* @version $Revision$ $Date$
@@ -90,32 +86,63 @@
* @author Matthew Hawthorne
* @author Stephen Colebourne
*/
-public class SetList extends AbstractList {
+public class SetList extends AbstractListDecorator {
/**
- * Delegate list.
+ * Internal Set to maintain uniqueness.
*/
- private final List delegate = new ArrayList();
+ protected final Set set;
/**
- * Helps to maintain uniqueness.
+ * Factory method to create a SetList using the supplied list to retain order.
+ * <p>
+ * If the list contains duplicates, these are removed (first indexed one kept).
+ * A <code>HashSet</code> is used for the set behaviour.
+ *
+ * @param list the list to decorate, must not be null
+ * @throws IllegalArgumentException if list is null
*/
- private final Set set = new HashSet();
+ public static SetList decorate(List list) {
+ if (list == null) {
+ throw new IllegalArgumentException("List must not be null");
+ }
+ if (list.isEmpty()) {
+ return new SetList(list, new HashSet());
+ } else {
+ List temp = new ArrayList(list);
+ list.clear();
+ SetList sl = new SetList(list, new HashSet());
+ sl.addAll(temp);
+ return sl;
+ }
+ }
+ //-----------------------------------------------------------------------
/**
- * Factory method to create a SetList.
- * @param list the list to decorate
+ * Constructor that wraps (not copies) the List and specifies the set to use.
+ * <p>
+ * The set and list must both be correctly initialised to the same elements.
+ *
+ * @param set the set to decorate, must not be null
+ * @param list the list to decorate, must not be null
+ * @throws IllegalArgumentException if set or list is null
*/
- public static SetList decorate(List list) {
- return new SetList(list);
+ protected SetList(List list, Set set) {
+ super(list);
+ if (set == null) {
+ throw new IllegalArgumentException("Set must not be null");
+ }
+ this.set = set;
}
+ //-----------------------------------------------------------------------
/**
- * Contructs an new list copying the specified elements.
- * @param coll a collection to copy
+ * Gets an unmodifiable view as a Set.
+ *
+ * @return an unmodifiable set view
*/
- protected SetList(List list) {
- addAll(list);
+ public Set asSet() {
+ return Collections.unmodifiableSet(set);
}
//-----------------------------------------------------------------------
@@ -152,14 +179,27 @@
* @param object the object to add
*/
public void add(int index, Object object) {
- // Adds element if it is not contained already
- if (!set.contains(object)) {
- delegate.add(index, object);
+ // adds element if it is not contained already
+ if (set.contains(object) == false) {
+ super.add(index, object);
set.add(object);
}
}
- //-----------------------------------------------------------------------
+ /**
+ * Adds an element to the end of the list if it is not already present.
+ * <p>
+ * <i>(Violation)</i>
+ * The <code>List</code> interface makes the assumption that the element is
+ * always inserted. This may not happen with this implementation.
+ *
+ * @param index the index to insert at
+ * @param object the object to add
+ */
+ public boolean addAll(Collection coll) {
+ return addAll(size(), coll);
+ }
+
/**
* Adds a collection of objects to the end of the list avoiding duplicates.
* <p>
@@ -202,28 +242,133 @@
*/
public Object set(int index, Object object) {
int pos = indexOf(object);
- Object result = delegate.set(index, object);
+ Object result = super.set(index, object);
if (pos == -1 || pos == index) {
return result;
}
return remove(pos);
}
- public Object get(int index) {
- return delegate.get(index);
+ public boolean remove(Object object) {
+ boolean result = super.remove(object);
+ set.remove(object);
+ return result;
}
- public int size() {
- return delegate.size();
+ public Object remove(int index) {
+ Object result = super.remove(index);
+ set.remove(result);
+ return result;
}
- public Object remove(int index) {
- return delegate.remove(index);
+ public boolean removeAll(Collection coll) {
+ boolean result = super.removeAll(coll);
+ set.removeAll(coll);
+ return result;
+ }
+
+ public boolean retainAll(Collection coll) {
+ boolean result = super.retainAll(coll);
+ set.retainAll(coll);
+ return result;
}
public void clear() {
- delegate.clear();
+ super.clear();
set.clear();
}
+ public boolean contains(Object object) {
+ return set.contains(object);
+ }
+
+ public boolean containsAll(Collection coll) {
+ return set.containsAll(coll);
+ }
+
+ public Iterator iterator() {
+ return new SetListIterator(super.iterator(), set);
+ }
+
+ public ListIterator listIterator() {
+ return new SetListListIterator(super.listIterator(), set);
+ }
+
+ public ListIterator listIterator(int index) {
+ return new SetListListIterator(super.listIterator(index), set);
+ }
+
+ public List subList(int fromIndex, int toIndex) {
+ return new SetList(super.subList(fromIndex, toIndex), set);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Inner class iterator.
+ */
+ protected static class SetListIterator extends AbstractIteratorDecorator {
+
+ protected final Set set;
+ protected Object last = null;
+
+ protected SetListIterator(Iterator it, Set set) {
+ super(it);
+ this.set = set;
+ }
+
+ public Object next() {
+ last = super.next();
+ return last;
+ }
+
+ public void remove() {
+ super.remove();
+ set.remove(last);
+ last = null;
+ }
+
+ }
+
+ /**
+ * Inner class iterator.
+ */
+ protected static class SetListListIterator extends
AbstractListIteratorDecorator {
+
+ protected final Set set;
+ protected Object last = null;
+
+ protected SetListListIterator(ListIterator it, Set set) {
+ super(it);
+ this.set = set;
+ }
+
+ public Object next() {
+ last = super.next();
+ return last;
+ }
+
+ public Object previous() {
+ last = super.previous();
+ return last;
+ }
+
+ public void remove() {
+ super.remove();
+ set.remove(last);
+ last = null;
+ }
+
+ public void add(Object object) {
+ if (set.contains(object) == false) {
+ super.add(object);
+ set.add(object);
+ }
+ }
+
+ public void set(Object object) {
+ throw new UnsupportedOperationException("ListIterator does not support
set");
+ }
+
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]