Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/Default/Decomposers/X2StringDecomposer.cs @ 1514

Last change on this file since 1514 was 1514, checked in by epitzer, 15 years ago

Improved 2string decomposers. (#563)

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