Free cookie consent management tool by TermsFeed Policy Generator

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

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

Replace final fixes for broken parent references with separation of instance creation with meta information. (#548)

File size: 9.1 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 Number2StringConverter {   
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 Number2StringConverter() {
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 object Parse(string stringValue, Type type) {
55      return numberParsers[type]
56        .Invoke(null,
57            BindingFlags.Static | BindingFlags.PutRefDispProperty,
58                  null, new[] {stringValue}, CultureInfo.InvariantCulture);
59    }
60
61  } 
62
63  public class DateTime2StringDecomposer : IDecomposer {
64
65    public int Priority {
66      get { return 100; }
67    }
68
69
70    public bool CanDecompose(Type type) {
71      return type == typeof(DateTime);
72    }
73
74    public IEnumerable<Tag> CreateMetaInfo(object obj) {
75      yield return new Tag(((DateTime)obj).Ticks);
76    }
77
78    public IEnumerable<Tag> Decompose(object obj) {
79      return new Tag[] { };
80    }
81
82    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
83      foreach (Tag tag in metaInfo) {
84        return new DateTime((long)tag.Value);
85      }
86      throw new ApplicationException("Not enough components to compose a bool.");
87    }
88
89    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {     
90    }
91
92  } 
93
94  public class CompactNumberArray2StringDecomposer : IDecomposer {
95
96    public int Priority {
97      get { return 200; }
98    }
99   
100    private static readonly Number2StringConverter numberConverter =
101      new Number2StringConverter();   
102
103    public bool CanDecompose(Type type) {
104      return
105        (type.IsArray || type == typeof (Array)) &&
106        numberConverter.CanDecompose(type.GetElementType());
107    }
108
109    public IEnumerable<Tag> CreateMetaInfo(object obj) {
110      Array a = (Array)obj;
111      int[] lengths = new int[a.Rank];
112      int[] lowerBounds = new int[a.Rank];
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        lengths[i] = a.GetLength(i);
118      }
119      for (int i = 0; i < a.Rank; i++) {
120        sb.Append(a.GetLowerBound(i)).Append(';');
121        lowerBounds[i] = a.GetLowerBound(i);
122      }
123      int[] positions = (int[])lowerBounds.Clone();
124      while (positions[a.Rank - 1] < lengths[a.Rank - 1] + lowerBounds[a.Rank - 1]) {
125        sb.Append(numberConverter.Format(a.GetValue(positions))).Append(';');
126        positions[0] += 1;
127        for (int i = 0; i < a.Rank - 1; i++) {
128          if (positions[i] >= lengths[i] + lowerBounds[i]) {
129            positions[i] = lowerBounds[i];
130            positions[i + 1] += 1;
131          } else {
132            break;
133          }
134        }
135      }
136      yield return new Tag("compact array", sb.ToString());
137    }
138
139    public IEnumerable<Tag> Decompose(object obj) {
140      return new Tag[] { };
141    }
142
143    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
144      var tagIter = metaInfo.GetEnumerator();
145      tagIter.MoveNext();
146      var valueIter = ((string) tagIter.Current.Value)
147        .Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries)
148        .GetEnumerator();
149      valueIter.MoveNext();
150      int rank = int.Parse((string) valueIter.Current);     
151      int[] lengths = new int[rank];
152      int[] lowerBounds = new int[rank];     
153      for (int i = 0; i < rank; i++) {
154        valueIter.MoveNext();
155        lengths[i] = int.Parse((string) valueIter.Current);       
156      }     
157      for (int i = 0; i < rank; i++) {
158        valueIter.MoveNext();
159        lowerBounds[i] = int.Parse((string) valueIter.Current);       
160      }
161      Type elementType = type.GetElementType();
162      Array a = Array.CreateInstance(elementType, lengths, lowerBounds);
163      int[] positions = (int[]) lowerBounds.Clone();
164      while (valueIter.MoveNext()) {
165        a.SetValue(
166          numberConverter.Parse((string)valueIter.Current, elementType),         
167          positions);
168        positions[0] += 1;
169        for ( int i = 0; i<rank-1; i++ ) {
170          if (positions[i] >= lengths[i] + lowerBounds[i]) {
171            positions[i + 1] += 1;
172            positions[i] = lowerBounds[i];
173          } else {
174            break;
175          }
176        }
177      }
178      return a;
179    }
180
181    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {
182    }
183
184  }
185
186  public class NumberEnumerable2StringDecomposer : IDecomposer {
187
188    public int Priority {
189      get { return 200; }
190    }
191
192    private static readonly Number2StringConverter numberConverter =
193      new Number2StringConverter();
194   
195    private static readonly Dictionary<Type, Type> interfaceCache = new Dictionary<Type, Type>();
196
197    public Type GetGenericEnumerableInterface(Type type) {
198      if (interfaceCache.ContainsKey(type))
199        return interfaceCache[type];
200      foreach (Type iface in type.GetInterfaces()) {
201        if (iface.IsGenericType &&
202          iface.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
203          numberConverter.CanDecompose(iface.GetGenericArguments()[0])) {
204          interfaceCache.Add(type, iface);
205          return iface;
206        }
207      }
208      interfaceCache.Add(type, null);
209      return null;
210    }
211   
212    public bool ImplementsGenericEnumerable(Type type) {
213      return GetGenericEnumerableInterface(type) != null;
214    }
215
216    public bool HasAddMethod(Type type) {
217      return
218        type.GetMethod("Add") != null &&
219        type.GetMethod("Add").GetParameters().Length == 1 &&
220        type.GetConstructor(
221          BindingFlags.Public |
222          BindingFlags.NonPublic |
223          BindingFlags.Instance,
224          null, Type.EmptyTypes, null) != null;     
225    }
226
227    public bool CanDecompose(Type type) {
228      return
229        ImplementsGenericEnumerable(type) &&
230        HasAddMethod(type);
231    }
232
233    public IEnumerable<Tag> CreateMetaInfo(object o) {
234      return new Tag[] { };
235    }
236
237    public IEnumerable<Tag> Decompose(object obj) {
238      Type type = obj.GetType();
239      Type enumerable = GetGenericEnumerableInterface(type);     
240      InterfaceMapping iMap = obj.GetType().GetInterfaceMap(enumerable);     
241      MethodInfo getEnumeratorMethod =
242        iMap.TargetMethods[
243        Array.IndexOf(
244          iMap.InterfaceMethods,
245          enumerable.GetMethod("GetEnumerator"))];
246      object[] empty = new object[] {};
247      object genericEnumerator = getEnumeratorMethod.Invoke(obj, empty);
248      MethodInfo moveNextMethod = genericEnumerator.GetType().GetMethod("MoveNext");
249      PropertyInfo currentProperty = genericEnumerator.GetType().GetProperty("Current");
250      StringBuilder sb = new StringBuilder();
251      while ( (bool)moveNextMethod.Invoke(genericEnumerator, empty) )
252        sb.Append(
253          numberConverter.Format(
254            currentProperty.GetValue(genericEnumerator, null))).Append(';');
255      yield return new Tag("compact enumerable", sb.ToString());
256    }
257
258    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
259      return Activator.CreateInstance(type, true);
260    }
261
262    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {
263      Type enumerable = GetGenericEnumerableInterface(type);
264      Type elementType = enumerable.GetGenericArguments()[0];     
265      MethodInfo addMethod = type.GetMethod("Add");     
266      var tagEnumerator = tags.GetEnumerator();
267      tagEnumerator.MoveNext();
268      string[] stringValues = ((string) tagEnumerator.Current.Value)
269        .Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
270      foreach (var value in stringValues) {
271        addMethod.Invoke(instance, new[] {numberConverter.Parse(value, elementType)});
272      }
273    }
274  }
275}
Note: See TracBrowser for help on using the repository browser.