Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/CompactNumberArray2StringSerializer.cs @ 3937

Last change on this file since 3937 was 3937, checked in by epitzer, 14 years ago

Estimate or calculate StringBuffer sizes in advance, use iterator over string splits instead of arrays. (#1138)

File size: 5.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Linq;
24using HeuristicLab.Persistence.Interfaces;
25using HeuristicLab.Persistence.Core;
26using System.Collections.Generic;
27using System.Reflection;
28using System.Globalization;
29using System.Text;
30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
31using HeuristicLab.Persistence.Auxiliary;
32
33namespace HeuristicLab.Persistence.Default.CompositeSerializers {
34
35  [StorableClass]
36  internal sealed class CompactNumberArray2StringSerializer : ICompositeSerializer {
37
38    public int Priority {
39      get { return 200; }
40    }
41
42    private static readonly Number2StringSerializer numberConverter =
43      new Number2StringSerializer();
44
45    public bool CanSerialize(Type type) {
46      return
47        (type.IsArray || type == typeof(Array)) &&
48        numberConverter.CanSerialize(type.GetElementType());
49    }
50
51    public string JustifyRejection(Type type) {
52      if (!type.IsArray && type != typeof(Array))
53        return "not an array";
54      return string.Format("number converter cannot serialize elements: " +
55        numberConverter.JustifyRejection(type.GetElementType()));
56    }
57
58    public IEnumerable<Tag> CreateMetaInfo(object obj) {
59      Array a = (Array)obj;
60      int[] lengths = new int[a.Rank];
61      int[] lowerBounds = new int[a.Rank];
62      StringBuilder sb = new StringBuilder(a.Rank * 3);
63      sb.Append(a.Rank).Append(';');
64      int capacity = 1;
65      for (int i = 0; i < a.Rank; i++) {
66        sb.Append(a.GetLength(i)).Append(';');
67        lengths[i] = a.GetLength(i);
68        capacity *= lengths[i];
69      }
70      sb.EnsureCapacity(capacity * 3);
71      for (int i = 0; i < a.Rank; i++) {
72        sb.Append(a.GetLowerBound(i)).Append(';');
73        lowerBounds[i] = a.GetLowerBound(i);
74      }
75      int[] positions = (int[])lowerBounds.Clone();
76      while (positions[a.Rank - 1] < lengths[a.Rank - 1] + lowerBounds[a.Rank - 1]) {
77        sb.Append(numberConverter.Format(a.GetValue(positions))).Append(';');
78        positions[0] += 1;
79        for (int i = 0; i < a.Rank - 1; i++) {
80          if (positions[i] >= lengths[i] + lowerBounds[i]) {
81            positions[i] = lowerBounds[i];
82            positions[i + 1] += 1;
83          } else {
84            break;
85          }
86        }
87      }
88      yield return new Tag("compact array", sb.ToString());
89    }
90
91    public IEnumerable<Tag> Decompose(object obj) {
92      return new Tag[] { };
93    }
94
95    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
96      try {
97        var tagIter = metaInfo.GetEnumerator();
98        tagIter.MoveNext();
99        var valueIter = ((string)tagIter.Current.Value).GetSplitEnumerator(';');
100        valueIter.MoveNext();
101        int rank = int.Parse((string)valueIter.Current);
102        int[] lengths = new int[rank];
103        int[] lowerBounds = new int[rank];
104        for (int i = 0; i < rank; i++) {
105          valueIter.MoveNext();
106          lengths[i] = int.Parse((string)valueIter.Current);
107        }
108        for (int i = 0; i < rank; i++) {
109          valueIter.MoveNext();
110          lowerBounds[i] = int.Parse((string)valueIter.Current);
111        }
112        Type elementType = type.GetElementType();
113        Array a = Array.CreateInstance(elementType, lengths, lowerBounds);
114        int[] positions = (int[])lowerBounds.Clone();
115        while (valueIter.MoveNext()) {
116          a.SetValue(
117            numberConverter.Parse((string)valueIter.Current, elementType),
118            positions);
119          positions[0] += 1;
120          for (int i = 0; i < rank - 1; i++) {
121            if (positions[i] >= lengths[i] + lowerBounds[i]) {
122              positions[i + 1] += 1;
123              positions[i] = lowerBounds[i];
124            } else {
125              break;
126            }
127          }
128        }
129        return a;
130      } catch (InvalidOperationException e) {
131        throw new PersistenceException("Insufficient data to deserialize compact array", e);
132      } catch (InvalidCastException e) {
133        throw new PersistenceException("Invalid element data during compact array deserialization", e);
134      }
135    }
136
137    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {
138      // Nothing to do: Compact arrays are already populated during instance creation.
139    }
140
141  }
142
143}
Note: See TracBrowser for help on using the repository browser.