/*
* DoublyLinkedList.java
*
* Created on December 11, 2000, 2:24 PM
*/
package com.limegroup.gnutella.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* A classic doubly-linked list. Unlike the LinkedList class in the JDK, this
* provides way a way to refer to elements of the list (each of type ListElement)
* directly, avoiding linear-time searches when you wish to remove an element.
* This currently only has a minimal set of operations.<p>
*
* <b>This class is not thread-safe.</b> All the access to the list should be
* synchronized externally if required.
*
* @author Anurag Singla initial revision
* @author Christopher Rohrs bug fix, specification cleanup, and unit tests
*/
public class DoublyLinkedList
{
/*
* This linked list can be visualized as
* null<--start<-->e1<-->e2<-->...<-->en<-->last-->null,
* where e1, e2,...en are the stored elements in the list
*/
/**
* points to the first element in the list (thru its next element)
* INVARIANT: prev, & value fields are always null for this
*/
private ListElement start;
/**
* points to the last element in the list (thru its prev element)
* INVARIANT: next, & value fields are always null for this
*/
private ListElement last;
/** Creates new empty DoublyLinkedList */
public DoublyLinkedList()
{
//allocate space for both start & last pointers
//The prev & next fields will be pointing to null at this point
//in both the references
start = new ListElement(null);
last = new ListElement(null);
//since no elements right now, make start & last point to each other
start.next = last;
last.prev = start;
}
/**
* Inserts an object at the end of the list, returning its
* corresponding element.
* @param value the value of the new element.
* @return the element holding value.
*/
public ListElement addLast(Object value)
{
ListElement element=new ListElement(value);
//else insert at the end
element.prev = last.prev;
element.next = last;
element.prev.next = element;
last.prev = element;
return element;
}
/**
* Removes and returns the first element from the list
* @return The element removed, or null if none present
*/
public ListElement removeFirst()
{
//if no element in the list, return null
if(start.next == last)
return null;
//else store the element to be removed/returned
ListElement removed = start.next;
//adjust the pointers
start.next = start.next.next;
start.next.prev = start;
//return the removed element
return removed;
}
/**
* Removes the specified element from the list
* @param element The element to be removed. This must be an element
* of this.
*/
public void remove(ListElement element)
{
//if null element or invalid state, return false
//No element in the list is gonna have any of the pointers null
if(element == null || element.prev == null || element.next == null)
return;
//also start and last cant be removed
if(element == start || element == last)
return;
//adjust the pointers to remove the element from the list
element.prev.next = element.next;
element.next.prev = element.prev;
}
/**
* Removes all entries from this list
*/
public void clear()
{
//since no elements, make start & last point to each other
start.next = last;
last.prev = start;
}
/*
* Returns an iterator that yields the ListElement's in this,
* each once, in order, from head to tail. Call getValue() on
* each element to get the values in this.
* @requires this not modified while iterator in use.
*/
public Iterator iterator() {
return new DoublyLinkedListIterator();
}
/**
* Returns true if this contains the given ListElement.
*/
public boolean contains(ListElement e) {
for (Iterator iter=iterator(); iter.hasNext(); ) {
ListElement e2=(ListElement)iter.next();
if (e.equals(e2))
return true;
}
return false;
}
private class DoublyLinkedListIterator extends UnmodifiableIterator {
/** The next element to yield, or last if done. */
private ListElement next=start.next;
public boolean hasNext() {
return next!=last;
}
public Object next() {
if (! hasNext())
throw new NoSuchElementException();
ListElement ret=next;
next=next.next;
return ret;
}
}
/**
* An element of the linked list. Immutable.
*/
public static class ListElement
{
/**
* The key/object it stores
*/
Object key;
/**
* Refernce to the previous element in the list
*/
ListElement prev;
/**
* Refernce to the next element in the list
*/
ListElement next;
/**
* creates a new instance, with the specified key
* @param key The key/value to be stored in this list element
*/
ListElement(Object key)
{
//store the object
this.key = key;
//make both the forward & backward pointers null
prev = null;
next = null;
}
/**
* returns the key stored in this element
* @return the key stored in this element
*/
public Object getKey()
{
return key;
}
}//end of class ListElement
}