#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 static StaticCache staticCache = null; private static object locker = new object(); public static StaticCache StaticCache { get { lock (locker) { if (staticCache == null) staticCache = new StaticCache(); return staticCache; } } } private Index transformers; private Index types; private Index strings; private Index boxes; private Dictionary object2BoxId; private Dictionary boxId2object; public long BoxCount { get; private set; } public Mapper() { transformers = new Index(); types = new Index(); strings = new Index(); boxes = new Index(); object2BoxId = new Dictionary(new ReferenceEqualityComparer()); boxId2object = new Dictionary(); BoxCount = 0; } public uint GetTransformerId(ITransformer transformer) { return transformers.GetIndex(transformer); } public ITransformer GetTransformer(uint transformerId) { return transformers.GetValue(transformerId); } 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 (object2BoxId.TryGetValue(o, out boxId)) return boxId; if (o == null) boxId = boxes.GetIndex(null); else { var type = o.GetType(); var typeInfo = StaticCache.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)); } object2BoxId.Add(o, boxId); return boxId; } public object GetObject(uint boxId) { object o; if (boxId2object.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); } boxId2object.Add(boxId, o); return o; } public object CreateInstance(Type type) { return StaticCache.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 => StaticCache.GetGuid(x)).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 mapper = new Mapper(); mapper.types = new Index(bundle.TypeGuidsList.Select(x => new Guid(x.ToByteArray())).Select(x => StaticCache.GetType(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 => StaticCache.GetTransformer(x))); return mapper.GetObject(bundle.RootBoxId); } } }