From e1750bdce9aaf8e1971b9641816949a5837cbe28 Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 1 May 2017 17:26:39 -0500 Subject: [PATCH] Move BinaryQuickSerializer from Emulation.Common to Common --- .../BinaryQuickSerializer.cs | 444 +++++++++--------- BizHawk.Common/BizHawk.Common.csproj | 1 + .../BizHawk.Emulation.Common.csproj | 1 - .../WonderSwan/WonderSwan.IStatable.cs | 4 +- 4 files changed, 223 insertions(+), 227 deletions(-) rename {BizHawk.Emulation.Common => BizHawk.Common}/BinaryQuickSerializer.cs (95%) diff --git a/BizHawk.Emulation.Common/BinaryQuickSerializer.cs b/BizHawk.Common/BinaryQuickSerializer.cs similarity index 95% rename from BizHawk.Emulation.Common/BinaryQuickSerializer.cs rename to BizHawk.Common/BinaryQuickSerializer.cs index 7801d74023..7db5441720 100644 --- a/BizHawk.Emulation.Common/BinaryQuickSerializer.cs +++ b/BizHawk.Common/BinaryQuickSerializer.cs @@ -1,223 +1,221 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.InteropServices; - -using 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] - public class BinaryQuickSerializer - { - #region methodinfo from a lambda expression. cool. - - private static MethodInfo FromExpression(Expression e) - { - var caller = e as MethodCallExpression; - if (caller == null) - { - throw new ArgumentException("Expression must be a method call"); - } - - return caller.Method; - } - - private static MethodInfo Method(Expression f) - { - return FromExpression(f.Body); - } - - private static MethodInfo Method(Expression> f) - { - return FromExpression(f.Body); - } - - #endregion - - #region read and write handlers for individual fields - - private static readonly Dictionary Readhandlers = new Dictionary(); - private static readonly Dictionary Writehandlers = new Dictionary(); - - private static void AddR(Expression> f) - { - var method = Method(f); - if (!typeof(T).IsAssignableFrom(method.ReturnType)) - { - throw new InvalidOperationException("Type mismatch"); - } - - Readhandlers.Add(typeof(T), method); - } - - private static void AddW(Expression> f) - { - var method = Method(f); - if (!method.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(T))) - { - throw new InvalidOperationException("Type mismatch"); - } - - Writehandlers.Add(typeof(T), Method(f)); - } - - static BinaryQuickSerializer() - { - AddR(r => r.ReadBoolean()); - AddW(r => r.Write(false)); - - AddR(r => r.ReadSByte()); - AddW(r => r.Write((sbyte)0)); - - AddR(r => r.ReadByte()); - AddW(r => r.Write((byte)0)); - - AddR(r => r.ReadInt16()); - AddW(r => r.Write((short)0)); - - AddR(r => r.ReadUInt16()); - AddW(r => r.Write((ushort)0)); - - AddR(r => r.ReadInt32()); - AddW(r => r.Write((int)0)); - - AddR(r => r.ReadUInt32()); - AddW(r => r.Write((uint)0)); - - AddR(r => r.ReadInt64()); - AddW(r => r.Write((long)0)); - - AddR(r => r.ReadUInt64()); - AddW(r => r.Write((ulong)0)); - } - - #endregion - - #region dynamic code generation - - private delegate void Reader(object target, BinaryReader r); - private delegate void Writer(object target, BinaryWriter w); - - private class SerializationFactory - { - public Type Type; - public Reader Read; - public Writer Write; - } - - private static SerializationFactory CreateFactory(Type t) - { - var fields = DeepEquality.GetAllFields(t) - ////.OrderBy(fi => (int)fi.GetManagedOffset()) // [StructLayout.Sequential] doesn't work with this - .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 il = rmeth.GetILGenerator(); - var target = il.DeclareLocal(t); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Castclass, t); - il.Emit(OpCodes.Stloc, target); - - foreach (var field in fields) - { - il.Emit(OpCodes.Ldloc, target); - il.Emit(OpCodes.Ldarg_1); - MethodInfo m; - if (!Readhandlers.TryGetValue(field.FieldType, out m)) - { - throw new InvalidOperationException("(R) Can't handle nested type " + field.FieldType); - } - - il.Emit(OpCodes.Callvirt, m); - il.Emit(OpCodes.Stfld, field); - } - - il.Emit(OpCodes.Ret); - } - - { - var il = wmeth.GetILGenerator(); - var target = il.DeclareLocal(t); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Castclass, t); - il.Emit(OpCodes.Stloc, target); - - foreach (var field in fields) - { - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldloc, target); - il.Emit(OpCodes.Ldfld, field); - MethodInfo m; - if (!Writehandlers.TryGetValue(field.FieldType, out m)) - { - throw new InvalidOperationException("(W) Can't handle nested type " + field.FieldType); - } - - il.Emit(OpCodes.Callvirt, m); - } - - il.Emit(OpCodes.Ret); - } - - return new SerializationFactory - { - Type = t, - Read = (Reader)rmeth.CreateDelegate(typeof(Reader)), - Write = (Writer)wmeth.CreateDelegate(typeof(Writer)) - }; - } - - #endregion - - private static readonly IDictionary Serializers = - new ConcurrentDictionary(); - - private static SerializationFactory GetFactory(Type t) - { - SerializationFactory f; - if (!Serializers.TryGetValue(t, out f)) - { - f = CreateFactory(t); - Serializers[t] = f; - } - - return f; - } - - public static T Create(BinaryReader r) - where T : new() - { - T target = new T(); - Read(target, r); - return target; - } - - public static object Create(Type t, BinaryReader r) - { - object target = Activator.CreateInstance(t); - Read(target, r); - return target; - } - - public static void Read(object target, BinaryReader r) - { - GetFactory(target.GetType()).Read(target, r); - } - - public static void Write(object target, BinaryWriter w) - { - GetFactory(target.GetType()).Write(target, w); - } - } -} +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; + +namespace BizHawk.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] + public class BinaryQuickSerializer + { + #region methodinfo from a lambda expression. cool. + + private static MethodInfo FromExpression(Expression e) + { + var caller = e as MethodCallExpression; + if (caller == null) + { + throw new ArgumentException("Expression must be a method call"); + } + + return caller.Method; + } + + private static MethodInfo Method(Expression f) + { + return FromExpression(f.Body); + } + + private static MethodInfo Method(Expression> f) + { + return FromExpression(f.Body); + } + + #endregion + + #region read and write handlers for individual fields + + private static readonly Dictionary Readhandlers = new Dictionary(); + private static readonly Dictionary Writehandlers = new Dictionary(); + + private static void AddR(Expression> f) + { + var method = Method(f); + if (!typeof(T).IsAssignableFrom(method.ReturnType)) + { + throw new InvalidOperationException("Type mismatch"); + } + + Readhandlers.Add(typeof(T), method); + } + + private static void AddW(Expression> f) + { + var method = Method(f); + if (!method.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(T))) + { + throw new InvalidOperationException("Type mismatch"); + } + + Writehandlers.Add(typeof(T), Method(f)); + } + + static BinaryQuickSerializer() + { + AddR(r => r.ReadBoolean()); + AddW(r => r.Write(false)); + + AddR(r => r.ReadSByte()); + AddW(r => r.Write((sbyte)0)); + + AddR(r => r.ReadByte()); + AddW(r => r.Write((byte)0)); + + AddR(r => r.ReadInt16()); + AddW(r => r.Write((short)0)); + + AddR(r => r.ReadUInt16()); + AddW(r => r.Write((ushort)0)); + + AddR(r => r.ReadInt32()); + AddW(r => r.Write((int)0)); + + AddR(r => r.ReadUInt32()); + AddW(r => r.Write((uint)0)); + + AddR(r => r.ReadInt64()); + AddW(r => r.Write((long)0)); + + AddR(r => r.ReadUInt64()); + AddW(r => r.Write((ulong)0)); + } + + #endregion + + #region dynamic code generation + + private delegate void Reader(object target, BinaryReader r); + private delegate void Writer(object target, BinaryWriter w); + + private class SerializationFactory + { + public Type Type; + public Reader Read; + public Writer Write; + } + + private static SerializationFactory CreateFactory(Type t) + { + var fields = DeepEquality.GetAllFields(t) + ////.OrderBy(fi => (int)fi.GetManagedOffset()) // [StructLayout.Sequential] doesn't work with this + .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 il = rmeth.GetILGenerator(); + var target = il.DeclareLocal(t); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, t); + il.Emit(OpCodes.Stloc, target); + + foreach (var field in fields) + { + il.Emit(OpCodes.Ldloc, target); + il.Emit(OpCodes.Ldarg_1); + MethodInfo m; + if (!Readhandlers.TryGetValue(field.FieldType, out m)) + { + throw new InvalidOperationException("(R) Can't handle nested type " + field.FieldType); + } + + il.Emit(OpCodes.Callvirt, m); + il.Emit(OpCodes.Stfld, field); + } + + il.Emit(OpCodes.Ret); + } + + { + var il = wmeth.GetILGenerator(); + var target = il.DeclareLocal(t); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, t); + il.Emit(OpCodes.Stloc, target); + + foreach (var field in fields) + { + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldloc, target); + il.Emit(OpCodes.Ldfld, field); + MethodInfo m; + if (!Writehandlers.TryGetValue(field.FieldType, out m)) + { + throw new InvalidOperationException("(W) Can't handle nested type " + field.FieldType); + } + + il.Emit(OpCodes.Callvirt, m); + } + + il.Emit(OpCodes.Ret); + } + + return new SerializationFactory + { + Type = t, + Read = (Reader)rmeth.CreateDelegate(typeof(Reader)), + Write = (Writer)wmeth.CreateDelegate(typeof(Writer)) + }; + } + + #endregion + + private static readonly IDictionary Serializers = + new ConcurrentDictionary(); + + private static SerializationFactory GetFactory(Type t) + { + SerializationFactory f; + if (!Serializers.TryGetValue(t, out f)) + { + f = CreateFactory(t); + Serializers[t] = f; + } + + return f; + } + + public static T Create(BinaryReader r) + where T : new() + { + T target = new T(); + Read(target, r); + return target; + } + + public static object Create(Type t, BinaryReader r) + { + object target = Activator.CreateInstance(t); + Read(target, r); + return target; + } + + public static void Read(object target, BinaryReader r) + { + GetFactory(target.GetType()).Read(target, r); + } + + public static void Write(object target, BinaryWriter w) + { + GetFactory(target.GetType()).Write(target, w); + } + } +} diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj index 56819dd327..f737438886 100644 --- a/BizHawk.Common/BizHawk.Common.csproj +++ b/BizHawk.Common/BizHawk.Common.csproj @@ -87,6 +87,7 @@ VersionInfo.cs + diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj index abd21a58ef..fd8bcc4236 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj @@ -104,7 +104,6 @@ - diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.IStatable.cs index d6241fcec0..a228dbb8ae 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.IStatable.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; using Newtonsoft.Json; +using BizHawk.Common; using BizHawk.Emulation.Common; using System.Runtime.InteropServices;