Created
September 27, 2012 16:34
-
-
Save bxt/3794990 to your computer and use it in GitHub Desktop.
ConsList for Java, draft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.AbstractList; | |
| import java.util.Collection; | |
| import java.util.Collections; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| public class ConsList<E> extends AbstractList<E> implements List<E> { | |
| private E element; | |
| private List<E> parent; | |
| public ConsList(E element, List<E> parent) { | |
| this.element = element; | |
| if(parent == null) { | |
| this.parent = Collections.emptyList(); | |
| } else { | |
| this.parent = parent; | |
| } | |
| } | |
| @Override | |
| public int size() { | |
| return parent.size() + 1; | |
| } | |
| @Override | |
| public boolean isEmpty() { | |
| return false; | |
| } | |
| @Override | |
| public boolean contains(Object o) { | |
| return (o == null ? element == null : o.equals(element)) | |
| || parent.contains(o); | |
| } | |
| @Override | |
| public boolean add(E e) { | |
| return parent.add(e); | |
| } | |
| @Override | |
| public boolean remove(Object o) { | |
| if(o == null ? element == null : o.equals(element)) { | |
| remove(0); | |
| return true; | |
| } else { | |
| return parent.remove(o); | |
| } | |
| } | |
| @Override | |
| public boolean addAll(Collection<? extends E> c) { | |
| return parent.addAll(c); | |
| } | |
| @Override | |
| public void clear() { | |
| throw new UnsupportedOperationException( | |
| "Can't remove the single consed element while clearing. "); | |
| } | |
| @Override | |
| public E get(int index) { | |
| if(index == 0) return element; | |
| return parent.get(index-1); | |
| } | |
| @Override | |
| public E set(int index, E element) { | |
| if(index != 0) return parent.set(index-1, element); | |
| E oldElement = this.element; | |
| this.element = element; | |
| return oldElement; | |
| } | |
| @Override | |
| public void add(int index, E element) { | |
| if(index == 0) { | |
| parent.add(0, this.element); | |
| this.element = element; | |
| } else { | |
| parent.add(index-1, element); | |
| } | |
| } | |
| @Override | |
| public E remove(int index) { | |
| if(index == 0) { | |
| if(parent.isEmpty()) throw new UnsupportedOperationException( | |
| "Can't remove the single consed element. "); | |
| E oldElement = this.element; | |
| this.element = parent.remove(0); | |
| return oldElement; | |
| } else { | |
| return parent.remove(index-1); | |
| } | |
| } | |
| @Override | |
| public int indexOf(Object o) { | |
| if(o == null ? element == null : o.equals(element)) return 0; | |
| int parentIndex = parent.indexOf(o); | |
| if(parentIndex == -1) return parentIndex; | |
| return parentIndex+1; | |
| } | |
| @Override | |
| public int lastIndexOf(Object o) { | |
| int parentIndex = parent.lastIndexOf(o); | |
| if(parentIndex != -1) return parentIndex+1; | |
| if(o == null ? element == null : o.equals(element)) return 0; | |
| return -1; | |
| } | |
| @Override | |
| public List<E> subList(int fromIndex, int toIndex) { | |
| if(fromIndex > 1) return parent.subList(fromIndex-1, toIndex-1); | |
| return super.subList(fromIndex, toIndex); | |
| } | |
| @Override | |
| public Iterator<E> iterator() { | |
| return new Itr(); | |
| } | |
| private class Itr implements Iterator<E> { | |
| private Iterator<E> parentIterator = null; | |
| private boolean parentIteratorNexted = false; | |
| @Override | |
| public boolean hasNext() { | |
| return parentIterator == null || parentIterator.hasNext(); | |
| } | |
| @Override | |
| public E next() { | |
| if(parentIterator == null) { | |
| parentIterator = ConsList.this.parent.iterator(); | |
| return ConsList.this.element; | |
| } else { | |
| parentIteratorNexted = true; | |
| return parentIterator.next(); | |
| } | |
| } | |
| @Override | |
| public void remove() { | |
| if(parentIterator == null) { | |
| throw new IllegalStateException( | |
| "Calling remove() before next()"); | |
| } else if (!parentIteratorNexted){ | |
| ConsList.this.remove(0); | |
| } else { | |
| parentIterator.remove(); | |
| } | |
| } | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if(o == this) return true; | |
| if(!(o instanceof List)) return false; | |
| List<?> l = (List<?>) o; | |
| if(l.isEmpty()) return false; | |
| if(l.size() != parent.size()+1) return false; | |
| if(! (element == null ? l.get(0)==null : l.get(0).equals(element))) | |
| return false; | |
| return parent.equals(l.subList(1, l.size())); | |
| } | |
| @Override | |
| public int hashCode() { | |
| int hashCode = 1; | |
| hashCode = 31*hashCode + (element==null ? 0 : element.hashCode()); | |
| for (E e : parent) | |
| hashCode = 31*hashCode + (e==null ? 0 : e.hashCode()); | |
| return hashCode; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import static org.junit.Assert.assertEquals; | |
| import static org.junit.Assert.fail; | |
| import java.util.ArrayList; | |
| import java.util.Collections; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import org.junit.Test; | |
| public class ConsListTest { | |
| private static List<Integer> getThreeConstList() { | |
| return new ConsList<Integer>(3, null); | |
| } | |
| private static List<Integer> getThreeImmutableList() { | |
| return Collections.singletonList(3); | |
| } | |
| private static List<Integer> getTwoThreeConstList() { | |
| return new ConsList<Integer>(2, getThreeConstList()); | |
| } | |
| private static List<Integer> getTwoThreeArrayList() { | |
| List<Integer> l = new ArrayList<Integer>(2); | |
| l.add(2); | |
| l.add(3); | |
| return l; | |
| } | |
| private static List<Integer> getTwoThreeMixList() { | |
| List<Integer> l = new ArrayList<Integer>(2); | |
| l.add(3); | |
| return new ConsList<Integer>(2, l); | |
| } | |
| @Test | |
| public void testHashCode() { | |
| assertEquals(getThreeImmutableList().hashCode(), | |
| getThreeConstList().hashCode()); | |
| assertEquals(getTwoThreeArrayList().hashCode(), | |
| getTwoThreeMixList().hashCode()); | |
| assertEquals(getTwoThreeArrayList().hashCode(), | |
| getTwoThreeConstList().hashCode()); | |
| } | |
| @Test | |
| public void testSize() { | |
| assertEquals(1, getThreeConstList().size()); | |
| assertEquals(2, getTwoThreeMixList().size()); | |
| assertEquals(2, getTwoThreeConstList().size()); | |
| List<Integer> arrayList = new ArrayList<Integer>(); | |
| List<Integer> consList = new ConsList<Integer>(2, arrayList); | |
| assertEquals(1, consList.size()); | |
| arrayList.add(5); | |
| assertEquals(2, consList.size()); | |
| arrayList.add(6); | |
| assertEquals(3, consList.size()); | |
| } | |
| @Test | |
| public void testIsEmpty() { | |
| assertEquals(false, getThreeConstList().isEmpty()); | |
| assertEquals(false, getTwoThreeMixList().isEmpty()); | |
| assertEquals(false, getTwoThreeConstList().isEmpty()); | |
| } | |
| @Test(expected=UnsupportedOperationException.class) | |
| public void testClear() { | |
| getThreeConstList().clear(); | |
| } | |
| @Test | |
| public void testContainsObject() { | |
| assertEquals(true, getThreeConstList().contains(3)); | |
| assertEquals(false, getThreeConstList().contains(2)); | |
| assertEquals(false, getTwoThreeMixList().contains(4)); | |
| assertEquals(true, getTwoThreeMixList().contains(3)); | |
| assertEquals(true, getTwoThreeMixList().contains(2)); | |
| assertEquals(false, getTwoThreeConstList().contains(4)); | |
| assertEquals(true, getTwoThreeConstList().contains(3)); | |
| assertEquals(true, getTwoThreeConstList().contains(2)); | |
| List<Integer> arrayList = new ArrayList<Integer>(); | |
| List<Integer> consList = new ConsList<Integer>(3, arrayList); | |
| assertEquals(false, consList.contains(4)); | |
| assertEquals(true, consList.contains(3)); | |
| assertEquals(false, consList.contains(2)); | |
| arrayList.add(2); | |
| assertEquals(false, consList.contains(4)); | |
| assertEquals(true, consList.contains(3)); | |
| assertEquals(true, consList.contains(2)); | |
| arrayList.add(4); | |
| assertEquals(true, consList.contains(4)); | |
| assertEquals(true, consList.contains(3)); | |
| assertEquals(true, consList.contains(2)); | |
| } | |
| @Test | |
| public void testAddE() { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.add(4); | |
| List<Integer> expected = new ArrayList<Integer>(); | |
| expected.add(2); | |
| expected.add(3); | |
| expected.add(4); | |
| assertEquals(expected, consList); | |
| } | |
| @Test(expected=UnsupportedOperationException.class) | |
| public void testAddEException() { | |
| getThreeConstList().add(2); | |
| } | |
| @Test | |
| public void testRemoveObject() { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| assertEquals(false, consList.remove(Integer.valueOf(4))); | |
| assertEquals(true, consList.remove(Integer.valueOf(2))); | |
| List<Integer> anotherConsList = getTwoThreeMixList(); | |
| assertEquals(false, anotherConsList.remove(Integer.valueOf(4))); | |
| assertEquals(true, anotherConsList.remove(Integer.valueOf(3))); | |
| } | |
| @Test(expected=UnsupportedOperationException.class) | |
| public void testRemoveObjectException() { | |
| getThreeConstList().remove(Integer.valueOf(3)); | |
| } | |
| @Test(expected=UnsupportedOperationException.class) | |
| public void testRemoveObjectEmptyedException() { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| try { | |
| consList.remove(Integer.valueOf(2)); | |
| } catch (UnsupportedOperationException e) { | |
| fail("Premature exception. "); | |
| } | |
| consList.remove(Integer.valueOf(3)); | |
| } | |
| @Test | |
| public void testAddAllCollectionOfQextendsE() { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.addAll(getTwoThreeMixList()); | |
| List<Integer> expected = new ArrayList<Integer>(); | |
| expected.add(2); | |
| expected.add(3); | |
| expected.add(2); | |
| expected.add(3); | |
| assertEquals(expected, consList); | |
| } | |
| @Test | |
| public void testAddAllIntCollectionOfQextendsE() { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.addAll(1,getTwoThreeConstList()); | |
| List<Integer> expected = new ArrayList<Integer>(); | |
| expected.add(2); | |
| expected.add(2); | |
| expected.add(3); | |
| expected.add(3); | |
| assertEquals(expected, consList); | |
| } | |
| @Test | |
| public void testGetInt() { | |
| assertEquals(Integer.valueOf(3), getThreeConstList().get(0)); | |
| assertEquals(Integer.valueOf(2), getTwoThreeMixList().get(0)); | |
| assertEquals(Integer.valueOf(3), getTwoThreeMixList().get(1)); | |
| assertEquals(Integer.valueOf(2), getTwoThreeConstList().get(0)); | |
| assertEquals(Integer.valueOf(3), getTwoThreeConstList().get(1)); | |
| } | |
| @Test | |
| public void testSetIntE() { | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.set(0, 4); | |
| List<Integer> expected = new ArrayList<Integer>(); | |
| expected.add(4); | |
| expected.add(3); | |
| assertEquals(expected, consList); | |
| } | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.set(1, 4); | |
| List<Integer> expected = new ArrayList<Integer>(); | |
| expected.add(2); | |
| expected.add(4); | |
| assertEquals(expected, consList); | |
| } | |
| } | |
| @Test | |
| public void testAddIntE() { | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.add(0, 4); | |
| List<Integer> expected = new ArrayList<Integer>(); | |
| expected.add(4); | |
| expected.add(2); | |
| expected.add(3); | |
| assertEquals(expected, consList); | |
| } | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.add(1, 4); | |
| List<Integer> expected = new ArrayList<Integer>(); | |
| expected.add(2); | |
| expected.add(4); | |
| expected.add(3); | |
| assertEquals(expected, consList); | |
| } | |
| } | |
| @Test | |
| public void testRemoveInt() { | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.remove(0); | |
| assertEquals(getThreeImmutableList(), consList); | |
| } | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.remove(1); | |
| assertEquals(Collections.singletonList(2), consList); | |
| } | |
| } | |
| @Test(expected=UnsupportedOperationException.class) | |
| public void testRemoveIntUnsupportedOperationException() { | |
| getThreeConstList().remove(0); | |
| } | |
| @Test(expected=UnsupportedOperationException.class) | |
| public void testRemoveIntSecondaryUnsupportedOperationException() { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.remove(0); | |
| consList.remove(0); | |
| } | |
| @Test(expected=IndexOutOfBoundsException.class) | |
| public void testRemoveIntSecondaryIndexOutOfBoundsException() { | |
| getTwoThreeMixList().remove(2); | |
| } | |
| @Test | |
| public void testIndexOfObject() { | |
| assertEquals(0, getThreeConstList().indexOf(Integer.valueOf(3))); | |
| assertEquals(-1, getThreeConstList().indexOf(Integer.valueOf(4))); | |
| assertEquals(0, getTwoThreeMixList().indexOf(Integer.valueOf(2))); | |
| assertEquals(1, getTwoThreeMixList().indexOf(Integer.valueOf(3))); | |
| assertEquals(-1, getTwoThreeMixList().indexOf(Integer.valueOf(4))); | |
| assertEquals(0, getTwoThreeConstList().indexOf(Integer.valueOf(2))); | |
| assertEquals(1, getTwoThreeConstList().indexOf(Integer.valueOf(3))); | |
| assertEquals(-1, getTwoThreeConstList().indexOf(Integer.valueOf(4))); | |
| List<Integer> consList = new ConsList<Integer>(3, | |
| new ConsList<Integer>(3, null)); | |
| assertEquals(0, consList.indexOf(Integer.valueOf(3))); | |
| } | |
| @Test | |
| public void testLastIndexOfObject() { | |
| assertEquals(0, getThreeConstList().lastIndexOf(Integer.valueOf(3))); | |
| assertEquals(-1, getThreeConstList().lastIndexOf(Integer.valueOf(4))); | |
| assertEquals(0, getTwoThreeMixList().lastIndexOf(Integer.valueOf(2))); | |
| assertEquals(1, getTwoThreeMixList().lastIndexOf(Integer.valueOf(3))); | |
| assertEquals(-1, getTwoThreeMixList().lastIndexOf(Integer.valueOf(4))); | |
| assertEquals(0, getTwoThreeConstList().lastIndexOf(Integer.valueOf(2))); | |
| assertEquals(1, getTwoThreeConstList().lastIndexOf(Integer.valueOf(3))); | |
| assertEquals(-1, getTwoThreeConstList().lastIndexOf(Integer.valueOf(4))); | |
| List<Integer> consList = new ConsList<Integer>(3, | |
| new ConsList<Integer>(3, null)); | |
| assertEquals(1, consList.lastIndexOf(Integer.valueOf(3))); | |
| } | |
| @Test | |
| public void testSubListIntInt() { | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.add(4); | |
| List<Integer> expected = new ArrayList<Integer>(); | |
| expected.add(3); | |
| expected.add(4); | |
| assertEquals(expected, consList.subList(1, 3)); | |
| } | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| consList.add(4); | |
| assertEquals(getTwoThreeArrayList(), consList.subList(0, 2)); | |
| } | |
| } | |
| @Test | |
| public void testIterator() { | |
| { | |
| List<Integer> consList = getTwoThreeConstList(); | |
| Iterator<Integer> it = consList.iterator(); | |
| assertEquals(true, it.hasNext()); | |
| assertEquals(Integer.valueOf(2), it.next()); | |
| assertEquals(true, it.hasNext()); | |
| assertEquals(Integer.valueOf(3), it.next()); | |
| assertEquals(false, it.hasNext()); | |
| } | |
| { | |
| List<Integer> consList = getTwoThreeMixList(); | |
| Iterator<Integer> it = consList.iterator(); | |
| assertEquals(true, it.hasNext()); | |
| assertEquals(Integer.valueOf(2), it.next()); | |
| assertEquals(true, it.hasNext()); | |
| assertEquals(Integer.valueOf(3), it.next()); | |
| assertEquals(false, it.hasNext()); | |
| it.remove(); | |
| assertEquals(Collections.singletonList(2), consList); | |
| } | |
| } | |
| @Test(expected=UnsupportedOperationException.class) | |
| public void testIteratorException() { | |
| List<Integer> consList = getThreeConstList(); | |
| Iterator<Integer> it = consList.iterator(); | |
| assertEquals(true, it.hasNext()); | |
| assertEquals(Integer.valueOf(3), it.next()); | |
| assertEquals(false, it.hasNext()); | |
| it.remove(); | |
| } | |
| @Test | |
| public void testEqualsObject() { | |
| assertEquals(true, getThreeConstList().equals(getThreeImmutableList())); | |
| assertEquals(true, getTwoThreeMixList().equals(getTwoThreeArrayList())); | |
| assertEquals(true, getTwoThreeConstList().equals(getTwoThreeArrayList())); | |
| } | |
| @Test | |
| public void testToString() { | |
| assertEquals(getThreeImmutableList().toString(), | |
| getThreeConstList().toString()); | |
| assertEquals(getTwoThreeArrayList().toString(), | |
| getTwoThreeMixList().toString()); | |
| assertEquals(getTwoThreeArrayList().toString(), | |
| getTwoThreeConstList().toString()); | |
| } | |
| @Test(expected=UnsupportedOperationException.class) | |
| public void testRemoveAll() { | |
| getThreeConstList().removeAll(getThreeImmutableList()); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment