Skip to content

Instantly share code, notes, and snippets.

@bxt
Created September 27, 2012 16:34
Show Gist options
  • Select an option

  • Save bxt/3794990 to your computer and use it in GitHub Desktop.

Select an option

Save bxt/3794990 to your computer and use it in GitHub Desktop.
ConsList for Java, draft
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;
}
}
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