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; + } }