diff --git a/Hyperion.Tests.Performance/Deserialization/DeserializeCollectionsBenchmark.cs b/Hyperion.Tests.Performance/Deserialization/DeserializeCollectionsBenchmark.cs index 2892593..3e74ca7 100644 --- a/Hyperion.Tests.Performance/Deserialization/DeserializeCollectionsBenchmark.cs +++ b/Hyperion.Tests.Performance/Deserialization/DeserializeCollectionsBenchmark.cs @@ -142,15 +142,14 @@ namespace Hyperion.Tests.Performance.Deserialization InitStreamWith(new LinkedList(new[] { "asdad", "asdabs3", "dfsdf9", "asdf4r", "sfsdf44g" })); } - [NBenchFact(Skip = "FIXME: some problem with recursion, StackOverflowException")] + [NBenchFact] [PerfBenchmark( Description = "Benchmark linked list deserialization", NumberOfIterations = StandardIterationCount, RunMode = RunMode.Throughput, RunTimeMilliseconds = StandardRunTime, - TestMode = TestMode.Test, - Skip = "FIXME: some problem with recursion, StackOverflowException")] - [CounterThroughputAssertion(TestCounterName, MustBe.GreaterThan, 80000)] + TestMode = TestMode.Test)] + [CounterThroughputAssertion(TestCounterName, MustBe.GreaterThan, 150000)] public void Deserialize_LinkedList() { Stream.Position = 0; // don't move it up to Setup, I don't know why it needed here to work diff --git a/Hyperion.Tests.Performance/Serialization/SerializeCollectionsBenchmark.cs b/Hyperion.Tests.Performance/Serialization/SerializeCollectionsBenchmark.cs index 053951b..6040ccc 100644 --- a/Hyperion.Tests.Performance/Serialization/SerializeCollectionsBenchmark.cs +++ b/Hyperion.Tests.Performance/Serialization/SerializeCollectionsBenchmark.cs @@ -80,15 +80,14 @@ namespace Hyperion.Tests.Performance.Serialization SerializeAndCount(new List { "asdad", "asdabs3", "sfsdf44g", "asdf4r", "sfsdf44g" }); } - [NBenchFact(Skip = "FIXME: Stack overflow exception")] + [NBenchFact] [PerfBenchmark( Description = "Benchmark linked list serialization", NumberOfIterations = StandardIterationCount, RunMode = RunMode.Throughput, RunTimeMilliseconds = StandardRunTime, - TestMode = TestMode.Test, - Skip = "FIXME: Stack overflow exception")] - [CounterThroughputAssertion(TestCounterName, MustBe.GreaterThan, 210000)] + TestMode = TestMode.Test)] + [CounterThroughputAssertion(TestCounterName, MustBe.GreaterThan, 500000)] public void Serialize_LinkedList() { var list = new LinkedList(new[] { "asdad", "asdabs3", "dfsdf9", "asdf4r", "sfsdf44g" }); diff --git a/Hyperion.Tests/CollectionTests.cs b/Hyperion.Tests/CollectionTests.cs index e1ba6d1..a7d61ce 100644 --- a/Hyperion.Tests/CollectionTests.cs +++ b/Hyperion.Tests/CollectionTests.cs @@ -167,6 +167,30 @@ namespace Hyperion.Tests Assert.Equal(expected, actual); } + [Fact] + public void CanSerializeLinkedList() + { + var expected = new LinkedList(new[] + { + new Something + { + BoolProp = true, + Else = new Else + { + Name = "Yoho" + }, + Int32Prop = 999, + StringProp = "Yesbox!" + }, + new Something(), new Something(), null + }); + + Serialize(expected); + Reset(); + var actual = Deserialize>(); + Assert.Equal(expected, actual); + } + [Fact(Skip = "add support for multi dimentional arrays")] public void CanSerializeMultiDimentionalArray() { diff --git a/Hyperion/Hyperion.csproj b/Hyperion/Hyperion.csproj index 3d1357c..a68fd75 100644 --- a/Hyperion/Hyperion.csproj +++ b/Hyperion/Hyperion.csproj @@ -68,6 +68,7 @@ + diff --git a/Hyperion/SerializerFactories/LinkedListSerializerFactory.cs b/Hyperion/SerializerFactories/LinkedListSerializerFactory.cs new file mode 100644 index 0000000..15a9020 --- /dev/null +++ b/Hyperion/SerializerFactories/LinkedListSerializerFactory.cs @@ -0,0 +1,92 @@ +#region copyright +// ----------------------------------------------------------------------- +// +// Copyright (C) 2015-2016 AsynkronIT +// Copyright (C) 2016-2016 Akka.NET Team +// +// ----------------------------------------------------------------------- +#endregion + +using System; +using System.Reflection; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Hyperion.Extensions; +using Hyperion.ValueSerializers; + +namespace Hyperion.SerializerFactories +{ + public sealed class LinkedListSerializerFactory : ValueSerializerFactory + { + private static readonly Type LinkedListType = typeof(LinkedList<>); + + public override bool CanSerialize(Serializer serializer, Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == LinkedListType; + + public override bool CanDeserialize(Serializer serializer, Type type) => CanSerialize(serializer, type); + + private static void WriteValues(LinkedList list, Stream stream, Type elementType, ValueSerializer elementSerializer, SerializerSession session) + { + Int32Serializer.WriteValueImpl(stream, list.Count, session); + var preserveObjectReferences = session.Serializer.Options.PreserveObjectReferences; + foreach (var value in list) + { + stream.WriteObject(value, elementType, elementSerializer, preserveObjectReferences, session); + } + } + + private static void ReadValues(int length, Stream stream, DeserializerSession session, LinkedList list) + { + for (var i = 0; i < length; i++) + { + var value = (T)stream.ReadObject(session); + list.AddLast(value); + } + } + + private static Type GetLinkedListType(Type type) + { + return type.GetTypeInfo().GetGenericArguments()[0]; + } + + public override ValueSerializer BuildSerializer(Serializer serializer, Type type, + ConcurrentDictionary typeMapping) + { + var elementType = GetLinkedListType(type); + var elementSerializer = serializer.GetSerializerByType(elementType); + var preserveObjectReferences = serializer.Options.PreserveObjectReferences; + //TODO: code gen this part + ObjectReader reader = (stream, session) => + { + var length = stream.ReadInt32(session); + var array = Activator.CreateInstance(type); + if (preserveObjectReferences) + { + session.TrackDeserializedObject(array); + } + + ReadValues(length, stream, session, (dynamic)array); + + return array; + }; + + ObjectWriter writer = (stream, arr, session) => + { + if (preserveObjectReferences) + { + session.TrackSerializedObject(arr); + } + + WriteValues((dynamic)arr, stream, elementType, elementSerializer, session); + + }; + + var ser = new ObjectSerializer(type); + ser.Initialize(reader, writer); + typeMapping.TryAdd(type, ser); + + return ser; + } + } +} \ No newline at end of file diff --git a/Hyperion/SerializerOptions.cs b/Hyperion/SerializerOptions.cs index 8ba8861..37022a7 100644 --- a/Hyperion/SerializerOptions.cs +++ b/Hyperion/SerializerOptions.cs @@ -39,6 +39,7 @@ namespace Hyperion new DefaultDictionarySerializerFactory(), new DictionarySerializerFactory(), new ArraySerializerFactory(), + new LinkedListSerializerFactory(), #if SERIALIZATION new ISerializableSerializerFactory(), //TODO: this will mess up the indexes in the serializer payload #endif