Free cookie consent management tool by TermsFeed Policy Generator

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

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

Replace value comparison with references comparison in serializer. (#605)

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