package org.pcollections;
import java.io.Serializable;
import java.util.AbstractSequentialList;
import java.util.Collection;
import java.util.Iterator;
import java.util.ListIterator;
public final class ConsPStack<E> extends AbstractSequentialList<E>
implements PStack<E>, Serializable {
private static final long serialVersionUID = 1L;
private static final ConsPStack<Object> EMPTY = new ConsPStack<Object>();
@SuppressWarnings("unchecked")
public static <E> ConsPStack<E> empty() {
return (ConsPStack<E>) EMPTY;
}
public static <E> ConsPStack<E> singleton(final E e) {
return ConsPStack.<E>empty().plus(e);
}
@SuppressWarnings("unchecked")
public static <E> ConsPStack<E> from(final Collection<? extends E> list) {
if (list instanceof ConsPStack)
return (ConsPStack<E>) list;
return ConsPStack.<E>from(list.iterator());
}
private static <E> ConsPStack<E> from(final Iterator<? extends E> i) {
if (!i.hasNext()) return empty();
E e = i.next();
return ConsPStack.<E>from(i).plus(e);
}
private final E first;
private final ConsPStack<E> rest;
private final int size;
private ConsPStack() {
if (EMPTY != null) throw new RuntimeException("empty constructor should only be used once");
size = 0;
first = null;
rest = null;
}
private ConsPStack(final E first, final ConsPStack<E> rest) {
this.first = first;
this.rest = rest;
size = 1 + rest.size;
}
@Override
public int size() {
return size;
}
@Override
public ListIterator<E> listIterator(final int index) {
if (index < 0 || index > size) throw new IndexOutOfBoundsException();
return new ListIterator<E>() {
int i = index;
ConsPStack<E> next = subList(index);
public boolean hasNext() {
return next.size > 0;
}
public boolean hasPrevious() {
return i > 0;
}
public int nextIndex() {
return i;
}
public int previousIndex() {
return i - 1;
}
public E next() {
E e = next.first;
next = next.rest;
i++;
return e;
}
public E previous() {
System.err.println("ConsPStack.listIterator().previous() is inefficient, don't use it!");
next = subList(--i);
return next.first;
}
public void add(final E o) {
throw new UnsupportedOperationException();
}
public void remove() {
throw new UnsupportedOperationException();
}
public void set(final E o) {
throw new UnsupportedOperationException();
}
};
}
@Override
public ConsPStack<E> subList(final int start, final int end) {
if (start < 0 || end > size || start > end) throw new IndexOutOfBoundsException();
if (start == end) return empty();
if (start > 0) return subList(start).subList(0, end - start);
if (end == size) return this;
ConsPStack<E> reversed = empty();
for (final E e : this) {
if (reversed.size == end) break;
reversed = reversed.plus(e);
}
return this.<E>empty().plusAll(reversed);
}
public ConsPStack<E> plus(final E e) {
return new ConsPStack<E>(e, this);
}
public ConsPStack<E> plusAll(final Collection<? extends E> list) {
ConsPStack<E> result = this;
for (E e : list) result = result.plus(e);
return result;
}
public ConsPStack<E> plus(final int i, final E e) {
return plusAll(i, singleton(e));
}
public ConsPStack<E> plusAll(final int i, final Collection<? extends E> list) {
if (i < 0 || i > size) throw new IndexOutOfBoundsException();
if (list.isEmpty()) return this;
ConsPStack<E> reversed = empty();
ConsPStack<E> suffix = this;
while (reversed.size < i) {
reversed = reversed.plus(suffix.first);
suffix = suffix.rest;
}
return suffix.plusAll(list).plusAll(reversed);
}
public ConsPStack<E> minus(final Object e) {
final int i = indexOf(e);
if (i == -1) return this;
return minus(i);
}
public ConsPStack<E> minus(final int i) {
if (i < 0 || i >= size) throw new IndexOutOfBoundsException("Index: " + i + "; size: " + size);
ConsPStack<E> reversed = empty();
ConsPStack<E> suffix = this;
while (reversed.size <= i) {
reversed = reversed.plus(suffix.first);
suffix = suffix.rest;
}
return suffix.plusAll(reversed.rest);
}
public ConsPStack<E> minusAll(final Collection<?> list) {
if (list.isEmpty()) return this;
ConsPStack<E> kept = empty();
ConsPStack<E> searching = this;
ConsPStack<E> reversed = kept;
ConsPStack<E> suffix = searching;
while (searching.size > 0) {
final E e = searching.first;
searching = searching.rest;
if (list.contains(e)) {
reversed = kept;
suffix = searching;
} else kept = kept.plus(e);
}
return suffix.plusAll(reversed);
}
public ConsPStack<E> with(final int i, final E e) {
if (i < 0 || i >= size) throw new IndexOutOfBoundsException();
ConsPStack<E> reversed = empty();
ConsPStack<E> suffix = this;
while (reversed.size <= i) {
reversed = reversed.plus(suffix.first);
suffix = suffix.rest;
}
return suffix.plus(e).plusAll(reversed.rest);
}
public ConsPStack<E> subList(int start) {
if (start < 0 || start > size) throw new IndexOutOfBoundsException();
ConsPStack<E> s = this;
while (start > 0) {
s = s.rest;
start--;
}
return s;
}
}