Move BinaryQuickSerializer from Emulation.Common to Common
This commit is contained in:
parent
ffd743cac7
commit
e1750bdce9
|
@ -1,223 +1,221 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using BizHawk.Common;
|
namespace BizHawk.Common
|
||||||
|
{
|
||||||
namespace BizHawk.Emulation.Common
|
// fields are serialized/deserialized in their memory order as reported by Marshal.OffsetOf
|
||||||
{
|
// to do anything useful, passed targets should be [StructLayout.Sequential] or [StructLayout.Explicit]
|
||||||
// fields are serialized/deserialized in their memory order as reported by Marshal.OffsetOf
|
public class BinaryQuickSerializer
|
||||||
// to do anything useful, passed targets should be [StructLayout.Sequential] or [StructLayout.Explicit]
|
{
|
||||||
public class BinaryQuickSerializer
|
#region methodinfo from a lambda expression. cool.
|
||||||
{
|
|
||||||
#region methodinfo from a lambda expression. cool.
|
private static MethodInfo FromExpression(Expression e)
|
||||||
|
{
|
||||||
private static MethodInfo FromExpression(Expression e)
|
var caller = e as MethodCallExpression;
|
||||||
{
|
if (caller == null)
|
||||||
var caller = e as MethodCallExpression;
|
{
|
||||||
if (caller == null)
|
throw new ArgumentException("Expression must be a method call");
|
||||||
{
|
}
|
||||||
throw new ArgumentException("Expression must be a method call");
|
|
||||||
}
|
return caller.Method;
|
||||||
|
}
|
||||||
return caller.Method;
|
|
||||||
}
|
private static MethodInfo Method(Expression<Action> f)
|
||||||
|
{
|
||||||
private static MethodInfo Method(Expression<Action> f)
|
return FromExpression(f.Body);
|
||||||
{
|
}
|
||||||
return FromExpression(f.Body);
|
|
||||||
}
|
private static MethodInfo Method<T>(Expression<Action<T>> f)
|
||||||
|
{
|
||||||
private static MethodInfo Method<T>(Expression<Action<T>> f)
|
return FromExpression(f.Body);
|
||||||
{
|
}
|
||||||
return FromExpression(f.Body);
|
|
||||||
}
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#region read and write handlers for individual fields
|
||||||
|
|
||||||
#region read and write handlers for individual fields
|
private static readonly Dictionary<Type, MethodInfo> Readhandlers = new Dictionary<Type, MethodInfo>();
|
||||||
|
private static readonly Dictionary<Type, MethodInfo> Writehandlers = new Dictionary<Type, MethodInfo>();
|
||||||
private static readonly Dictionary<Type, MethodInfo> Readhandlers = new Dictionary<Type, MethodInfo>();
|
|
||||||
private static readonly Dictionary<Type, MethodInfo> Writehandlers = new Dictionary<Type, MethodInfo>();
|
private static void AddR<T>(Expression<Action<BinaryReader>> f)
|
||||||
|
{
|
||||||
private static void AddR<T>(Expression<Action<BinaryReader>> f)
|
var method = Method(f);
|
||||||
{
|
if (!typeof(T).IsAssignableFrom(method.ReturnType))
|
||||||
var method = Method(f);
|
{
|
||||||
if (!typeof(T).IsAssignableFrom(method.ReturnType))
|
throw new InvalidOperationException("Type mismatch");
|
||||||
{
|
}
|
||||||
throw new InvalidOperationException("Type mismatch");
|
|
||||||
}
|
Readhandlers.Add(typeof(T), method);
|
||||||
|
}
|
||||||
Readhandlers.Add(typeof(T), method);
|
|
||||||
}
|
private static void AddW<T>(Expression<Action<BinaryWriter>> f)
|
||||||
|
{
|
||||||
private static void AddW<T>(Expression<Action<BinaryWriter>> f)
|
var method = Method(f);
|
||||||
{
|
if (!method.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(T)))
|
||||||
var method = Method(f);
|
{
|
||||||
if (!method.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(T)))
|
throw new InvalidOperationException("Type mismatch");
|
||||||
{
|
}
|
||||||
throw new InvalidOperationException("Type mismatch");
|
|
||||||
}
|
Writehandlers.Add(typeof(T), Method(f));
|
||||||
|
}
|
||||||
Writehandlers.Add(typeof(T), Method(f));
|
|
||||||
}
|
static BinaryQuickSerializer()
|
||||||
|
{
|
||||||
static BinaryQuickSerializer()
|
AddR<bool>(r => r.ReadBoolean());
|
||||||
{
|
AddW<bool>(r => r.Write(false));
|
||||||
AddR<bool>(r => r.ReadBoolean());
|
|
||||||
AddW<bool>(r => r.Write(false));
|
AddR<sbyte>(r => r.ReadSByte());
|
||||||
|
AddW<sbyte>(r => r.Write((sbyte)0));
|
||||||
AddR<sbyte>(r => r.ReadSByte());
|
|
||||||
AddW<sbyte>(r => r.Write((sbyte)0));
|
AddR<byte>(r => r.ReadByte());
|
||||||
|
AddW<byte>(r => r.Write((byte)0));
|
||||||
AddR<byte>(r => r.ReadByte());
|
|
||||||
AddW<byte>(r => r.Write((byte)0));
|
AddR<short>(r => r.ReadInt16());
|
||||||
|
AddW<short>(r => r.Write((short)0));
|
||||||
AddR<short>(r => r.ReadInt16());
|
|
||||||
AddW<short>(r => r.Write((short)0));
|
AddR<ushort>(r => r.ReadUInt16());
|
||||||
|
AddW<ushort>(r => r.Write((ushort)0));
|
||||||
AddR<ushort>(r => r.ReadUInt16());
|
|
||||||
AddW<ushort>(r => r.Write((ushort)0));
|
AddR<int>(r => r.ReadInt32());
|
||||||
|
AddW<int>(r => r.Write((int)0));
|
||||||
AddR<int>(r => r.ReadInt32());
|
|
||||||
AddW<int>(r => r.Write((int)0));
|
AddR<uint>(r => r.ReadUInt32());
|
||||||
|
AddW<uint>(r => r.Write((uint)0));
|
||||||
AddR<uint>(r => r.ReadUInt32());
|
|
||||||
AddW<uint>(r => r.Write((uint)0));
|
AddR<long>(r => r.ReadInt64());
|
||||||
|
AddW<long>(r => r.Write((long)0));
|
||||||
AddR<long>(r => r.ReadInt64());
|
|
||||||
AddW<long>(r => r.Write((long)0));
|
AddR<ulong>(r => r.ReadUInt64());
|
||||||
|
AddW<ulong>(r => r.Write((ulong)0));
|
||||||
AddR<ulong>(r => r.ReadUInt64());
|
}
|
||||||
AddW<ulong>(r => r.Write((ulong)0));
|
|
||||||
}
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#region dynamic code generation
|
||||||
|
|
||||||
#region dynamic code generation
|
private delegate void Reader(object target, BinaryReader r);
|
||||||
|
private delegate void Writer(object target, BinaryWriter w);
|
||||||
private delegate void Reader(object target, BinaryReader r);
|
|
||||||
private delegate void Writer(object target, BinaryWriter w);
|
private class SerializationFactory
|
||||||
|
{
|
||||||
private class SerializationFactory
|
public Type Type;
|
||||||
{
|
public Reader Read;
|
||||||
public Type Type;
|
public Writer Write;
|
||||||
public Reader Read;
|
}
|
||||||
public Writer Write;
|
|
||||||
}
|
private static SerializationFactory CreateFactory(Type t)
|
||||||
|
{
|
||||||
private static SerializationFactory CreateFactory(Type t)
|
var fields = DeepEquality.GetAllFields(t)
|
||||||
{
|
////.OrderBy(fi => (int)fi.GetManagedOffset()) // [StructLayout.Sequential] doesn't work with this
|
||||||
var fields = DeepEquality.GetAllFields(t)
|
.OrderBy(fi => (int)Marshal.OffsetOf(t, fi.Name))
|
||||||
////.OrderBy(fi => (int)fi.GetManagedOffset()) // [StructLayout.Sequential] doesn't work with this
|
.ToList();
|
||||||
.OrderBy(fi => (int)Marshal.OffsetOf(t, fi.Name))
|
|
||||||
.ToList();
|
var rmeth = new DynamicMethod(t.Name + "_r", null, new[] { typeof(object), typeof(BinaryReader) }, true);
|
||||||
|
var wmeth = new DynamicMethod(t.Name + "_w", null, new[] { typeof(object), typeof(BinaryWriter) }, true);
|
||||||
var rmeth = new DynamicMethod(t.Name + "_r", null, new[] { typeof(object), typeof(BinaryReader) }, true);
|
|
||||||
var wmeth = new DynamicMethod(t.Name + "_w", null, new[] { typeof(object), typeof(BinaryWriter) }, true);
|
{
|
||||||
|
var il = rmeth.GetILGenerator();
|
||||||
{
|
var target = il.DeclareLocal(t);
|
||||||
var il = rmeth.GetILGenerator();
|
il.Emit(OpCodes.Ldarg_0);
|
||||||
var target = il.DeclareLocal(t);
|
il.Emit(OpCodes.Castclass, t);
|
||||||
il.Emit(OpCodes.Ldarg_0);
|
il.Emit(OpCodes.Stloc, target);
|
||||||
il.Emit(OpCodes.Castclass, t);
|
|
||||||
il.Emit(OpCodes.Stloc, target);
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
foreach (var field in fields)
|
il.Emit(OpCodes.Ldloc, target);
|
||||||
{
|
il.Emit(OpCodes.Ldarg_1);
|
||||||
il.Emit(OpCodes.Ldloc, target);
|
MethodInfo m;
|
||||||
il.Emit(OpCodes.Ldarg_1);
|
if (!Readhandlers.TryGetValue(field.FieldType, out m))
|
||||||
MethodInfo m;
|
{
|
||||||
if (!Readhandlers.TryGetValue(field.FieldType, out m))
|
throw new InvalidOperationException("(R) Can't handle nested type " + field.FieldType);
|
||||||
{
|
}
|
||||||
throw new InvalidOperationException("(R) Can't handle nested type " + field.FieldType);
|
|
||||||
}
|
il.Emit(OpCodes.Callvirt, m);
|
||||||
|
il.Emit(OpCodes.Stfld, field);
|
||||||
il.Emit(OpCodes.Callvirt, m);
|
}
|
||||||
il.Emit(OpCodes.Stfld, field);
|
|
||||||
}
|
il.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
il.Emit(OpCodes.Ret);
|
|
||||||
}
|
{
|
||||||
|
var il = wmeth.GetILGenerator();
|
||||||
{
|
var target = il.DeclareLocal(t);
|
||||||
var il = wmeth.GetILGenerator();
|
il.Emit(OpCodes.Ldarg_0);
|
||||||
var target = il.DeclareLocal(t);
|
il.Emit(OpCodes.Castclass, t);
|
||||||
il.Emit(OpCodes.Ldarg_0);
|
il.Emit(OpCodes.Stloc, target);
|
||||||
il.Emit(OpCodes.Castclass, t);
|
|
||||||
il.Emit(OpCodes.Stloc, target);
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
foreach (var field in fields)
|
il.Emit(OpCodes.Ldarg_1);
|
||||||
{
|
il.Emit(OpCodes.Ldloc, target);
|
||||||
il.Emit(OpCodes.Ldarg_1);
|
il.Emit(OpCodes.Ldfld, field);
|
||||||
il.Emit(OpCodes.Ldloc, target);
|
MethodInfo m;
|
||||||
il.Emit(OpCodes.Ldfld, field);
|
if (!Writehandlers.TryGetValue(field.FieldType, out m))
|
||||||
MethodInfo m;
|
{
|
||||||
if (!Writehandlers.TryGetValue(field.FieldType, out m))
|
throw new InvalidOperationException("(W) Can't handle nested type " + field.FieldType);
|
||||||
{
|
}
|
||||||
throw new InvalidOperationException("(W) Can't handle nested type " + field.FieldType);
|
|
||||||
}
|
il.Emit(OpCodes.Callvirt, m);
|
||||||
|
}
|
||||||
il.Emit(OpCodes.Callvirt, m);
|
|
||||||
}
|
il.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
il.Emit(OpCodes.Ret);
|
|
||||||
}
|
return new SerializationFactory
|
||||||
|
{
|
||||||
return new SerializationFactory
|
Type = t,
|
||||||
{
|
Read = (Reader)rmeth.CreateDelegate(typeof(Reader)),
|
||||||
Type = t,
|
Write = (Writer)wmeth.CreateDelegate(typeof(Writer))
|
||||||
Read = (Reader)rmeth.CreateDelegate(typeof(Reader)),
|
};
|
||||||
Write = (Writer)wmeth.CreateDelegate(typeof(Writer))
|
}
|
||||||
};
|
|
||||||
}
|
#endregion
|
||||||
|
|
||||||
#endregion
|
private static readonly IDictionary<Type, SerializationFactory> Serializers =
|
||||||
|
new ConcurrentDictionary<Type, SerializationFactory>();
|
||||||
private static readonly IDictionary<Type, SerializationFactory> Serializers =
|
|
||||||
new ConcurrentDictionary<Type, SerializationFactory>();
|
private static SerializationFactory GetFactory(Type t)
|
||||||
|
{
|
||||||
private static SerializationFactory GetFactory(Type t)
|
SerializationFactory f;
|
||||||
{
|
if (!Serializers.TryGetValue(t, out f))
|
||||||
SerializationFactory f;
|
{
|
||||||
if (!Serializers.TryGetValue(t, out f))
|
f = CreateFactory(t);
|
||||||
{
|
Serializers[t] = f;
|
||||||
f = CreateFactory(t);
|
}
|
||||||
Serializers[t] = f;
|
|
||||||
}
|
return f;
|
||||||
|
}
|
||||||
return f;
|
|
||||||
}
|
public static T Create<T>(BinaryReader r)
|
||||||
|
where T : new()
|
||||||
public static T Create<T>(BinaryReader r)
|
{
|
||||||
where T : new()
|
T target = new T();
|
||||||
{
|
Read(target, r);
|
||||||
T target = new T();
|
return target;
|
||||||
Read(target, r);
|
}
|
||||||
return target;
|
|
||||||
}
|
public static object Create(Type t, BinaryReader r)
|
||||||
|
{
|
||||||
public static object Create(Type t, BinaryReader r)
|
object target = Activator.CreateInstance(t);
|
||||||
{
|
Read(target, r);
|
||||||
object target = Activator.CreateInstance(t);
|
return target;
|
||||||
Read(target, r);
|
}
|
||||||
return target;
|
|
||||||
}
|
public static void Read(object target, BinaryReader r)
|
||||||
|
{
|
||||||
public static void Read(object target, BinaryReader r)
|
GetFactory(target.GetType()).Read(target, r);
|
||||||
{
|
}
|
||||||
GetFactory(target.GetType()).Read(target, r);
|
|
||||||
}
|
public static void Write(object target, BinaryWriter w)
|
||||||
|
{
|
||||||
public static void Write(object target, BinaryWriter w)
|
GetFactory(target.GetType()).Write(target, w);
|
||||||
{
|
}
|
||||||
GetFactory(target.GetType()).Write(target, w);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
|
@ -87,6 +87,7 @@
|
||||||
<Link>VersionInfo.cs</Link>
|
<Link>VersionInfo.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="AWEMemoryStream.cs" />
|
<Compile Include="AWEMemoryStream.cs" />
|
||||||
|
<Compile Include="BinaryQuickSerializer.cs" />
|
||||||
<Compile Include="Bit.cs" />
|
<Compile Include="Bit.cs" />
|
||||||
<Compile Include="BitReverse.cs" />
|
<Compile Include="BitReverse.cs" />
|
||||||
<Compile Include="Buffer.cs" />
|
<Compile Include="Buffer.cs" />
|
||||||
|
|
|
@ -104,7 +104,6 @@
|
||||||
<Compile Include="Base Implementations\NullVideo.cs" />
|
<Compile Include="Base Implementations\NullVideo.cs" />
|
||||||
<Compile Include="Base Implementations\SimpleSyncSoundProvider.cs" />
|
<Compile Include="Base Implementations\SimpleSyncSoundProvider.cs" />
|
||||||
<Compile Include="Base Implementations\TraceBuffer.cs" />
|
<Compile Include="Base Implementations\TraceBuffer.cs" />
|
||||||
<Compile Include="BinaryQuickSerializer.cs" />
|
|
||||||
<Compile Include="BizInvoke\BizInvoker.cs" />
|
<Compile Include="BizInvoke\BizInvoker.cs" />
|
||||||
<Compile Include="BizInvoke\DynamicLibraryImportResolver.cs" />
|
<Compile Include="BizInvoke\DynamicLibraryImportResolver.cs" />
|
||||||
<Compile Include="Base Implementations\CodeDataLog.cs" />
|
<Compile Include="Base Implementations\CodeDataLog.cs" />
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue