using System;
using System.Collections;
using System.Collections.Generic;
namespace Chernobyl.Collections.Generic
{
///
/// An that iterates through instances of types
/// that are structured like a linked list. i.e., the type contains an
/// instance to another instance of the same type. For example:
///
/// public class Foobar
/// {
/// public Foobar NextFoo { get; set; }
/// }
///
///
/// The type that contains an instance of it's
/// own type (a class that acts as a node in a linked list).
public class LinkedEnumerator : IEnumerator
{
///
/// Initializes a new instance of the
/// class.
///
/// The inclusive node to start from (it will
/// become the first value of .
/// A method that returns the next item for the
/// current instance. The current instance is passed into the method as
/// the first argument and the second argument is for returning the next
/// instance. False is to be returned if there is no next item, true if
/// the next item set on the second parameter is a valid instance.
public LinkedEnumerator(T start, NextItem getNextItem)
{
Start = start;
GetNextItem = getNextItem;
Reset();
}
///
/// Gets the element in the collection at the current position of the
/// enumerator.
///
/// The element in the collection at the current position of
/// the enumerator.
public T Current
{
get
{
if (Started == false)
throw new InvalidOperationException("The enumerator is " +
"positioned before the first element of the collection " +
"Make sure the MoveNext() method has been called. ");
if (Finished == true)
throw new InvalidOperationException("The enumerator is " +
"positioned after the last element of the collection " +
"Make sure to call Reset() to before restarting the iteration. ");
return _current;
}
private set { _current = value; }
}
///
/// Performs application-defined tasks associated with freeing, releasing,
/// or resetting unmanaged resources.
///
public void Dispose()
{ /* Does nothing */ }
///
/// Gets the element in the collection at the current position of the
/// enumerator.
///
/// The element in the collection at the current position of
/// the enumerator.
object IEnumerator.Current
{
get { return Current; }
}
///
/// Advances the enumerator to the next element of the collection.
///
///
/// true if the enumerator was successfully advanced to the next element;
/// false if the enumerator has passed the end of the collection.
///
/// The collection was
/// modified after the enumerator was created.
public bool MoveNext()
{
bool result = false;
if (Started == false)
{
result = Started = true;
Current = Start;
}
else
{
// GetNextItem will return false if we are finished, true if otherwise
Finished = !GetNextItem(Current, out _current);
result = !Finished;
}
return result;
}
///
/// Sets the enumerator to its initial position, which is before the
/// first element in the collection.
///
/// The collection was
/// modified after the enumerator was created.
public void Reset()
{
Current = Start;
Started = false;
Finished = false;
}
///
/// Represents a method that is used to retrieve the next item in a
/// linked set of instances.
///
/// The current item that was enumerated over.
/// The instance that is to take the result of the
/// next item to enumerate through.
/// False if there is no next item, true if the next item set
/// on is valid.
public delegate bool NextItem(T current, out T next);
///
/// A method that returns the next item for the current instance. The
/// current instance is passed into the method as the first argument and
/// the second argument is for returning the next instance. False is to
/// be returned if there is no next item, true if the next item set
/// on the second parameter is a valid instance.
///
NextItem GetNextItem { get; set; }
///
/// The inclusive node to start from (it will become the first value of
/// .
///
T Start { get; set; }
///
/// True if this has started iterating
/// ( has been called), false if we haven't
/// started.
///
protected bool Started { get; set; }
///
/// True if the end of the resource processing chain has been reached,
/// false if otherwise.
///
bool Finished { get; set; }
///
/// Backing field to .
///
T _current;
}
}