using System;
namespace System.Collections
{
class Node
{
internal Node _prev;
internal Node _next;
internal object _data;
internal bool _valid = true;
}
///
/// A double linked list.
///
///
/// This class does not invalidate the enumerators when changed except when the
/// enumerator points to a node that is removed.
///
public class DoubleLinkedList
: ICollection
{
private int _count;
internal Node _head;
internal Node _tail;
///
/// Constructs an empty list.
///
public DoubleLinkedList()
{
}
///
/// Adds an element at the head of the list.
///
/// The element to be added.
public void AddHead(object o)
{
Node n = new Node();
n._prev = null;
if(_head != null)
_head._prev = n;
n._next = _head;
n._data = o;
_head = n;
if(_tail == null)
_tail = n;
_count++;
}
///
/// Adds an element at the back of the list.
///
/// The element to be added.
public void AddTail(object o)
{
Node n = new Node();
if(_tail != null)
_tail._next = n;
n._prev = _tail;
n._next = null;
n._data = o;
_tail = n;
if(_head == null)
_head = n;
_count++;
}
///
/// Gets or sets the first element of the list.
///
public object Head
{
get
{
return _head._data;
}
set
{
_head._data = value;
}
}
///
/// Gets or sets the last element of the list.
///
public object Tail
{
get
{
return _tail._data;
}
set
{
_tail._data = value;
}
}
///
/// Removes the first element of the list.
///
/// The data stored at the now-removed head.
public object RemoveHead()
{
if(_count <= 0)
throw new InvalidOperationException(
"Can't remove an element of an empty list");
if(_head._next != null)
_head._next._prev = null;
else
_tail = null;
Node n = _head;
_head = _head._next;
n._next = null;
object o = n._data;
n._data = null;
n._valid = false;
_count--;
return o;
}
///
/// Removes the last element of the list.
///
/// The data stored at the now-removed tail.
public object RemoveTail()
{
if(_count <= 0)
throw new InvalidOperationException(
"Can't remove an element of an empty list");
if(_tail._prev != null)
_tail._prev._next = null;
else
_head = null;
Node n = _tail;
_tail = _tail._prev;
n._prev = null;
object o = n._data;
n._data = null;
n._valid = false;
_count--;
return o;
}
///
/// Removes the element an enumerator points to. Invalidates the enumerator.
///
/// The enumerator that points to the element that should be removed.
/// Must be a DoLiLiEnumerator, otherwise the function throws an exception.
public void RemoveAt(IEnumerator i)
{
if(_count <= 0)
throw new InvalidOperationException(
"Can't remove an element of an empty list");
try
{
DoLiLiEnumerator e = (DoLiLiEnumerator)i;
if(e._list != this)
throw new ArgumentException(
"Enumerator does not belong to the collection", "i");
RemoveNode(e._node);
}
catch(InvalidCastException e)
{
throw new ArgumentException(
"Enumerator does not belong to the collection", "i", e);
}
}
///
/// Searches and removes a node from the list.
///
/// The object to remove.
public void Remove(object o)
{
for(Node n = _head; n != null; n = n._next)
{
if(n._data == o)
{
RemoveNode(n);
break;
}
}
}
private void RemoveNode(Node n)
{
if(n._next != null)
n._next._prev = n._prev;
if(n._prev != null)
n._prev._next = n._next;
if(_head == n)
_head = n._next;
if(_tail == n)
_tail = n._prev;
n._next = null;
n._prev = null;
n._data = null;
n._valid = false;
_count--;
}
#region ICollectionImpl
///
/// Gets the number of elements in the list.
///
public int Count
{
get
{
return _count;
}
}
///
/// Returns true if this list is synchronized (thread-safe).
/// Always returns false;
///
public bool IsSynchronized
{
get
{
return false;
}
}
///
/// Returns an object to synchronize on.
/// Always returns null.
///
public object SyncRoot
{
get
{
return null;
}
}
public void CopyTo(Array array, int index)
{
if(array == null)
throw new ArgumentNullException("array");
if(index < 0)
throw new ArgumentOutOfRangeException("index");
if(array.Rank > 1 || index > array.GetLength(0)
|| _count > array.GetLength(0)-index)
throw new ArgumentException();
// This satisfies the last exception requirement of CopyTo.
foreach(object o in this)
{
array.SetValue(o, index++);
}
}
#endregion
#region IEnumerableImpl
///
/// Obtains an enumerator for this list.
///
/// An IEnumerator that points to a DoLiLiEnumerator.
public IEnumerator GetEnumerator()
{
return new DoLiLiEnumerator(this);
}
#endregion
///
/// An enumerator for a double linked list.
///
public class DoLiLiEnumerator
: IEnumerator
{
internal DoubleLinkedList _list;
internal Node _node;
///
/// Constructs a new enumerator for a list.
///
/// The list to enumerate.
public DoLiLiEnumerator(DoubleLinkedList list)
{
_list = list;
}
#region IEnumeratorImpl
///
/// Gets the element the enumerator points to.
/// This implementation supports set. This sets the data at the current node.
///
public object Current
{
get
{
if(_node == null || !_node._valid)
throw new InvalidOperationException("Enumerator invalid");
return _node._data;
}
set
{
if(_node == null || !_node._valid)
throw new InvalidOperationException("Enumerator invalid");
_node._data = value;
}
}
///
/// Advances the enumerator.
///
/// true if the enumerator is still valid.
public bool MoveNext()
{
if(_node == null)
_node = _list._head;
else
_node = _node._next;
return _node != null;
}
///
/// Resets the enumerator to the start of the list.
///
public void Reset()
{
_node = null;
}
#endregion
}
}
}