Skip to content

Instantly share code, notes, and snippets.

@Noxivs
Created October 22, 2013 16:57
Show Gist options
  • Save Noxivs/7104195 to your computer and use it in GitHub Desktop.
Save Noxivs/7104195 to your computer and use it in GitHub Desktop.
Compiled tree written in C#.Net
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Trees
{
public class CompilableTree<TKey, TValue>
{
protected readonly CompilableTree<TKey, TValue> _parent;
protected readonly IDictionary<TKey, CompilableTree<TKey, TValue>> _children;
protected readonly int _index;
public TKey Key { get; set; }
public TValue Value { get; set; }
public int Index
{
get
{
return _index;
}
}
protected Expression KeyExpression
{
get { return Expression.Property(Expression.Constant(this), "Key"); }
}
protected Expression ValueExpression
{
get { return Expression.Property(Expression.Constant(this), "Value"); }
}
public CompilableTree() : this(null, 0) { }
public CompilableTree(CompilableTree<TKey, TValue> parent, int index)
{
_parent = parent;
_children = new Dictionary<TKey, CompilableTree<TKey, TValue>>();
_index = index;
}
public Func<IEnumerable<TKey>, TValue> Compile()
{
ParameterExpression keysParameter = Expression.Parameter(typeof(IEnumerable<TKey>), "keys");
LabelTarget returnTarget = Expression.Label(typeof(TValue));
BlockExpression body;
if (_children.Count == 0)
{
body = Expression.Block(
Expression.Return(returnTarget, Expression.Default(typeof(TValue)), typeof(TValue)),
Expression.Label(returnTarget, Expression.Default(typeof(TValue)))
);
return
Expression.Lambda<Func<IEnumerable<TKey>, TValue>>(body, keysParameter).Compile();
}
body = Expression.Block(
Compile(returnTarget, keysParameter),
Expression.Label(returnTarget, Expression.Default(typeof(TValue)))
);
return Expression.Lambda<Func<IEnumerable<TKey>, TValue>>(body, keysParameter).Compile();
}
public virtual void Add(IList<TKey> keys, TValue value, bool replace = true)
{
if (_index - keys.Count >= 0)
{
if (replace)
Value = value;
}
else
{
TKey key = keys[_index];
CompilableTree<TKey, TValue> child;
if (!_children.TryGetValue(key, out child))
{
child = new CompilableTree<TKey, TValue>(this, _index + 1) {Key = key};
_children.Add(key, child);
}
child.Add(keys, value, replace);
}
}
protected SwitchExpression Compile(LabelTarget returnTarget, Expression keysParameter, int level = 0)
{
var switchValue = Expression.Call(
null,
typeof(Enumerable).GetMethod("ElementAt").MakeGenericMethod(typeof(TKey)),
keysParameter,
Expression.Constant(level, typeof(int))
);
var defaultCase = Expression.Return(returnTarget, Expression.Default(typeof(TValue)), typeof(TValue));
var switchCases = _children.Values.Select(x => x.ToSwitchCase(returnTarget, keysParameter, level + 1)).ToArray();
return Expression.Switch(
switchValue,
defaultCase,
switchCases
);
}
protected SwitchCase ToSwitchCase(LabelTarget returnTarget, Expression keysParameter, int level)
{
if (Value != null)
{
return Expression.SwitchCase(Expression.Return(returnTarget, Expression.Constant(Value), typeof(TValue)),
KeyExpression
);
}
else
{
return Expression.SwitchCase(
Compile(returnTarget, keysParameter, level),
KeyExpression
);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment