using System; using System.Collections.Generic; using System.Linq; namespace HeuristicLab.Problems.ProgramSynthesis { public static class ExpressionTable { public static readonly IReadOnlyDictionary StatelessExpressionTable; public static readonly IReadOnlyDictionary> StatefulExpressionFactory; public static readonly IReadOnlyList ExpressionNames; public static readonly int ExpressionCount; private static readonly Dictionary indexToNameTable = new Dictionary(); private static readonly Dictionary typeToNameTable = new Dictionary(); private static readonly Dictionary nameToTypeTable = new Dictionary(); private static readonly Dictionary> stackTypeToNamesTable = new Dictionary>(); private static readonly Dictionary> stackDependencyToNamesTable = new Dictionary>(); private static readonly Dictionary typeToAttributeTable = new Dictionary(); private static readonly List inExpressionTable = new List(); public static readonly IReadOnlyList StatelessExpressionTypes; public static readonly IReadOnlyList StatefulExpressionTypes; static ExpressionTable() { StatelessExpressionTypes = GetExpressionTypes(typeof(StatelessExpression)).ToList(); StatefulExpressionTypes = GetExpressionTypes(typeof(StatefulExpression<>)).ToList(); StatelessExpressionTable = GetStatelessExpressionTable(); StatefulExpressionFactory = GetStatefulExpressionFactory(); ExpressionNames = StatelessExpressionTable.Keys .Concat(StatefulExpressionFactory.Keys) .Where(t => typeToNameTable.ContainsKey(t)) .Select(type => typeToNameTable[type]) .ToList(); ExpressionCount = StatelessExpressionTable.Count + StatefulExpressionFactory.Count; } public static IReadOnlyDictionary IndexToNameTable { get { return indexToNameTable; } } public static IReadOnlyDictionary TypeToNameTable { get { return typeToNameTable; } } public static IReadOnlyDictionary NameToTypeTable { get { return nameToTypeTable; } } public static IReadOnlyList InExpressionTable { get { return inExpressionTable; } } public static IReadOnlyDictionary> StackTypeToNamesTable { get { return stackTypeToNamesTable; } } public static IReadOnlyDictionary> StackDependencyToNamesTable { get { return stackDependencyToNamesTable; } } public static IReadOnlyDictionary TypeToAttributeTable { get { return typeToAttributeTable; } } private static Dictionary GetStatelessExpressionTable() { var dictionary = new Dictionary(); foreach (var type in StatelessExpressionTypes) { var expression = Activator.CreateInstance(type) as Expression; var attribute = (PushExpressionAttribute)Attribute.GetCustomAttribute(type, typeof(PushExpressionAttribute)); typeToAttributeTable.Add(type, attribute); dictionary.Add(type, expression); indexToNameTable.Add(indexToNameTable.Keys.Count, attribute.Name); typeToNameTable.Add(type, attribute.Name); nameToTypeTable.Add(attribute.Name, type); if (attribute.IsInExpression) { // ReSharper disable once AssignNullToNotNullAttribute // ReSharper disable once PossibleInvalidOperationException inExpressionTable.Insert(attribute.InExpressionNr.Value - 1, expression); } if (!stackTypeToNamesTable.ContainsKey(attribute.StackType)) { stackTypeToNamesTable.Add(attribute.StackType, new List()); } stackTypeToNamesTable[attribute.StackType].Add(attribute.Name); var dependencies = attribute.StackType | attribute.AdditionalStackDependencies; if (!stackDependencyToNamesTable.ContainsKey(dependencies)) { stackDependencyToNamesTable.Add(dependencies, new List()); } stackDependencyToNamesTable[dependencies].Add(attribute.Name); } return dictionary; } private static Dictionary> GetStatefulExpressionFactory() { var dictionary = new Dictionary>(); foreach (var type in StatefulExpressionTypes) { // Make a NewExpression that calls the ctor var newExp = System.Linq.Expressions.Expression.New(type); // Create a lambda with the New expression as body var creator = System.Linq.Expressions.Expression.Lambda>(newExp).Compile(); var attribute = (PushExpressionAttribute)Attribute.GetCustomAttribute(type, typeof(PushExpressionAttribute)); typeToAttributeTable.Add(type, attribute); dictionary.Add(type, creator); // do not index hidden expressions like push expression in tables if (attribute.IsHidden) continue; indexToNameTable.Add(indexToNameTable.Keys.Count, attribute.Name); typeToNameTable.Add(type, attribute.Name); nameToTypeTable.Add(attribute.Name, type); if (!stackTypeToNamesTable.ContainsKey(attribute.StackType)) { stackTypeToNamesTable.Add(attribute.StackType, new List()); } stackTypeToNamesTable[attribute.StackType].Add(attribute.Name); var dependencies = attribute.StackType | attribute.AdditionalStackDependencies; if (!stackDependencyToNamesTable.ContainsKey(dependencies)) { stackDependencyToNamesTable.Add(dependencies, new List()); } stackDependencyToNamesTable[dependencies].Add(attribute.Name); } return dictionary; } private static IEnumerable GetExpressionTypes(Type baseType) { return from domainAssembly in AppDomain.CurrentDomain.GetAssemblies() from assemblyType in domainAssembly.GetTypes() where !assemblyType.IsAbstract && assemblyType.IsSubclass(baseType) && assemblyType.GetConstructor(Type.EmptyTypes) != null select assemblyType; } public static IReadOnlyList GetExpressionsByStackTypes(StackTypes allowedTypes) { return stackDependencyToNamesTable .Where(entry => (entry.Key & ~allowedTypes) == 0x0) .SelectMany(entry => entry.Value) .ToList(); } public static PushProgram GetProgram(IManagedPool pool, int[] index) { var expressions = new Expression[index.Length]; for (var i = 0; i < index.Length; i++) { expressions[i] = GetExpression(index[i]); } return PushProgram.Create(pool, expressions); } public static Expression GetExpression(int index) { return GetExpression(indexToNameTable[index]); } public static Expression GetExpression(Type type) { var name = TypeToNameTable[type]; return GetExpression(name); } public static Expression GetExpression(string name) { Expression expression; if (!TryGetStatelessExpression(name, out expression) && !TryGetStatefulExpression(name, out expression)) throw new InvalidOperationException(string.Format("Expression with name {0} not found", name)); return expression; } public static Expression GetStatelessExpression() where T : StatelessExpression { Expression expression; var type = typeof(T); if (StatelessExpressionTable.TryGetValue(type, out expression)) return expression; throw new NotSupportedException("Expression not supported: " + type.Name); } public static Expression GetStatelessExpression(string name) { Type type; Expression expression; if (NameToTypeTable.TryGetValue(name, out type) && StatelessExpressionTable.TryGetValue(type, out expression)) return expression; throw new NotSupportedException("Expression not supported: " + name); } public static bool TryGetStatelessExpression(string name, out Expression expression) { Type type; if (!NameToTypeTable.TryGetValue(name, out type) || !StatelessExpressionTable.TryGetValue(type, out expression)) { expression = null; return false; } return true; } public static Expression GetStatefulExpression() { return GetStatefulExpression(typeToNameTable[typeof(T)]); } public static Expression GetStatefulExpression(string name) { Type type; Func creator; if (NameToTypeTable.TryGetValue(name, out type) && StatefulExpressionFactory.TryGetValue(type, out creator)) { return creator(); } throw new NotSupportedException("Expression not supported: " + name); } public static bool TryGetStatefulExpression(string name, out Expression expression) { if (NameToTypeTable.ContainsKey(name)) { expression = StatefulExpressionFactory[NameToTypeTable[name]](); return true; } expression = default(Expression); return false; } } }