package freenet.support;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* DoublyLinkedList implementation. See DoublyLinkedList for an explanation
* when to use this.
*
* @author tavin
*
* TODO: there are still some unimplemented methods
* -- it remains to be seen if they are needed at all
*/
public class DoublyLinkedListImpl<T extends DoublyLinkedList.Item<? extends T>> implements DoublyLinkedList<T> {
protected int size;
protected T _firstItem, _lastItem;
//@Override
//public final DoublyLinkedListImpl<T> clone() {
// return new DoublyLinkedListImpl<T>(this);
//}
/**
* A new list with no items.
*/
public DoublyLinkedListImpl() {
clear();
}
protected DoublyLinkedListImpl(T _h, T _t, int size) {
_firstItem = _h;
_lastItem = _t;
T i = _firstItem;
while (i != null ) {
i.setParent(this);
i = i.getNext();
}
this.size = size;
}
// /**
// *
// * XXX: FIXME this doesn't really work. it use .clone() method
// *
// * @param impl
// */
// protected DoublyLinkedListImpl(DoublyLinkedListImpl<T> impl) {
// this();
// Enumeration<T> e = impl.forwardElements();
// boolean checked = false;
// for(;e.hasMoreElements();) {
// DoublyLinkedListImpl.Item oi = (DoublyLinkedListImpl.Item) e.nextElement();
// T i = (T) oi.clone();
// if(!checked) {
// checked = true;
// if(!i.getClass().getName().equals(oi.getClass().getName())) {
// System.err.println("Clone constructor failed for "+oi+": "+i);
// new Exception("error").printStackTrace();
// }
// }
// this.push(i);
// }
// }
//=== DoublyLinkedList implementation ======================================
/**
* {@inheritDoc}
*/
@Override
public void clear() {
// Help to detect removal after clear().
// The check in remove() is enough, strictly,
// as long as people don't add elements afterwards.
if (_firstItem == null)
return;
T pos = _firstItem;
T opos;
while(true) {
if(pos == null) break;
pos.setParent(null);
pos.setPrev(null);
opos = pos;
pos = pos.getNext();
opos.setNext(null);
}
_firstItem = _lastItem = null;
size = 0;
}
/**
* {@inheritDoc}
*/
@Override
public final int size() {
assert size != 0 || (_firstItem == null && _lastItem == null);
return size;
}
/**
* {@inheritDoc}
*/
@Override
public final boolean isEmpty() {
assert size != 0 || (_firstItem == null && _lastItem == null);
return size == 0;
}
/**
* {@inheritDoc}
* @see #forwardElements()
*/
@Override
public final Enumeration<T> elements() {
return forwardElements();
}
@Override
public boolean contains(T item) {
for(T i : this) {
if(i.equals(item))
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public final T head() {
return size == 0 ? null : _firstItem;
}
/**
* {@inheritDoc}
*/
@Override
public final T tail() {
return size == 0 ? null : _lastItem;
}
//=== methods that add/remove items at the head of the list ================
/**
* {@inheritDoc}
*/
@Override
public final void unshift(T i) {
insertNext(null, i);
}
/**
* {@inheritDoc}
*/
@Override
public final T shift() {
return size == 0 ? null : remove(_firstItem);
}
/**
* {@inheritDoc}
*/
@Override
public DoublyLinkedList<T> shift(int n) {
if (n > size) n = size;
if (n < 1) return new DoublyLinkedListImpl<T>();
T i = _firstItem;
for (int m = 0; m < n - 1; ++m)
i = i.getNext();
T newTailItem = i;
T newFirstItem = newTailItem.getNext();
newTailItem.setNext(null);
DoublyLinkedList<T> newlist = new DoublyLinkedListImpl<T>(_firstItem, newTailItem, n);
if (newFirstItem != null) {
newFirstItem.setPrev(null);
_firstItem = newFirstItem;
} else {
_firstItem = _lastItem = null;
}
size -= n;
return newlist;
}
//=== methods that add/remove items at the tail of the list ================
/**
* {@inheritDoc}
*/
@Override
public final void push(T i) {
insertPrev(null, i);
}
/**
* {@inheritDoc}
*/
@Override
public final T pop() {
return size == 0 ? null : remove(_lastItem);
}
/**
* {@inheritDoc}
*/
@Override
public DoublyLinkedList<T> pop(int n) {
if (n > size) n = size;
if (n < 1) return new DoublyLinkedListImpl<T>();
T i = _lastItem;
for (int m = 0; m < n - 1; ++m)
i = i.getPrev();
T newFirstItem = i;
T newLastItem = newFirstItem.getPrev();
newFirstItem.setPrev(null);
DoublyLinkedList<T> newlist = new DoublyLinkedListImpl<T>(newFirstItem, _lastItem, n);
if (newLastItem != null) {
newLastItem.setNext(null);
_lastItem = newLastItem;
} else
_firstItem = _lastItem = null;
size -= n;
return newlist;
}
//=== testing/looking at neighbor items ====================================
/**
* {@inheritDoc}
*/
@Override
public final boolean hasNext(T i) {
T next = i.getNext();
return next != null;
}
/**
* {@inheritDoc}
*/
@Override
public final boolean hasPrev(T i) {
T prev = i.getPrev();
return prev != null;
}
/**
* {@inheritDoc}
*/
@Override
public final T next(T i) {
T next = i.getNext();
return next;
}
/**
* {@inheritDoc}
*/
@Override
public final T prev(T i) {
T prev = i.getPrev();
return prev;
}
//=== insertion and removal of items =======================================
/**
* {@inheritDoc}
*/
@Override
public T remove(T i) {
if (i.getParent() == null || isEmpty())
return null; // not in list
if (i.getParent() != this)
throw new PromiscuousItemException(i, i.getParent());
T next = i.getNext();
T prev = i.getPrev();
if ((next == null) && (prev == null)) // only item in list
assert size == 1;
if (next == null) { // last item
assert _lastItem == i;
_lastItem = prev;
} else {
assert next.getPrev() == i;
next.setPrev(prev);
}
if (prev == null) { // first item
assert _firstItem == i;
_firstItem = next;
} else {
assert prev.getNext() == i;
prev.setNext(next);
}
i.setNext(null);
i.setPrev(null);
--size;
i.setParent(null);
return i;
}
/**
* {@inheritDoc}
*/
@Override
public void insertPrev(T i, T j) {
if (j.getParent() != null)
throw new PromiscuousItemException(j, j.getParent());
if ((j.getNext() != null) || (j.getPrev() != null))
throw new PromiscuousItemException(j);
if (i == null) {
// insert as tail
j.setPrev(_lastItem);
j.setNext(null);
j.setParent(this);
if (_lastItem != null) {
_lastItem.setNext(j);
_lastItem = j;
} else {
_firstItem = _lastItem = j;
}
++size;
} else {
// insert in middle
if (i.getParent() == null)
throw new PromiscuousItemException(i, i.getParent()); // different trace to make easier debugging
if (i.getParent() != this)
throw new PromiscuousItemException(i, i.getParent());
T prev = i.getPrev();
if (prev == null) {
if (i != _firstItem)
throw new VirginItemException(i);
_firstItem = j;
} else
prev.setNext(j);
j.setPrev(prev);
i.setPrev(j);
j.setNext(i);
j.setParent(this);
++size;
}
}
/**
* {@inheritDoc}
*/
@Override
public void insertNext(T i, T j) {
if (j.getParent() != null)
throw new PromiscuousItemException(j, i.getParent());
if ((j.getNext() != null) || (j.getPrev() != null))
throw new PromiscuousItemException(j);
if (i == null) {
// insert as head
j.setPrev(null);
j.setNext(_firstItem);
j.setParent(this);
if (_firstItem != null) {
_firstItem.setPrev(j);
_firstItem = j;
} else {
_firstItem = _lastItem = j;
}
++size;
} else {
if (i.getParent() != this)
throw new PromiscuousItemException(i, i.getParent());
T next = i.getNext();
if (next == null) {
if (i != _lastItem)
throw new VirginItemException(i);
_lastItem = j;
} else
next.setPrev(j);
j.setNext(next);
i.setNext(j);
j.setPrev(i);
j.setParent(this);
++size;
}
}
//=== Walkable implementation ==============================================
/**
* @return an Enumeration of list elements from head to tail
*/
private Enumeration<T> forwardElements() {
return new ForwardWalker();
}
/**
* @return an Enumeration of list elements from tail to head
*/
public Enumeration<T> reverseElements() {
return new ReverseWalker();
}
private class ForwardWalker implements Enumeration<T> {
protected T next;
protected ForwardWalker() {
next = _firstItem;
}
@Override
public final boolean hasMoreElements() {
return next != null;
}
@Override
public T nextElement() {
if (next == null)
throw new NoSuchElementException();
T result = next;
next = next.getNext();
return result;
}
}
private class ReverseWalker implements Enumeration<T> {
protected T next;
protected ReverseWalker() {
next = _lastItem;
}
@Override
public final boolean hasMoreElements() {
return next != null;
}
@Override
public T nextElement() {
if (next == null)
throw new NoSuchElementException();
T result = next;
if(next == null) throw new IllegalStateException("next==null");
next = next.getPrev();
return result;
}
}
//=== list element ====================================================
public static class Item<T extends DoublyLinkedListImpl.Item<?>> implements DoublyLinkedList.Item<T> {
private T prev;
private T next;
private DoublyLinkedList<? super T> list;
// @Override
// public T clone() {
// if(getClass() != Item.class)
// throw new RuntimeException("Must implement clone() for "+getClass());
// return (T) new Item<T>();
// }
@Override
public final T getNext() {
return next;
}
@Override
@SuppressWarnings("unchecked")
public final T setNext(DoublyLinkedList.Item<?> i) {
T old = next;
next = (T) i;
return old;
}
@Override
public final T getPrev() {
return prev;
}
@Override
@SuppressWarnings("unchecked")
public final T setPrev(DoublyLinkedList.Item<?> i) {
T old = prev;
prev = (T) i;
return old;
}
@Override
public DoublyLinkedList<? super T> getParent() {
return list;
}
@Override
public DoublyLinkedList<? super T> setParent(DoublyLinkedList<? super T> l) {
DoublyLinkedList<? super T> old = list;
list = l;
return old;
}
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private Enumeration<T> e = forwardElements();
@Override
public boolean hasNext() {
return e.hasMoreElements();
}
@Override
public T next() {
if(!hasNext())
throw new NoSuchElementException();
return e.nextElement();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}