Skip to content

Instantly share code, notes, and snippets.

@volgar1x
Created August 22, 2012 23:15
Show Gist options
  • Save volgar1x/3430475 to your computer and use it in GitHub Desktop.
Save volgar1x/3430475 to your computer and use it in GitHub Desktop.
class Tree<TKey, TValue>
{
protected readonly Tree<TKey, TValue> parent;
protected readonly IDictionary<TKey, Tree<TKey, TValue>> children = new Dictionary<TKey, Tree<TKey, TValue>>();
public Tree(Tree<TKey, TValue> parent) {
this.parent = parent;
}
public Tree() {
this(null);
}
public Tree<TKey, TValue> Parent { get { return parent; } }
public TKey Key { get; set; }
public TValue Value { get; set; }
public TValue this[IEnumerable<TKey>] {
get {
return Get(value);
}
}
protected Tree<TKey, TValue> GetChildOrCreate(TKey key) {
Tree<TKey, TValue> child = children[key];
if (child == null) {
child = new Tree<TKey, TValue>(this);
children.Add(key, child);
}
return child;
}
public TValue Get(IEnumerable<TKey> keys) {
if (keys.Count() <= 0) {
return Value;
}
Tree<TKey, TValue> child = children[keys.First()];
if (child != null) {
return child.Get(keys.Skip(1)); // http://msdn.microsoft.com/en-us/library/bb358985.aspx
}
else if (parent != null) {
return parent.Value;
}
return null;
}
public Tree<TKey, TValue> Get(TKey key) {
return child[key];
}
public void Add(IEnumerable<TKey> keys, TValue value) {
TKey key = keys.First();
Tree<TKey, TValue> child = GetChildOrCreate(key);
if (keys.Count() > 0) {
child.Add(keys.Skip(1), value);
} else {
child.Value = value;
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
return new TreeEnumerator<TKey, TValue>(this);
}
public IEnumerable<KeyValuePair<TKey, TValue>> Enumerate() {
if (Key != null) {
yield return new KeyValuePair<TKey, TValue>(Key, Value);
}
foreach (KeyValuePair<TKey, Tree<TKey, TValue>> entry : children) {
entry.Enumerate();
}
}
}
class CompilableTree<TKey, TValue> : Tree<TKey, TValue> {
protected Expression KeyExpression {
get {
return Expression.Property(Expression.Constant(this), "Key");
}
}
protected Expression ValueExpression {
get {
return Expression.Property(Expression.Constant(this), "Value");
}
}
protected SwitchCase ToSwitchCase(Expression ret, Expression param, int level) {
if (Value != null) {
return Expression.SwitchCase(
Expression.Return(
ret,
ValueExpression
),
KeyExpression
);
} else {
return Expression.SwitchCase(
Compile(ret, param, level),
KeyExpression
);
}
}
private static readonly MethodInfo ELEMENT_AT =
typeof(Enumerable).GetMethod(
"ElementAt",
typeof(IEnumerable<TKey>),
typeof(int)
);
protected SwitchExpression Compile(Expression ret, Expression param, int level = 0) {
return Expression.Switch(
Expression.Call(ELEMENT_AT, param, level),
Expression.Return(ret, Expression.Constant(null)), // return null by default
children.Values.Select(x => x.ToSwitchCase(ret, param, level + 1)).ToArray()
);
}
public Func<IEnumerable<TKey>, TValue> Compile() {
Expression ret = Expression.Label(), param = Expression.Parameter(typeof(IEnumerable<TKey>));
Expression body = Compile(ret, e);
return Expression.Lambda<Func<IEnumerable<TKey>, TValue>>(body).Compile();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment