using System;
using System.Collections.Generic;
// collection class with the following operations:
// * add object
// * iterate collection using foreach statement
// * remove current object from within iteration
// when removing objects while iterating, the following conditions are assured:
// * no elements that are still in the collection are left out
// * no elements that are no longer in the collection are iterated
// * no element is iterated twice
// * in case of nested iterations of the collection, all this is true for each of them
// calling GetEnumerator explicitely is not recommended
// never iterate from multiple threads at the same time
namespace Common
{
///
/// Simple collection class which can be changed from within iteration.
///
/// type of collected objects
class ToughSet : IEnumerable
{
List list = new List();
List> enumerators = new List>(4); // list will rarely have more than 1 element
///
/// Creates an empty collection.
///
public ToughSet() { }
///
/// Number of elements contained in the collection.
///
public int Count { get { return list.Count; } }
///
/// Adds an object to the collection.
///
/// The object to be added.
public void Add(T item) { list.Add(item); }
///
/// Removes the current object of an iteration from the collection. Can only be called from within foreach loop.
///
public void RemoveCurrent()
{
if (enumerators.Count == 0)
throw new Exception("ToughSet.Remove() can only be called from within foreach loop!");
Enumerator innerEnumerator = enumerators[enumerators.Count - 1];
if (!innerEnumerator.currentWasRemoved)
{
int removeIndex = innerEnumerator.index;
if (removeIndex >= 0 && removeIndex < list.Count)
{
list.RemoveAt(removeIndex);
foreach (Enumerator enumerator in enumerators)
enumerator.RemoveAt(removeIndex);
}
}
}
void EnumerationEnded(Enumerator enumerator) // parameter is only for proof of correctness
{
if (enumerators.Count == 0)
throw new Exception("Error in ToughSet: Only started foreach loop can end!");
Enumerator innerEnumerator = enumerators[enumerators.Count - 1];
if (enumerator != innerEnumerator)
throw new Exception("Error in ToughSet: Only most inner foreach loop can end!");
enumerator.DisposeEvent -= EnumerationEnded;
enumerators.RemoveAt(enumerators.Count - 1);
}
#region IEnumerable members
class Enumerator : IEnumerator
{
ToughSet parent;
public int index;
public bool currentWasRemoved = false;
TEn current;
public Enumerator(ToughSet parent)
{
this.parent = parent;
index = -1;
}
public void RemoveAt(int removeIndex)
{
if (removeIndex == index)
currentWasRemoved = true;
if (removeIndex <= index)
index--;
}
public delegate void DisposeEventHandler(Enumerator enumerator);
public event DisposeEventHandler DisposeEvent;
#region IEnumerator Members
public void Reset() { index = -1; }
public TEn Current { get { return current; } }
object System.Collections.IEnumerator.Current { get { return current; } }
public void Dispose() { DisposeEvent(this); }
public bool MoveNext()
{
index++;
if (index < parent.list.Count)
{
current = parent.list[index];
currentWasRemoved = false;
return true;
}
else
return false;
}
#endregion
}
public IEnumerator GetEnumerator()
{
Enumerator enumerator = new Enumerator(this);
enumerators.Add(enumerator);
enumerator.DisposeEvent += EnumerationEnded;
return enumerator;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
#endregion
}
}
/*
class was tested with the following code:
ToughSet ts = new ToughSet();
for (int i = 0; i < 20; i++)
ts.Add(i);
foreach (int i in ts)
{ // should iterate 0-1-2-3-5-6-7-8-9-11-13-14-15-16-17
if (i == 3)
{
foreach (int j in ts)
{
if (j == 1 || j == 4 || j ==12)
ts.Remove();
if (j == 14)
break;
}
}
if (i == 9)
{
foreach (int j in ts)
{
if (j == 0 || j == 9 || j == 10)
ts.Remove();
if (j == 16)
break;
}
}
if (i == 8 || i == 9 || i == 16)
ts.Remove();
if (i == 17)
break;
}
foreach (int i in ts)
{ // should iterate 2-3-5-6-7-11-13-14-15-17-18-19
}
ts.Remove(); // should throw exception
*/