Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Core/Serializer.cs @ 1707

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

Use actual GetHashCode instead of garbage collector handle for less speed but more safety. (#605)

File size: 5.2 KB
Line 
1using System.Collections.Generic;
2using System.Collections;
3using System;
4using System.Linq;
5using HeuristicLab.Persistence.Auxiliary;
6using HeuristicLab.Persistence.Interfaces;
7using HeuristicLab.Persistence.Core.Tokens;
8using HeuristicLab.Persistence.Default.Decomposers.Storable;
9using System.Text;
10
11namespace HeuristicLab.Persistence.Core {
12
13  public class Serializer : IEnumerable<ISerializationToken> {
14
15    class ReferenceEqualityComparer : IEqualityComparer<object> {
16
17      public bool Equals(object a, object b) {
18        return Object.ReferenceEquals(a, b);
19      }
20
21      public int GetHashCode(object obj) {
22        return obj.GetHashCode();
23      }
24
25    }
26
27    private readonly object obj;
28    private readonly string rootName;
29    private readonly Dictionary<object, int> obj2id;
30    private readonly Dictionary<Type, int> typeCache;
31    private readonly Configuration configuration;
32
33    public List<TypeMapping> TypeCache {
34      get {
35        List<TypeMapping> result = new List<TypeMapping>();
36        foreach (var pair in typeCache) {
37          string serializer = null;
38          IFormatter f = configuration.GetFormatter(pair.Key);
39          if (f != null) {
40            serializer = f.GetType().VersionInvariantName();
41          } else {
42            IDecomposer d = configuration.GetDecomposer(pair.Key);
43            serializer = d.GetType().VersionInvariantName();
44          }
45          result.Add(new TypeMapping(pair.Value, pair.Key.VersionInvariantName(), serializer));
46        }
47        return result;
48      }
49    }
50
51    public Serializer(object obj, Configuration configuration) :
52      this(obj, configuration, "ROOT") { }
53
54    public Serializer(object obj, Configuration configuration, string rootName) {
55      this.obj = obj;
56      this.rootName = rootName;
57      this.configuration = configuration;
58      obj2id = new Dictionary<object, int>(new ReferenceEqualityComparer()) { { new object(), 0 } };
59      typeCache = new Dictionary<Type, int>();
60    }
61
62    IEnumerator IEnumerable.GetEnumerator() {
63      return GetEnumerator();
64    }
65
66    public IEnumerator<ISerializationToken> GetEnumerator() {
67      return Serialize(new DataMemberAccessor(rootName, null, () => obj, null));
68    }
69
70    private IEnumerator<ISerializationToken> Serialize(DataMemberAccessor accessor) {
71      object value = accessor.Get();
72      if (value == null)
73        return NullReferenceEnumerator(accessor.Name);
74      Type type = value.GetType();
75      if (obj2id.ContainsKey(value))
76        return ReferenceEnumerator(accessor.Name, obj2id[value]);
77      if (!typeCache.ContainsKey(type))
78        typeCache.Add(type, typeCache.Count);
79      int typeId = typeCache[type];
80      int? id = null;
81      if (!type.IsValueType) {
82        id = obj2id.Count;
83        obj2id.Add(value, (int)id);
84      }
85      IFormatter formatter = configuration.GetFormatter(type);
86      if (formatter != null)
87        return PrimitiveEnumerator(accessor.Name, typeId, formatter.Format(value), id);
88      IDecomposer decomposer = configuration.GetDecomposer(type);
89      if (decomposer != null)
90        return CompositeEnumerator(accessor.Name, decomposer.Decompose(value), id, typeId, decomposer.CreateMetaInfo(value));
91      throw new PersistenceException(
92          String.Format(
93          "No suitable method for serializing values of type \"{0}\" found\r\n" +
94          "Formatters:\r\n{1}\r\n" +
95          "Decomposers:\r\n{2}",
96          value.GetType().VersionInvariantName(),
97          string.Join("\r\n", configuration.Formatters.Select(f => f.GetType().VersionInvariantName()).ToArray()),
98          string.Join("\r\n", configuration.Decomposers.Select(d => d.GetType().VersionInvariantName()).ToArray())
99          ));
100
101    }
102
103    private IEnumerator<ISerializationToken> NullReferenceEnumerator(string name) {
104      yield return new NullReferenceToken(name);
105    }
106
107    private IEnumerator<ISerializationToken> ReferenceEnumerator(string name, int id) {
108      yield return new ReferenceToken(name, id);
109    }
110
111    private IEnumerator<ISerializationToken> PrimitiveEnumerator(string name,
112        int typeId, ISerialData serializedValue, int? id) {
113      yield return new PrimitiveToken(name, typeId, id, serializedValue);
114    }
115
116    private IEnumerator<ISerializationToken> CompositeEnumerator(
117        string name, IEnumerable<Tag> tags, int? id, int typeId, IEnumerable<Tag> metaInfo) {
118      yield return new BeginToken(name, typeId, id);
119      bool first = true;
120      foreach (var tag in metaInfo) {
121        IEnumerator<ISerializationToken> metaIt = Serialize(new DataMemberAccessor(tag.Value, tag.Name));
122        while (metaIt.MoveNext()) {
123          if (first) {
124            yield return new MetaInfoBeginToken();
125            first = false;
126          }
127          yield return metaIt.Current;
128        }
129      }
130      if (!first) {
131        yield return new MetaInfoEndToken();
132      }
133      foreach (var tag in tags) {
134        IEnumerator<ISerializationToken> it = Serialize(new DataMemberAccessor(tag.Value, tag.Name));
135        while (it.MoveNext())
136          yield return it.Current;
137      }
138      yield return new EndToken(name, typeId, id);
139    }
140
141  }
142
143
144}
Note: See TracBrowser for help on using the repository browser.