Move BinaryQuickSerializer from Emulation.Common to Common

This commit is contained in:
adelikat 2017-05-01 17:26:39 -05:00
parent ffd743cac7
commit e1750bdce9
4 changed files with 223 additions and 227 deletions

View File

@ -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); }
} }
}
}

View File

@ -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" />

View File

@ -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" />

View File

@ -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;