Changeset 1494


Ignore:
Timestamp:
04/03/09 11:33:59 (12 years ago)
Author:
epitzer
Message:

Generic decomposers for number arrays and number enumerables that "decompose" into a single string. (#563)

Location:
trunk/sources
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Persistence.Test/NewSerializationTest.cs

    r1475 r1494  
    1212
    1313namespace HeuristicLab.Persistence.Test {
     14
     15  public class StringDecomposerTest {
     16    [Storable] private bool _bool = true;
     17    [Storable] private byte _byte = 0xFF;
     18    [Storable] private sbyte _sbyte = 0xF;
     19    [Storable] private short _short = -123;
     20    [Storable] private ushort _ushort = 123;
     21    [Storable] private int _int = -123;
     22    [Storable] private uint _uint = 123;
     23    [Storable] private long _long = 123456;
     24    [Storable] private ulong _ulong = 123456;
     25    [Storable] private long[,] _long_array =
     26      new long[,] { { 123, 456, },  {789, 123 }} ;
     27    [Storable] public List<int> list = new List<int>{ 1, 2, 3, 4, 5};
     28  }
    1429
    1530  public enum TestEnum { va1, va2, va3, va8 } ;
     
    218233    }   
    219234
     235   
     236
     237    public static void Test5() {
     238      StringDecomposerTest sdt = new StringDecomposerTest();     
     239      XmlGenerator.Serialize(sdt, "test5.zip");
     240      object o = XmlParser.DeSerialize("test5.zip");
     241      Console.WriteLine(ViewOnlyGenerator.Serialize(sdt));
     242      Console.WriteLine(ViewOnlyGenerator.Serialize(o));
     243    }
     244
    220245    public class Base {
    221246      [Storable] private int baseInt = 3;     
     
    233258      Test3();
    234259      Test4();
     260      Test5();
    235261      //SpeedTest();
    236262      //SpeedTest2();
  • trunk/sources/HeuristicLab.Persistence/Core/DeSerializer.cs

    r1454 r1494  
    4949      var map = new Dictionary<Type, object>();
    5050      foreach (var typeMapping in typeCache) {
    51         Type type = Type.GetType(typeMapping.TypeName);
     51        Type type = Type.GetType(typeMapping.TypeName, true);
    5252        typeIds.Add(typeMapping.Id, type);
    5353        if (typeMapping.Serializer != null) {
  • trunk/sources/HeuristicLab.Persistence/Default/Decomposers/X2StringDecomposer.cs

    r1476 r1494  
    33using HeuristicLab.Persistence.Core;
    44using System.Collections.Generic;
     5using System.Reflection;
     6using System.Globalization;
     7using System.Text;
     8using System.Collections;
    59
    610namespace HeuristicLab.Persistence.Default.Decomposers {
    7  
    8   public class Int2StringDecomposer : IDecomposer {
    9 
    10     public bool CanDecompose(Type type) {
    11       return type == typeof (int);
    12     }
    13 
    14     public IEnumerable<Tag> DeCompose(object obj) {
    15       yield return new Tag(obj.ToString());
     11
     12  public class Number2StringDecomposer : IDecomposer {
     13
     14    private static readonly List<Type> numberTypes =
     15      new List<Type> {
     16        typeof(bool),
     17        typeof(byte),
     18        typeof(sbyte),
     19        typeof(short),
     20        typeof(ushort),
     21        typeof(int),
     22        typeof(uint),
     23        typeof(long),
     24        typeof(ulong),
     25        typeof(float),
     26        typeof(double),
     27        typeof(decimal),
     28      };
     29
     30    private static readonly Dictionary<Type, MethodInfo> numberParser; 
     31
     32    static Number2StringDecomposer() {
     33      numberParser = new Dictionary<Type, MethodInfo>();
     34      foreach ( var type in numberTypes ) {
     35        numberParser[type] = type
     36          .GetMethod("Parse", BindingFlags.Static | BindingFlags.Public,
     37                     null, new[] {typeof (string)}, null);         
     38      }
     39    }
     40
     41    public bool CanDecompose(Type type) {
     42      return numberParser.ContainsKey(type);
     43    }
     44
     45    public string SimpleDecompose(object obj) {
     46      if (obj.GetType() == typeof(float))       
     47        return ((float)obj).ToString("r", CultureInfo.InvariantCulture);
     48      else if (obj.GetType() == typeof(double))
     49        return ((double)obj).ToString("r", CultureInfo.InvariantCulture);
     50      else if (obj.GetType() == typeof(decimal))
     51        return ((decimal)obj).ToString("r", CultureInfo.InvariantCulture);
     52      else
     53        return obj.ToString();     
     54    }
     55
     56    public IEnumerable<Tag> DeCompose(object obj) {     
     57      yield return new Tag(SimpleDecompose(obj));     
    1658    }
    1759
     
    2062    }
    2163
    22     public object Populate(object instance, IEnumerable<Tag> tags, Type type) {
    23       foreach ( Tag tag in tags ) {
    24         return int.Parse((string) tag.Value);
    25       }
    26       throw new ApplicationException("Not enough components to compose an integer.");
    27     }
    28    
    29   }
    30 
    31   public class Long2StringDecomposer : IDecomposer {
    32 
    33     public bool CanDecompose(Type type) {
    34       return type == typeof(long);
    35     }
    36 
    37     public IEnumerable<Tag> DeCompose(object obj) {
    38       yield return new Tag(obj.ToString());
    39     }
    40 
    41     public object CreateInstance(Type type) {
    42       return null;
    43     }
    44 
    45     public object Populate(object instance, IEnumerable<Tag> tags, Type type) {
    46       foreach (Tag tag in tags) {
    47         return long.Parse((string)tag.Value);
    48       }
    49       throw new ApplicationException("Not enough components to compose an integer.");
    50     }
    51 
    52   }
    53 
    54   public class Double2StringDecomposer : IDecomposer {
    55 
    56     public bool CanDecompose(Type type) {
    57       return type == typeof (double);
    58     }
    59 
    60     public IEnumerable<Tag> DeCompose(object obj) {
    61       yield return new Tag(((double)obj).ToString("r"));
    62     }
    63 
    64     public object CreateInstance(Type type) {
    65       return null;
    66     }
    67 
    68     public object Populate(object instance, IEnumerable<Tag> tags, Type type) {
    69       foreach (Tag tag in tags) {
    70         return double.Parse((string)tag.Value);
    71       }
    72       throw new ApplicationException("Not enough components to compose a double.");
    73     }
    74 
    75   }
    76 
    77   public class Bool2StringDecomposer : IDecomposer {
    78 
    79     public bool CanDecompose(Type type) {
    80       return type == typeof(bool);
    81     }
    82 
    83     public IEnumerable<Tag> DeCompose(object obj) {
    84       yield return new Tag(obj.ToString());
    85     }
    86 
    87     public object CreateInstance(Type type) {
    88       return null;
    89     }
    90 
    91     public object Populate(object instance, IEnumerable<Tag> tags, Type type) {
    92       foreach (Tag tag in tags) {
    93         return bool.Parse((string) tag.Value);
    94       }
    95       throw new ApplicationException("Not enough components to compose a bool.");
    96     }
    97 
    98   }
     64    public object Parse(string stringValue, Type type) {
     65      return numberParser[type]
     66        .Invoke(null,
     67            BindingFlags.Static | BindingFlags.PutRefDispProperty,
     68                  null, new[] {stringValue}, CultureInfo.InvariantCulture);
     69    }
     70
     71    public object Populate(object instance, IEnumerable<Tag> tags, Type type) {     
     72      foreach (Tag tag in tags)
     73        return Parse((string)tag.Value, type);
     74      throw new ApplicationException("not enough tags to re-compose number.");
     75    }
     76
     77  } 
    9978
    10079  public class DateTime2StringDecomposer : IDecomposer {
     
    121100  } 
    122101
     102  public class CompactNumberArray2StringDecomposer : IDecomposer {
     103   
     104    private static readonly Number2StringDecomposer numberDecomposer =
     105      new Number2StringDecomposer();   
     106
     107    public bool CanDecompose(Type type) {
     108      return
     109        (type.IsArray || type == typeof (Array)) &&
     110        numberDecomposer.CanDecompose(type.GetElementType());
     111    }
     112
     113    public IEnumerable<Tag> DeCompose(object obj) {
     114      Array a = (Array) obj;
     115      StringBuilder sb = new StringBuilder();
     116      sb.Append(a.Rank).Append(';');     
     117      for ( int i = 0; i<a.Rank; i++ )
     118        sb.Append(a.GetLength(i)).Append(';');
     119      for ( int i = 0; i<a.Rank; i++)
     120        sb.Append(a.GetLowerBound(i)).Append(';');
     121      foreach (var number in a) {       
     122        sb.Append(numberDecomposer.SimpleDecompose(number)).Append(';');
     123      }
     124      yield return new Tag("compact array", sb.ToString());
     125    }
     126
     127    public object CreateInstance(Type type) {
     128      return null;
     129    }
     130
     131    public object Populate(object instance, IEnumerable<Tag> tags, Type type) {     
     132      var iter = tags.GetEnumerator();
     133      iter.MoveNext();
     134      var it = ((string) iter.Current.Value).Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries).GetEnumerator();
     135      it.MoveNext();
     136      int rank = int.Parse((string) it.Current);
     137      it.MoveNext();
     138      int[] lengths = new int[rank];
     139      int[] lowerBounds = new int[rank];
     140      for (int i = 0; i < rank; i++, it.MoveNext())
     141        lengths[i] = int.Parse((string) it.Current);
     142      for (int i = 0; i < rank; i++, it.MoveNext())
     143        lowerBounds[i] = int.Parse((string)it.Current);
     144      Array a = Array.CreateInstance(type.GetElementType(), lengths, lowerBounds);
     145      int[] positions = (int[]) lowerBounds.Clone();
     146      while (it.MoveNext()) {
     147        a.SetValue(
     148          numberDecomposer.Parse((string)it.Current, type.GetElementType()),         
     149          positions);
     150        positions[0] += 1;
     151        for ( int i = 0; i<rank-1; i++ ) {
     152          if (positions[i] >= lengths[i] + lowerBounds[i]) {
     153            positions[i + 1] += 1;
     154            positions[i] = lowerBounds[i];
     155          } else {
     156            break;
     157          }
     158        }
     159      }
     160      return a;
     161    }
     162  }
     163
     164  public class NumberEnumerable2StringDecomposer : IDecomposer {
     165
     166    private static readonly Number2StringDecomposer numberDecomposer =
     167      new Number2StringDecomposer();
     168   
     169    public bool ImplementsGenericEnumerable(Type type) {
     170      foreach( Type iface in type.GetInterfaces() ) {
     171        if ( iface.IsGenericType &&
     172          iface.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
     173          numberDecomposer.CanDecompose(iface.GetGenericArguments()[0]) )
     174          return true;
     175      }
     176      return false;
     177    }
     178
     179    public bool HasAddMethod(Type type) {
     180      return
     181        type.GetMethod("Add") != null &&
     182        type.GetMethod("Add").GetParameters().Length == 1 &&
     183        type.GetConstructor(
     184          BindingFlags.Public |
     185          BindingFlags.NonPublic |
     186          BindingFlags.Instance,
     187          null, Type.EmptyTypes, null) != null;     
     188    }
     189
     190    public bool CanDecompose(Type type) {
     191      return
     192        ImplementsGenericEnumerable(type) &&
     193        HasAddMethod(type);
     194    }
     195
     196    public IEnumerable<Tag> DeCompose(object obj) {
     197      Type elementType = obj.GetType().GetGenericArguments()[0];
     198      Type instantiatedGenericInterface =
     199        typeof (IEnumerable<>).MakeGenericType(new[] {elementType});
     200      MethodInfo genericGetEnumeratorMethod =
     201        instantiatedGenericInterface.GetMethod("GetEnumerator");
     202      InterfaceMapping iMap = obj.GetType().GetInterfaceMap(instantiatedGenericInterface);
     203      MethodInfo getEnumeratorMethod =
     204        iMap.TargetMethods[Array.IndexOf(iMap.InterfaceMethods, genericGetEnumeratorMethod)];
     205      object[] empty = new object[] {};
     206      object genericEnumerator = getEnumeratorMethod.Invoke(obj, empty);
     207      MethodInfo moveNextMethod = genericEnumerator.GetType().GetMethod("MoveNext");
     208      PropertyInfo currentProperty = genericEnumerator.GetType().GetProperty("Current");
     209      StringBuilder sb = new StringBuilder();
     210      while ( (bool)moveNextMethod.Invoke(genericEnumerator, empty) )
     211        sb.Append(
     212          numberDecomposer.SimpleDecompose(
     213            currentProperty.GetValue(genericEnumerator, null))).Append(';');
     214      yield return new Tag("compact enumerable", sb.ToString());
     215    }
     216
     217    public object CreateInstance(Type type) {
     218      return Activator.CreateInstance(type, true);
     219    }
     220
     221    public object Populate(object instance, IEnumerable<Tag> tags, Type type) {
     222      Type elementType = type.GetGenericArguments()[0];
     223      MethodInfo addMethod = type.GetMethod("Add");     
     224      var tagEnumerator = tags.GetEnumerator();
     225      tagEnumerator.MoveNext();
     226      string[] stringValues = ((string) tagEnumerator.Current.Value)
     227        .Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
     228      foreach (var value in stringValues) {
     229        addMethod.Invoke(instance, new[] {numberDecomposer.Parse(value, elementType)});
     230      }     
     231      return instance;     
     232    }
     233   
     234  }
     235
    123236}
Note: See TracChangeset for help on using the changeset viewer.