Add List.subList and implementations.
Patch by: wcn@google.com
Review by: jat
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6340 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/super/com/google/gwt/emul/java/util/AbstractList.java b/user/super/com/google/gwt/emul/java/util/AbstractList.java
index 7a08442..e76a993 100644
--- a/user/super/com/google/gwt/emul/java/util/AbstractList.java
+++ b/user/super/com/google/gwt/emul/java/util/AbstractList.java
@@ -110,6 +110,74 @@
}
}
+ private static class SubList<E> extends AbstractList<E> {
+ private final List<E> wrapped;
+ private final int fromIndex;
+ private int size;
+
+ public SubList(List<E> wrapped, int fromIndex, int toIndex) {
+ this.wrapped = wrapped;
+ this.fromIndex = fromIndex;
+ size = getSize(fromIndex, toIndex);
+ if (fromIndex > toIndex) {
+ throw new IllegalArgumentException("fromIndex: " + fromIndex +
+ " > toIndex: " + toIndex);
+ }
+ if (fromIndex < 0) {
+ throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
+ " < 0");
+ }
+ if (toIndex > wrapped.size()) {
+ throw new IndexOutOfBoundsException("toIndex: " + toIndex +
+ " > wrapped.size() " + wrapped.size());
+ }
+ }
+
+ @Override
+ public void add(int index, E element) {
+ checkIndexForAdd(index);
+ size++;
+ wrapped.add(fromIndex + index, element);
+ }
+
+ @Override
+ public E get(int index) {
+ checkIndex(index);
+ return wrapped.get(fromIndex + index);
+ }
+
+ @Override
+ public E remove(int index) {
+ checkIndex(index);
+ E result = wrapped.remove(fromIndex + index);
+ size--;
+ return result;
+ }
+
+ @Override
+ public E set(int index, E element) {
+ checkIndex(index);
+ return wrapped.set(fromIndex + index, element);
+ }
+
+ @Override
+ public int size() {
+ return size;
+ }
+
+ private void checkIndex(int index) {
+ checkIndex(index, size);
+ }
+
+ private void checkIndexForAdd(int index) {
+ checkIndex(index, size - 1);
+ }
+
+ private int getSize(int fromIndex, int toIndex) {
+ return toIndex - fromIndex;
+ }
+ }
+
protected static void checkIndex(int index, int size) {
if (index < 0 || index >= size) {
indexOutOfBounds(index, size);
@@ -233,9 +301,9 @@
throw new UnsupportedOperationException("Set not supported on this list");
}
- // TODO(jat): implement
-// public List<E> subList(int fromIndex, int toIndex) {
-// }
+ public List<E> subList(int fromIndex, int toIndex) {
+ return new SubList<E>(this, fromIndex, toIndex);
+ }
protected void removeRange(int fromIndex, int endIndex) {
ListIterator<E> iter = listIterator(fromIndex);
diff --git a/user/super/com/google/gwt/emul/java/util/ArrayList.java b/user/super/com/google/gwt/emul/java/util/ArrayList.java
index 59b3e77..52a57ed 100644
--- a/user/super/com/google/gwt/emul/java/util/ArrayList.java
+++ b/user/super/com/google/gwt/emul/java/util/ArrayList.java
@@ -276,11 +276,6 @@
size = newSize;
}
- // TODO(jat): implement
-// @Override
-// List<E> subList(int fromIndex, int toIndex) {
-// }
-
@SuppressWarnings("unchecked")
private void clearImpl() {
array = (E[]) new Object[0];
diff --git a/user/super/com/google/gwt/emul/java/util/Collections.java b/user/super/com/google/gwt/emul/java/util/Collections.java
index d5528f2..fdf7ce8 100644
--- a/user/super/com/google/gwt/emul/java/util/Collections.java
+++ b/user/super/com/google/gwt/emul/java/util/Collections.java
@@ -148,6 +148,10 @@
public T set(int index, T element) {
throw new UnsupportedOperationException();
}
+
+ public List<T> subList(int fromIndex, int toIndex) {
+ return new UnmodifiableList<T>(list.subList(fromIndex, toIndex));
+ }
}
static class UnmodifiableMap<K, V> implements Map<K, V> {
diff --git a/user/super/com/google/gwt/emul/java/util/LinkedList.java b/user/super/com/google/gwt/emul/java/util/LinkedList.java
index 342a11c..f8e280b 100644
--- a/user/super/com/google/gwt/emul/java/util/LinkedList.java
+++ b/user/super/com/google/gwt/emul/java/util/LinkedList.java
@@ -28,6 +28,8 @@
List<E>, Queue<E>, Serializable {
/*
* This implementation uses a doubly-linked circular list with a header node.
+ *
+ * TODO(jat): add more efficient subList implementation.
*/
/**
@@ -302,11 +304,6 @@
return size;
}
- // TODO(jat): implement
-// @Override
-// List<E> subList(final int fromIndex, final int toIndex) {
-// }
-
private void addBefore(E o, Node<E> target) {
new Node<E>(o, target);
++size;
diff --git a/user/super/com/google/gwt/emul/java/util/List.java b/user/super/com/google/gwt/emul/java/util/List.java
index 10276f3..08831bc 100644
--- a/user/super/com/google/gwt/emul/java/util/List.java
+++ b/user/super/com/google/gwt/emul/java/util/List.java
@@ -67,8 +67,7 @@
int size();
- // TODO(jat): add back when we implement in all List
- // List<E> subList(int fromIndex, int toIndex);
+ List<E> subList(int fromIndex, int toIndex);
Object[] toArray();
diff --git a/user/super/com/google/gwt/emul/java/util/Vector.java b/user/super/com/google/gwt/emul/java/util/Vector.java
index b160320..a0e8748 100644
--- a/user/super/com/google/gwt/emul/java/util/Vector.java
+++ b/user/super/com/google/gwt/emul/java/util/Vector.java
@@ -222,11 +222,10 @@
return arrayList.size();
}
- // TODO(jat): add back when ArrayList actually supports subList
-// @Override
-// public List<E> subList(int fromIndex, int toIndex) {
-// return arrayList.subList(fromIndex, toIndex);
-// }
+ @Override
+ public List<E> subList(int fromIndex, int toIndex) {
+ return arrayList.subList(fromIndex, toIndex);
+ }
@Override
public Object[] toArray() {
diff --git a/user/test/com/google/gwt/emultest/java/util/ListTestBase.java b/user/test/com/google/gwt/emultest/java/util/ListTestBase.java
index 524fca7..7e2727b 100644
--- a/user/test/com/google/gwt/emultest/java/util/ListTestBase.java
+++ b/user/test/com/google/gwt/emultest/java/util/ListTestBase.java
@@ -17,10 +17,13 @@
import org.apache.commons.collections.TestArrayList;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
+
/**
* Tests List, and, by extension AbstractList. Uses inheritance to inherit all
* of Apache's TestList and TestCollection.
@@ -182,4 +185,101 @@
}
}
}
+
+ public void testSubList() {
+ List<Integer> wrappedList = createListWithContent(new int[]{1, 2, 3, 4, 5});
+ List<Integer> testList = wrappedList.subList(1, 4);
+ assertEquals(3, testList.size());
+
+ assertEquals(testList, Arrays.asList(2, 3, 4));
+ checkListSizeAndContent(testList, new int[]{2, 3, 4});
+ testList.add(1, 6);
+ assertEquals(testList, Arrays.asList(2, 6, 3, 4));
+ checkListSizeAndContent(testList, new int[]{2, 6, 3, 4});
+ assertEquals(wrappedList, Arrays.asList(1, 2, 6, 3, 4, 5));
+ checkListSizeAndContent(wrappedList, new int[]{1, 2, 6, 3, 4, 5});
+ testList.remove(2);
+ assertEquals(testList, Arrays.asList(2, 6, 4));
+ checkListSizeAndContent(testList, new int[]{2, 6, 4});
+
+ try {
+ testList.remove(3);
+ fail("Expected remove to fail");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ checkListSizeAndContent(wrappedList, new int[]{1, 2, 6, 4, 5});
+ testList.set(0, 7);
+ checkListSizeAndContent(testList, new int[]{7, 6, 4});
+ checkListSizeAndContent(wrappedList, new int[]{1, 7, 6, 4, 5});
+
+ try {
+ wrappedList.subList(-1, 5);
+ fail("expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ wrappedList.subList(0, 15);
+ fail("expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ wrappedList.subList(5, 1);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ wrappedList.subList(0, 1).add(2, 5);
+ fail("expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ wrappedList.subList(0, 1).add(-1, 5);
+ fail("expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ wrappedList.subList(0, 1).get(1);
+ fail("expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ wrappedList.subList(0, 1).get(-1);
+ fail("expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ wrappedList.subList(0, 1).set(2, 2);
+ fail("expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ wrappedList.subList(0, 1).set(-1, 5);
+ fail("expected IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ private void checkListSizeAndContent(List<Integer> in, int[] expected) {
+ assertEquals(expected.length, in.size());
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], (int) in.get(i));
+ }
+ }
+
+ private List<Integer> createListWithContent(int[] in) {
+ List<Integer> results = new ArrayList<Integer>();
+ for (int i = 0; i < in.length; i++) {
+ results.add(in[i]);
+ }
+ return results;
+ }
}