Skip to content

Instantly share code, notes, and snippets.

@jnm2
Created May 2, 2015 20:18
Show Gist options
  • Save jnm2/21efb048c94c23837598 to your computer and use it in GitHub Desktop.
Save jnm2/21efb048c94c23837598 to your computer and use it in GitHub Desktop.
Gives foreach recursive abilities without recursive calls
using System;
using System.Collections.Generic;
using System.ComponentModel;
public sealed class StackEnumerator<T> : IDisposable
{
private readonly Stack<IEnumerator<T>> stack = new Stack<IEnumerator<T>>();
private IEnumerator<T> current;
public bool MoveNext()
{
while (!current.MoveNext())
{
current.Dispose();
if (stack.Count == 0) return false;
current = stack.Pop();
}
return true;
}
public T Current
{
get { return current.Current; }
}
public void Recurse(IEnumerator<T> newCurrent)
{
stack.Push(current);
current = newCurrent;
}
public void Recurse(IEnumerable<T> newCurrent)
{
Recurse(newCurrent.GetEnumerator());
}
public StackEnumerator(IEnumerator<T> initial)
{
current = initial;
}
public StackEnumerator(IEnumerable<T> initial) : this(initial.GetEnumerator())
{
}
public StackEnumerator(T initial) : this(new[] { initial })
{
}
// Foreach support
[EditorBrowsable(EditorBrowsableState.Never)]
public StackEnumerator<T> GetEnumerator()
{
return this;
}
public void Dispose()
{
current.Dispose();
foreach (var item in stack)
item.Dispose();
stack.Clear();
}
}
public sealed class StackEnumerator<TContext, T> : IDisposable
{
public struct ContextCurrent
{
private readonly TContext context;
public TContext Context { get { return context; } }
private readonly T current;
public T Current { get { return current; } }
public ContextCurrent(TContext context, T current)
{
this.context = context;
this.current = current;
}
}
private readonly Stack<Tuple<TContext, IEnumerator<T>>> stack = new Stack<Tuple<TContext, IEnumerator<T>>>();
private Tuple<TContext, IEnumerator<T>> current;
public bool MoveNext()
{
while (!current.Item2.MoveNext())
{
current.Item2.Dispose();
if (stack.Count == 0) return false;
current = stack.Pop();
}
return true;
}
public ContextCurrent Current
{
get { return new ContextCurrent(current.Item1, current.Item2.Current); }
}
public void Recurse(TContext newContext, IEnumerator<T> newCurrent)
{
stack.Push(current);
current = Tuple.Create(newContext, newCurrent);
}
public void Recurse(TContext newContext, IEnumerable<T> newCurrent)
{
Recurse(newContext, newCurrent.GetEnumerator());
}
public void Recurse(TContext newContext, T newCurrent)
{
Recurse(newContext, new[] { newCurrent });
}
public StackEnumerator(TContext initialContext, IEnumerator<T> initial)
{
current = Tuple.Create(initialContext, initial);
}
public StackEnumerator(TContext initialContext, IEnumerable<T> initial) : this(initialContext, initial.GetEnumerator())
{
}
public StackEnumerator(TContext initialContext, T initial) : this(initialContext, new[] { initial })
{
}
// Foreach support
[EditorBrowsable(EditorBrowsableState.Never)]
public StackEnumerator<TContext, T> GetEnumerator()
{
return this;
}
public void Dispose()
{
current.Item2.Dispose();
foreach (var item in stack)
item.Item2.Dispose();
stack.Clear();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment