-
-
Save stefan-baumann/bac6e9bdf14437e34ef5fdd78a549087 to your computer and use it in GitHub Desktop.
Raw Data Serializer Test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace RawSerializerTest | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
//Test methods | |
List<Tuple<string, Func<TestStruct, byte[]>, Func<byte[], TestStruct>>> methods = new List<Tuple<string, Func<TestStruct, byte[]>, Func<byte[], TestStruct>>>() | |
{ | |
Tuple.Create("Marshal", (Func<TestStruct, byte[]>)GetDataMarshal<TestStruct>, (Func<byte[], TestStruct>)GetStructMarshal<TestStruct>), | |
Tuple.Create("GCHandle", (Func<TestStruct, byte[]>)GetDataGCHandle<TestStruct>, (Func<byte[], TestStruct>)GetStructGCHandle<TestStruct>), | |
Tuple.Create("Unsafe", (Func<TestStruct, byte[]>)GetDataUnsafe<TestStruct>, (Func<byte[], TestStruct>)GetStructUnsafe<TestStruct>), | |
Tuple.Create("MakeRef", (Func<TestStruct, byte[]>)GetDataMakeRef<TestStruct>, (Func<byte[], TestStruct>)GetStructMakeRef<TestStruct>) | |
}; | |
//Test data | |
int iterations = 5000000; | |
TestStruct testStruct = new TestStruct(true, 123, 80543, 652145.903); | |
//3 Rounds of testing | |
for (int rounds = 0; rounds < 3; rounds++) | |
{ | |
//Test each method | |
Console.WriteLine("----- Testing Round {0} -----", rounds + 1); | |
foreach (var method in methods) | |
{ | |
Console.Write("{0,-10}", method.Item1 + ":"); | |
//Check correct functionality | |
if (method.Item3(method.Item2(testStruct)) != testStruct) | |
{ | |
Console.WriteLine("Test failed."); | |
break; | |
} | |
Stopwatch watch = Stopwatch.StartNew(); | |
for (int i = 0; i < iterations; i++) | |
{ | |
byte[] data = method.Item2(testStruct); | |
TestStruct reconstructed = method.Item3(data); | |
} | |
watch.Stop(); | |
Console.WriteLine("{0:0.000} nanoseconds", watch.ElapsedMilliseconds / (iterations / 1000d)); | |
} | |
} | |
Console.WriteLine("------ Test Finished ------"); | |
Console.ReadKey(true); | |
} | |
#region Marshal | |
static byte[] GetDataMarshal<T>(T @struct) where T : struct | |
{ | |
int size = Marshal.SizeOf(typeof(T)); | |
IntPtr buffer = Marshal.AllocHGlobal(size); | |
try | |
{ | |
Marshal.StructureToPtr(@struct, buffer, false); | |
byte[] data = new byte[size]; | |
Marshal.Copy(buffer, data, 0, size); | |
return data; | |
} | |
finally | |
{ | |
Marshal.FreeHGlobal(buffer); | |
} | |
} | |
static T GetStructMarshal<T>(byte[] data) where T : struct | |
{ | |
int size = Marshal.SizeOf(typeof(T)); | |
IntPtr buffer = Marshal.AllocHGlobal(size); | |
try | |
{ | |
Marshal.Copy(data, 0, buffer, size); | |
T @struct = (T)Marshal.PtrToStructure(buffer, typeof(T)); | |
return @struct; | |
} | |
finally | |
{ | |
Marshal.FreeHGlobal(buffer); | |
} | |
} | |
#endregion | |
#region GCHandle Marshal | |
static unsafe byte[] GetDataGCHandle<T>(T @struct) where T : struct | |
{ | |
byte[] data = new byte[Marshal.SizeOf(typeof(T))]; | |
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); | |
try | |
{ | |
Marshal.StructureToPtr<T>(@struct, handle.AddrOfPinnedObject(), false); | |
return data; | |
} | |
finally | |
{ | |
handle.Free(); | |
} | |
} | |
static unsafe T GetStructGCHandle<T>(byte[] data) where T : struct | |
{ | |
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); | |
try | |
{ | |
T @struct = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject()); | |
return @struct; | |
} | |
finally | |
{ | |
handle.Free(); | |
} | |
} | |
#endregion | |
#region Unsafe Marshal | |
static unsafe byte[] GetDataUnsafe<T>(T @struct) where T : struct | |
{ | |
byte[] data = new byte[Marshal.SizeOf(typeof(T))]; | |
fixed (byte* ptr = data) | |
{ | |
Marshal.StructureToPtr<T>(@struct, (IntPtr)ptr, false); | |
} | |
return data; | |
} | |
static unsafe T GetStructUnsafe<T>(byte[] data) where T : struct | |
{ | |
fixed (byte* ptr = data) | |
{ | |
return Marshal.PtrToStructure<T>((IntPtr)ptr); | |
} | |
} | |
#endregion | |
#region __makeref Crazyness | |
static unsafe byte[] GetDataMakeRef<T>(T @struct) where T : struct | |
{ | |
int size = Marshal.SizeOf(typeof(T)); | |
byte[] data = new byte[size]; | |
TypedReference @ref = __makeref(@struct); | |
Marshal.Copy(*((IntPtr*)&@ref), data, 0, size); | |
return data; | |
} | |
static unsafe T GetStructMakeRef<T>(byte[] data) where T : struct | |
{ | |
T @struct = default(T); | |
TypedReference @ref = __makeref(@struct); | |
Marshal.Copy(data, 0, *((IntPtr*)&@ref), Marshal.SizeOf(typeof(T))); | |
return @struct; | |
} | |
#endregion | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public struct TestStruct | |
{ | |
public TestStruct(bool a, byte b, int c, double d) | |
{ | |
this.A = a; | |
this.B = b; | |
this.C = c; | |
this.D = d; | |
} | |
public bool A; | |
public byte B; | |
public int C; | |
public double D; | |
public static bool operator == (TestStruct left, TestStruct right) | |
{ | |
return left.A == right.A && left.B == right.B && left.C == right.C && left.D == right.D; | |
} | |
public static bool operator != (TestStruct left, TestStruct right) | |
{ | |
return !(left == right); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment