#region License Information /* HeuristicLab * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.PluginInfrastructure; using Google.ProtocolBuffers; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Persistence { public sealed class Mapper { private Index transformers; private Dictionary typeInfos; private Index types; private Index strings; private Index boxes; private Dictionary boxCache; private Dictionary objectCache; public long BoxCount { get; private set; } public Mapper() { transformers = new Index(); typeInfos = new Dictionary(); types = new Index(); strings = new Index(); boxes = new Index(); boxCache = new Dictionary(new ReferenceEqualityComparer()); objectCache = new Dictionary(); BoxCount = 0; foreach (var transformer in ApplicationManager.Manager.GetInstances().OrderBy(x => x.Order)) { transformer.Initialize(transformers.GetIndex(transformer)); } } public TypeInfo GetTypeInfo(Type type) { TypeInfo typeInfo; if (!typeInfos.TryGetValue(type, out typeInfo)) { var transformer = transformers.GetValues().Where(x => x.CanTransformType(type)).FirstOrDefault(); typeInfo = new TypeInfo(type, transformer); typeInfos.Add(type, typeInfo); } return typeInfo; } public IEnumerable GetTypeInfos() { return typeInfos.Values; } public IEnumerable GetTypes() { return typeInfos.Values.Select(x => x.Type); } public uint GetTypeId(Type type) { return types.GetIndex(type); } public Type GetType(uint typeId) { return types.GetValue(typeId); } public uint GetStringId(string str) { return strings.GetIndex(str); } public string GetString(uint stringId) { return strings.GetValue(stringId); } public uint GetBoxId(object o) { uint boxId; if (boxCache.TryGetValue(o, out boxId)) return boxId; if (o == null) boxId = boxes.GetIndex(null); else { var type = o.GetType(); var typeInfo = GetTypeInfo(type); if (typeInfo.Transformer == null) throw new ArgumentException("Cannot serialize object of type " + o.GetType()); BoxCount++; typeInfo.Used++; boxId = boxes.GetIndex(typeInfo.Transformer.ToBox(o, this)); } boxCache.Add(o, boxId); return boxId; } public object GetObject(uint boxId) { object o; if (objectCache.TryGetValue(boxId, out o)) return o; var box = this.boxes.GetValue(boxId); if (box == null) o = null; else { var transformer = transformers.GetValue(box.TransformerId); o = transformer.ToObject(box, this); } objectCache.Add(boxId, o); return o; } public object CreateInstance(Type type) { return GetTypeInfo(type).GetConstructor()(); } public static Bundle ToBundle(object o) { var mapper = new Mapper(); var bundle = Bundle.CreateBuilder(); bundle.RootBoxId = mapper.GetBoxId(o); bundle.AddRangeTransformerGuids(mapper.transformers.GetValues().Select(x => x.Guid).Select(x => ByteString.CopyFrom(x.ToByteArray()))); bundle.AddRangeTypeGuids(mapper.types.GetValues().Select(x => mapper.typeInfos[x].StorableClassAttribute.Guid).Select(x => ByteString.CopyFrom(x.ToByteArray()))); bundle.AddRangeStrings(mapper.strings.GetValues()); bundle.AddRangeBoxes(mapper.boxes.GetValues()); return bundle.Build(); } public static object ToObject(Bundle bundle) { var types = new Dictionary(); foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var t in asm.GetTypes().Where(x => StorableClassAttribute.IsStorableClass(x))) types.Add(StorableClassAttribute.GetStorableClassAttribute(t).Guid, t); } var mapper = new Mapper(); mapper.types = new Index(bundle.TypeGuidsList.Select(x => new Guid(x.ToByteArray())).Select(x => types[x])); mapper.strings = new Index(bundle.StringsList); mapper.boxes = new Index(bundle.BoxesList); mapper.transformers = new Index(bundle.TransformerGuidsList.Select(x => new Guid(x.ToByteArray())).Select(x => mapper.transformers.GetValues().First(y => y.Guid == x))); foreach (var type in mapper.types.GetValues()) mapper.typeInfos.Add(type, new TypeInfo(type)); return mapper.GetObject(bundle.RootBoxId); } } }