Skip to content

Instantly share code, notes, and snippets.

@stefan-baumann
Created May 31, 2016 22:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefan-baumann/bac6e9bdf14437e34ef5fdd78a549087 to your computer and use it in GitHub Desktop.
Save stefan-baumann/bac6e9bdf14437e34ef5fdd78a549087 to your computer and use it in GitHub Desktop.
Raw Data Serializer Test
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