Resolvers
Array3CodeGenResolver.cs
using Bssom.Serializer.Binary;
using Bssom.Serializer.BssMap;
using Bssom.Serializer.BssMap.KeyResolvers;
using Bssom.Serializer.BssomBuffer;
using Bssom.Serializer.Internal;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
namespace Bssom.Serializer.Resolvers
{
public sealed clast Array3CodeGenResolver : IFormatterResolver
{
internal const string ModuleName = "Bssom.Serializer.Resolvers.Array3CodeGenResolver";
internal static readonly DynamicFormatterastembly Dynamicastembly;
///
/// The singleton instance that can be used.
///
public static readonly Array3CodeGenResolver Instance;
static Array3CodeGenResolver()
{
Instance = new Array3CodeGenResolver();
Dynamicastembly = new DynamicFormatterastembly(ModuleName);
}
public IBssomFormatter GetFormatter()
{
return FormatterCache.Formatter;
}
private static clast FormatterCache
{
public static readonly IBssomFormatter Formatter;
static FormatterCache()
{
Type t = typeof(T);
Formatter = (IBssomFormatter)Activator.CreateInstance(Array3CodeGenResolverBuilder.Build(Dynamicastembly, new ObjectSerializationInfo(t, false)));
}
}
#if NETFRAMEWORK
public astemblyBuilder Save()
{
return Dynamicastembly.Save();
}
#endif
}
}
namespace Bssom.Serializer.Internal
{
internal static clast Array3CodeGenResolverBuilder
{
public static TypeInfo Build(DynamicFormatterastembly astembly, ObjectSerializationInfo serializationInfo)
{
Type type = serializationInfo.Type;
TypeBuilder typeBuilder = astembly.DefineFormatterType(type);
serializationInfo.SerializeMemberInfosOrderByKeyIndex(type);
MethodBuilder serializeMethod = TypeBuildHelper.DefineSerializeMethod(typeBuilder, type);
MethodBuilder deserializeMethod = TypeBuildHelper.DefineDeserializeMethod(typeBuilder, type);
MethodBuilder sizeMethod = TypeBuildHelper.DefineSizeMethod(typeBuilder, type);
Type delegateCacheType = typeof(Array3DelegateCache).MakeGenericType(type);
delegateCacheType.GetMethod(nameof(Array3DelegateCache.Factory), BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { astembly, serializationInfo });
TypeBuildHelper.CallSerializeDelegate(serializeMethod, type, delegateCacheType.GetField(nameof(Array3DelegateCache.Serialize)));
TypeBuildHelper.CallSizeDelegate(sizeMethod, type, delegateCacheType.GetField(nameof(Array3DelegateCache.Size)));
TypeBuildHelper.CallDeserializeDelegate(deserializeMethod, type, delegateCacheType.GetField(nameof(Array3DelegateCache.Deserialize)));
return typeBuilder.CreateTypeInfo();
}
private static void SerializeMemberInfosOrderByKeyIndex(this ObjectSerializationInfo serializationInfo, Type type)
{
if (serializationInfo.SerializeMemberInfos.Length > 0)
{
serializationInfo.SerializeMemberInfos = serializationInfo.SerializeMemberInfos.OrderBy(e => e.KeyIndex).ToArray();
SerializeMemberInfo[] serializeMemberInfos = serializationInfo.SerializeMemberInfos;
for (int i = 0; i < serializeMemberInfos.Length; i++)
{
var mem = serializeMemberInfos[i];
if (!mem.KeyIndexHasValue)
throw BssomSerializationTypeFormatterException.Array3MembersMustDefindKeyAttribute(type, mem.Name);
if (i != 0 && mem.KeyIndex == serializeMemberInfos[i - 1].KeyIndex)
throw BssomSerializationTypeFormatterException.Array3KeyAttributeValueRepeated(type);
}
}
}
}
internal static clast Array3DynamicExpressionBuild
{
#region Serialize
public static Expression BuildSerializeLambda(ObjectSerializationInfo serializationInfo, ParameterExpression instance)
{
return Expression.Lambda(BuildSerializeCore(typeof(T), serializationInfo, instance), CommonExpressionMeta.Par_Writer, CommonExpressionMeta.Par_SerializeContext, instance);
}
public unsafe static IntPtr AsPointer(ref T t)
{
return new IntPtr(Unsafe.AsPointer(ref t));
}
private static Expression BuildSerializeCore(Type type, ObjectSerializationInfo serializationInfo, ParameterExpression instance)
{
List ary = new List();
LabelTarget returnTarget = Expression.Label(typeof(void), "returnLable");
if (!type.IsValueType)
{
//if (value==null)
// writer.WriteNull(); goto label;
ary.Add(CommonExpressionMeta.Block_IfNullWriteNullWithReturn(instance, type, returnTarget));
}
ParameterExpression[] variables = null;
var keys = serializationInfo.SerializeMemberInfos;
if (keys.Length == 0)
{
//writer.WriteRaw(Array3Cache._EmptyBuffer);
ary.Add(CommonExpressionMeta.Call_WriteRaw(Expression.Field(null, Array3Cache._EmptyBuffer)));
}
else
{
int maxLen = keys[keys.Length - 1].KeyIndex + 1;
Type stackallocBlockType = StackallocBlockProvider.GetOrCreateType(maxLen * sizeof(uint));
//long position;
//Block{size} block;
//IntPtr blockPtr;
variables = new ParameterExpression[3];
variables[0] = Expression.Variable(typeof(long), "elementOffPosition");
variables[1] = Expression.Variable(stackallocBlockType, "block");
variables[2] = Expression.Variable(typeof(IntPtr),"blockPtr");
//position = writer.WriteArray3Header(keys.Length);
ary.Add(Expression.astign(variables[0], CommonExpressionMeta.Call_WriteArray3Header(maxLen)));
//block = new Block{size}();
ary.Add(Expression.astign(variables[1], Expression.New(stackallocBlockType)));
//blockPtr = AsPointer(ref block);
ary.Add(Expression.astign(variables[2], ExpressionTreeAux.AsPointerExpression(variables[1])));
//0,3,5 --> maxLen = 6
FieldInfo memFormatters = serializationInfo.StoreMemberFormatterInstances();
int realIndex = 0;
for (int i = 0; i < maxLen; i++)
{
//StackallocBlockHelper.WriteUInt(blockPtr, 0, (uint)(writer.Position - position));
ary.Add(Expression.Call(null, StackallocBlockHelper._WriteUIntMethodInfo, variables[2], Expression.Constant(i), Expression.Convert(Expression.Subtract(CommonExpressionMeta.Field_WriterPos, variables[0]), typeof(uint))));
if (keys[realIndex].KeyIndex != i)
{
//WriteNull()
ary.Add(CommonExpressionMeta.Call_Writer_WriteNull);
}
else
{
//Writer(mem.Value)
ary.Add(SpecialCodeGenExpression.WriteValues(keys[realIndex], instance, memFormatters));
realIndex++;
}
}
//writer.WriteBackArray3Header(blockPtr)
ary.Add(CommonExpressionMeta.Call_WriteBackArray3Header(variables[0], variables[2], maxLen));
}
ary.Add(Expression.Label(returnTarget));
if (variables != null)
return Expression.Block(variables, ary);
return Expression.Block(ary);
}
#endregion
#region Deserialize
public static Expression BuildDeserializeLambda(ObjectSerializationInfo serializationInfo)
{
return Expression.Lambda(BuildDeserializeCore(typeof(T), serializationInfo), CommonExpressionMeta.Par_Reader, CommonExpressionMeta.Par_DeserializeContext);
}
private static Expression BuildDeserializeCore(Type t, ObjectSerializationInfo serializationInfo)
{
List ary = new List();
LabelTarget returnTarget = Expression.Label(t, "returnLable");
//int num;
ParameterExpression num = Expression.Variable(typeof(int), "num");
//int for-i;
ParameterExpression forVariable = Expression.Variable(typeof(int), "i");
//context.option.Security.DepthStep(ref reader);
ary.Add(CommonExpressionMeta.Call_DeserializeContext_Option_Security_DepthStep);
//if(reader.TryReadNullWithEnsureBuildInType(BssomType.Array3))
// return default(t);
ary.Add(Expression.IfThen(CommonExpressionMeta.Call_Reader_TryReadNullWithEnsureBuildInType(BssomType.Array3),
Expression.Return(returnTarget, Expression.Default(t))));
//T t = new T();
ParameterExpression instance = Expression.Parameter(t, "instance");
if (serializationInfo.IsDefaultNoArgsCtor)
{
ary.Add(Expression.astign(instance, Expression.New(t)));
}
else
{
ParameterInfo[] parInfos = serializationInfo.BestmatchConstructor.GetParameters();
Expression[] pars = new Expression[parInfos.Length];
if (serializationInfo.ConstructorParametersIsDefaultValue)
{
for (int i = 0; i < parInfos.Length; i++)
{
pars[i] = Expression.Default(parInfos[i].ParameterType);
}
ary.Add(Expression.astign(instance, Expression.New(serializationInfo.BestmatchConstructor, pars)));
}
else
{
object[] cps = serializationInfo.ConstructorParameters;
for (int i = 0; i < parInfos.Length; i++)
{
pars[i] = Expression.Constant(cps[i], parInfos[i].ParameterType);
}
ary.Add(Expression.astign(instance, Expression.New(serializationInfo.BestmatchConstructor, pars)));
}
}
//reader.SkipVariableNumber()
ary.Add(CommonExpressionMeta.Call_Reader_SkipVariableNumber);
//num = reader.ReadVariableNumber()
ary.Add(Expression.astign(num, CommonExpressionMeta.Call_Reader_ReadVariableNumber));
//i = 0;
ary.Add(Expression.astign(forVariable, Expression.Constant(0)));
var members = serializationInfo.SerializeMemberInfos;
if (members.Length > 0)
{
//reader.Buffer.Seek(offsetSegment, Current)
ary.Add(CommonExpressionMeta.Call_Reader_BufferSeek(Expression.Convert(Expression.Multiply(num, Expression.Constant(BssomBinaryPrimitives.FixUInt32NumberSize)), typeof(Int64)), BssomSeekOrgin.Current));
//switch(i)
// case 0: instance.Key0 = readValue();
// case 3: instance.Key1 = readValue();
// case 5: instance.Key2 = readValue();
// default: skipObj();
FieldInfo memFormatters = serializationInfo.StoreMemberFormatterInstances();
SwitchCase[] switchCases = new SwitchCase[members.Length];
for (int i = 0; i < members.Length; i++)
{
switchCases[i] = Expression.SwitchCase(SpecialCodeGenExpression.ReadValues(members[i], instance, memFormatters), Expression.Constant(members[i].KeyIndex));
}
Expression content = Expression.Switch(
typeof(void),
forVariable,
CommonExpressionMeta.Call_Reader_SkipObject,
null,
switchCases
);
ary.Add(For(forVariable, Expression.LessThan(forVariable, num), Expression.astign(forVariable, Expression.Add(forVariable, Expression.Constant(1))), content));
}
//context.Depth--;
ary.Add(CommonExpressionMeta.Call_DeserializeContext_Depth_Decrementastign);
ary.Add(Expression.Return(returnTarget, instance));
ary.Add(Expression.Label(returnTarget, instance));
return Expression.Block(new ParameterExpression[] { instance, num, forVariable, }, ary);
}
private static Expression For(ParameterExpression loopVar, Expression condition, Expression increment, Expression loopContent)
{
var initastign = Expression.astign(loopVar, Expression.Constant(0));
var breakLabel = Expression.Label("LoopBreak");
var loop = Expression.Block(
initastign,
Expression.Loop(
Expression.IfThenElse(
condition,
Expression.Block(
loopContent,
increment
),
Expression.Break(breakLabel)
),
breakLabel)
);
return loop;
}
#endregion
#region Size
public static Expression BuildSizeLambda(ObjectSerializationInfo serializationInfo, ParameterExpression instance)
{
return Expression.Lambda(BuildSizeCore(typeof(T), serializationInfo, instance), CommonExpressionMeta.Par_SizeContext, instance);
}
private static Expression BuildSizeCore(Type type, ObjectSerializationInfo serializationInfo, ParameterExpression instance)
{
List ary = new List();
LabelTarget returnTarget = Expression.Label(typeof(int), "returnLable");
if (!type.IsValueType)
{
//if (value==null)
// goto label: 1;
ary.Add(CommonExpressionMeta.Block_IfNullSize(instance, type, returnTarget));
}
ParameterExpression size = Expression.Variable(typeof(int));
SerializeMemberInfo[] mems = serializationInfo.SerializeMemberInfos;
if (mems.Length == 0)
{
ary.Add(Expression.astign(size, Expression.Constant(Array3Cache.Empty.Length)));
}
else
{
int maxLen = mems[mems.Length - 1].KeyIndex + 1;
ary.Add(Expression.astign(size, Expression.Constant(BssomBinaryPrimitives.Array3HeaderSize(maxLen))));
FieldInfo memFormatters = serializationInfo.StoreMemberFormatterInstances();
int nullNumber = 0;
int realIndex = 0;
for (int i = 0; i < maxLen; i++)
{
if (mems[realIndex].KeyIndex != i)
{
nullNumber++;
}
else
{
//Size(mem.Value)
ary.Add(SpecialCodeGenExpression.SizeValues(mems[realIndex], instance, size, memFormatters));
realIndex++;
}
}
if (nullNumber > 0)
ary.Add(Expression.Addastign(size, Expression.Constant(nullNumber * BssomBinaryPrimitives.NullSize)));
}
ary.Add(Expression.Label(returnTarget, size));
return Expression.Block(new ParameterExpression[] { size }, ary);
}
#endregion
}
internal static clast Array3DelegateCache
{
public static Serialize Serialize;
public static Deserialize Deserialize;
public static Size Size;
internal static void Factory(DynamicFormatterastembly astembly, ObjectSerializationInfo objectSerializationInfo)
{
ParameterExpression instance = Expression.Parameter(objectSerializationInfo.Type, "value");
Expression serializeExpression = Array3DynamicExpressionBuild.BuildSerializeLambda(objectSerializationInfo, instance);
Expression sizeExpression = Array3DynamicExpressionBuild.BuildSizeLambda(objectSerializationInfo, instance);
Expression deserializeExpression = Array3DynamicExpressionBuild.BuildDeserializeLambda(objectSerializationInfo);
Serialize = serializeExpression.Compile();
Size = sizeExpression.Compile();
Deserialize = deserializeExpression.Compile();
#if NETFRAMEWORK
TypeBuilder typeBuilder = astembly.DefineFormatterDelegateType(objectSerializationInfo.Type);
MethodBuilder serializeDelegate = TypeBuildHelper.DefineSerializeDelegate(typeBuilder, typeof(T));
serializeExpression.CompileToMethod(serializeDelegate);
MethodBuilder sizeDelegate = TypeBuildHelper.DefineSizeDelegate(typeBuilder, typeof(T));
sizeExpression.CompileToMethod(sizeDelegate);
MethodBuilder deserializeDelegate = TypeBuildHelper.DefineDeserializeDelegate(typeBuilder, typeof(T));
deserializeExpression.CompileToMethod(deserializeDelegate);
typeBuilder.CreateTypeInfo();
#endif
}
}
internal static clast Array3Cache
{
public static readonly FieldInfo _EmptyBuffer = typeof(Array3Cache).GetField(nameof(Empty));
public static byte[] Empty;
static Array3Cache()
{
ExpandableBufferWriter bw = ExpandableBufferWriter.CreateTemporary();
BssomWriter cw = new BssomWriter(bw);
cw.WriteBuildInType(BssomType.Array3);
cw.WriteVariableNumber(BssomBinaryPrimitives.FixUInt32NumberSize);//len
cw.WriteUInt32FixNumber(0);//count
Empty = bw.GetBufferedArray();
}
}
}