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 } } }