#region Copyright 2010-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
namespace CSharpTest.Net.Collections
{
///
/// A typed node, used similiarly to LinkedListNode<T>. Can belong to single list
/// at a time, the type of list is usually LListNode<T>.LList
///
///
public class LListNode : LListNode
{
/// Constructs a node without a value
public LListNode() { }
/// Constructs a node with a value
public LListNode(T value) { Value = value; }
/// Gets/Sets the value of this node
public T Value;
/// Returns the previous item in the list or null
public new LListNode Previous { get { return (LListNode)base.Previous; } }
/// Returns the next item in the list or null
public new LListNode Next { get { return (LListNode)base.Next; } }
/// Provides a linked list of nodes of type T
public new class LList : LList>
{
/// Adds the node to the front of the list
public void AddFirst(T value) { AddFirst(new LListNode(value)); }
/// Adds the node to the end of the list
public void AddLast(T value) { AddLast(new LListNode(value)); }
}
}
///
/// The basic Linked-list node, untyped, use LListNode<T> for strong typed nodes and lists.
///
public class LListNode
{
private LListNode _prev, _next;
///
/// You may derive an instance class from LListNode and use it in a single list, or you
/// may construct a node<T> with the value that the node should contain.
///
protected LListNode() { }
/// Returns the previous item in the list or null
public LListNode Previous { get { return _prev; } }
/// Returns the next item in the list or null
public LListNode Next { get { return _next; } }
/// Provides a linked list of nodes of type T
public class LList : LList { }
/// Provides a linked list of nodes of type T
public class LList : System.Collections.Generic.ICollection
where TNode : LListNode
{
int _count;
TNode _head, _tail;
/// Returns the number of items in the list
public int Count { get { return _count; } }
/// Returns true if the list is empty
public bool IsEmpty { get { return _head == null; } }
/// Returns the first node in the list
public TNode First { get { return _head; } }
/// Returns the last node in the list
public TNode Last { get { return _tail; } }
/// Adds the node to the front of the list
public void AddFirst(TNode value)
{
Check.Assert(value._prev == null && value._next == null);
value._prev = null;
value._next = _head;
if (_head != null) _head._prev = value;
_head = value;
_tail = _tail ?? value;
_count++;
}
/// Adds the node to the end of the list
public void AddLast(TNode value)
{
Check.Assert(value._prev == null && value._next == null);
value._next = null;
value._prev = _tail;
if (_tail != null) _tail._next = value;
_tail = value;
_head = _head ?? value;
_count++;
}
/// Remvoes the node from the list
public bool Remove(TNode value)
{
int removed = 0;
if (ReferenceEquals(_head, value) && ++removed > 0)
_head = (TNode)value._next;
if (value._next != null && ++removed > 0)
value._next._prev = value._prev;
if (ReferenceEquals(_tail, value) && ++removed > 0)
_tail = (TNode)value._prev;
if (value._prev != null && ++removed > 0)
value._prev._next = value._next;
value._next = value._prev = null;
_count--;
return removed > 0;
}
/// Remvoes all the nodes from the list
public void Clear()
{
foreach (TNode item in this)
item._next = item._prev = null;
_head = _tail = null;
_count = 0;
}
/// Returns an enumerator that iterates through the collection.
public System.Collections.Generic.IEnumerator GetEnumerator() { return new Enumerator, TNode>(this); }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new Enumerator, TNode>(this); }
void System.Collections.Generic.ICollection.Add(TNode item)
{ AddLast(item); }
bool System.Collections.Generic.ICollection.Contains(TNode item)
{
while (item._prev != null)
item = (TNode)item._prev;
return item == _head;
}
void System.Collections.Generic.ICollection.CopyTo(TNode[] array, int arrayIndex)
{
foreach (TNode node in this)
array[arrayIndex++] = node;
}
bool System.Collections.Generic.ICollection.IsReadOnly
{
get { return false; }
}
}
/// Provides a enumeration of the list where it is acceptable to remove current
private class Enumerator : System.Collections.Generic.IEnumerator
where TList : LList
where TNode : LListNode
{
TList _list;
TNode _current, _next;
/// Creates the enumeration on a list
public Enumerator(TList list)
{
_list = list;
_next = _list.First;
_current = null;
}
object System.Collections.IEnumerator.Current { get { return Current; } }
/// Returns the current node
public TNode Current
{
get
{
if (_list == null) throw new ObjectDisposedException(GetType().FullName);
if (_current == null) throw new InvalidOperationException();
return _current;
}
}
/// Disposes of the enumeration
public void Dispose() { _list = null; _next = _current = null; }
/// Moves to the next element or returns false
public bool MoveNext()
{
if (_list == null) throw new ObjectDisposedException(GetType().FullName);
_current = _next;
if (_current == null) return false;
_next = (TNode)_current._next;
return true;
}
/// Resets the enumeration back to the beginning of the list
public void Reset()
{
if (_list == null) throw new ObjectDisposedException(GetType().FullName);
_next = _list.First;
_current = null;
}
}
}
}