From 421782794032564f467b37a80dc1b3377c4ad51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?JasonXuDeveloper=20-=20=E5=82=91?= Date: Wed, 18 Oct 2023 22:39:11 +1100 Subject: [PATCH] [update] Nino.Serialization v1.2.2 Nino.Serialization v1.2.2 - [optimization] better generator and better size computation - [optimization] faster serialization/deserialization - [optimization] lowerge - [remove] no longer support ILRuntime --- Docs/Serialization.md | 104 +++-- ...ino_Test_BuildTestDataCodeGen_Serialize.cs | 30 +- .../Nino_Test_CustomTypeTest_Serialize.cs | 14 +- .../Generated/Nino_Test_Data_Serialize.cs | 18 +- ...o_Test_IncludeAllClassCodeGen_Serialize.cs | 10 +- .../Nino_Test_NotIncludeAllClass_Serialize.cs | 10 +- .../Nino/Serialization/CodeGenerator.cs | 139 ++++++- .../Assets/Nino/Serialization/Deserializer.cs | 123 ++++-- .../Nino/Serialization/ILRuntimeResolver.cs | 365 ------------------ .../Nino/Serialization/Reader.Generic.cs | 212 ++++++++++ .../Assets/Nino/Serialization/Reader.cs | 49 --- .../Nino/Serialization/Serializer.Generic.cs | 22 ++ .../Nino/Serialization/Serializer.Helper.cs | 69 ++-- .../Assets/Nino/Serialization/Serializer.cs | 50 +-- .../Assets/Nino/Serialization/TypeModel.cs | 48 ++- .../Nino/Serialization/Writer.Generic.cs | 217 ++++++++--- .../Assets/Nino/Serialization/Writer.cs | 24 -- Nino_Unity/Assets/Nino/Test/BuildTest.cs | 16 +- Nino_Unity/Assets/Nino/Test/BuildTest2.cs | 14 +- Nino_Unity/Assets/Nino/Test/Data.cs | 2 +- .../Test/Editor/Serialization/Test11.bytes | Bin 6656 -> 0 bytes .../Nino/Test/Editor/Serialization/Test11.cs | 31 -- .../Nino/Test/Editor/Serialization/Test7.cs | 99 ++--- README.md | 2 +- .../Nino_Benchmark_Models_Data_Serialize.cs | 18 +- src/Nino.Serialization/CodeGenerator.cs | 139 ++++++- src/Nino.Serialization/Deserializer.cs | 123 ++++-- src/Nino.Serialization/ILRuntimeResolver.cs | 365 ------------------ .../Nino.Serialization.csproj | 9 +- src/Nino.Serialization/Reader.Generic.cs | 212 ++++++++++ src/Nino.Serialization/Reader.cs | 49 --- src/Nino.Serialization/Serializer.Generic.cs | 22 ++ src/Nino.Serialization/Serializer.Helper.cs | 69 ++-- src/Nino.Serialization/Serializer.cs | 50 +-- src/Nino.Serialization/TypeModel.cs | 48 ++- src/Nino.Serialization/Writer.Generic.cs | 217 ++++++++--- src/Nino.Serialization/Writer.cs | 24 -- 37 files changed, 1590 insertions(+), 1423 deletions(-) delete mode 100644 Nino_Unity/Assets/Nino/Serialization/ILRuntimeResolver.cs delete mode 100644 Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.bytes delete mode 100644 Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.cs delete mode 100644 src/Nino.Serialization/ILRuntimeResolver.cs diff --git a/Docs/Serialization.md b/Docs/Serialization.md index 211b38d..5425da9 100644 --- a/Docs/Serialization.md +++ b/Docs/Serialization.md @@ -47,6 +47,8 @@ public partial struct NotIncludeAllClass > **强烈建议通过生成代码来提高性能,但是需要注意,每次更新字段或属性后需要重新生成代码来更新** > > 如果不需要序列化`字符串`或`非固定长度的集合(例如string[])`,则会生成非常高效的代码 +> +> **强烈推荐使用自动收集,这样会最大限度的优化生成出来的代码** @@ -54,6 +56,7 @@ public partial struct NotIncludeAllClass - 可以给已序列化的相同类型的字段/属性改名 - 可以给已序列化的字段/属性改成相同大小的类型(`int`->`uint`,`int`->`float`,`List`->`List`->`List - List<可Nino序列化类型>,HashSet<可Nino序列化类型>,Queue<可Nino序列化类型>,Stack<可Nino序列化类型>,可Nino序列化类型[], ICollection<可Nino序列化> - Dictionary,IDictionary<可Nino序列化> @@ -84,37 +87,11 @@ public partial struct NotIncludeAllClass -## ILRuntime - -Nino支持ILRuntime的使用,但需要初始化ILRuntime: - -1. 把ILRuntime导入Unity工程,并对ILRuntime目录生成assembly definition文件 - -2. 进入Nino_Unity/Assets/Nino/Serialization,找到```Nino.Serialization.asmdef```,选中后在Inspector上添加对ILRuntime的assembly definition的引用,并apply变动 - -3. 在PlayerSetting里Symbol区域添加```ILRuntime```(如果Symbol一栏不是空的,记得两个标签之间要用```;```隔开) - -4. 调用ILRuntime解析工具 - - ```csharp - Nino.Serialization.ILRuntimeResolver.RegisterILRuntimeClrRedirection(domain); - ``` +## 代码热更 - domain是ILRuntime的AppDomain,该方法应该在domain.LoadAssembly后,进入热更代码前调用,参考Test11 +- 暂时因为**ILRuntime**原理限制,Nino无法支持**ILRuntime** -5. 热更工程引用Library/ScriptAssemblies/Nino.Serialization.dll和Library/ScriptAssemblies/Nino.Shared.dll - -6. ILRuntime下**非常不建议**给热更工程的结构体生成静态性能优化代码,**因为原理限制会产生负优化!!!**,如果执意要生产代码,请参考后续步骤,反之可以忽略后面的步骤 - -7. 如果需要给热更工程生成代码,打开```Nino_Unity/Assets/Nino/Editor/SerializationHelper.cs```,修改```ExternalDLLPath```字段内的```Assets/Nino/Test/Editor/Serialization/Test11.bytes```,变为你的热更工程的DLL文件的路径,记得带后缀,修改生效后,在菜单栏点击```Nino/Generator/Serialization Code```即可给热更工程的Nino序列化类型生成代码 - -8. 生成热更工程的代码后,需要把生成的热更序列化类型的代码从Unity工程移到热更工程,并且在Unity工程删掉会报错的热更类型代码 - -> 如果用的是assembly definition来生成热更库的,需要把生成的热更代码放到assembly definition的目录内,把外部会报错的代码挪进去就好 -> -> 需要注意的是,ILRuntime下生成与不生成代码的差距不是特别大 -> -> ILRuntime下也不支持多态! +- Nino支持**HybridCLR** @@ -135,28 +112,71 @@ Nino支持ILRuntime的使用,但需要初始化ILRuntime: 示例: ```csharp -public class Vector3Wrapper : NinoWrapperBase +[NinoSerialize(false)] +public partial class CustomTypeTest +{ + [NinoMember(1)] public Vector3 v3; + + [NinoMember(2)] private DateTime dt = DateTime.Now; + + [NinoMember(3)] public int? ni { get; set; } + + [NinoMember(4)] public List qs; + + [NinoMember(5)] public Matrix4x4 m; + + [NinoMember(6)] public Dictionary dict; + + [NinoMember(7)] public Dictionary dict2; + + public override string ToString() + { + return + $"{v3}, {dt}, {ni}, {String.Join(",", qs)}, {m.ToString()}\n" + + $"dict.keys: {string.Join(",", dict.Keys)},\ndict.values:{string.Join(",", dict.Values)}\n" + + $"dict2.keys: {string.Join(",", dict2.Keys)},\ndict2.values:{string.Join(",", dict2.Values)}\n"; + } +} + +public class CustomTypeTestWrapper : NinoWrapperBase { - public override void Serialize(Vector3 val, ref Writer writer) + public override void Serialize(CustomTypeTest val, ref Writer writer) { - writer.Write(val.x); - writer.Write(val.y); - writer.Write(val.z); + writer.Write(ref val.v3, sizeof(float) * 3); + writer.Write(ref val.m, sizeof(float) * 16); + writer.Write(val.ni); + writer.Write(val.qs); + writer.Write(val.dict); + writer.Write(val.dict2); } - public override Vector3 Deserialize(Reader reader) + public override CustomTypeTest Deserialize(Reader reader) { - return new Vector3(reader.Read(4), reader.Read(4), reader.Read(4)); + var ret = new CustomTypeTest(); + reader.Read(ref ret.v3, sizeof(float) * 3); + reader.Read(ref ret.m, sizeof(float) * 16); + ret.ni = reader.ReadNullable(); + ret.qs = reader.ReadList(); + ret.dict = reader.ReadDictionary(); + ret.dict2 = reader.ReadDictionary(); + return ret; } - public override int GetSize(Vector3 val) + public override int GetSize(CustomTypeTest val) { - return 12; + int ret = 1; + ret += sizeof(float) * 3; + ret += sizeof(float) * 16; + ret += Serializer.GetSize(val.ni); + ret += Serializer.GetSize(val.qs); + ret += Serializer.GetSize(val.dict); + ret += Serializer.GetSize(val.dict2); + return ret; } } //别忘了在某个地方调用下面的代码: -WrapperManifest.AddWrapper(typeof(Vector3), new Vector3Wrapper()); +WrapperManifest.AddWrapper(typeof(CustomTypeTest), new CustomTypeTestWrapper()); ``` @@ -167,7 +187,7 @@ WrapperManifest.AddWrapper(typeof(Vector3), new Vector3Wrapper()); - Unity下直接在菜单栏点击```Nino/Generator/Serialization Code```即可,代码会生成到```Assets/Nino/Generated```,也可以打开```Assets/Nino/Editor/SerializationHelper.cs```并修改内部的```ExportPath```参数 - 非Unity下调用```CodeGenerator.GenerateSerializationCodeForAllTypePossible```接口即可 -- **开启了自动收集字段和属性,生成代码和没生成代码,序列化的结果是一样的** +- **开启了自动收集字段和属性,生成代码和没生成代码,序列化的结果是一样的,但是速度会快很多** > 不想生成代码的类或结构体可以打```[CodeGenIgnore]```标签到该类或结构体上,可以在性能对比的时候用这个(例如[这个真机测试](../Nino_Unity/Assets/Nino/Test/BuildTest.cs)) @@ -185,7 +205,7 @@ Nino支持以下三种压缩方式: > 序列化和反序列化的时候可以选择压缩方式,但是需要注意反序列化数据的时候,需要用和序列化时相同的压缩方式去反序列化 > -> 注意,v1.2.0暂时仅支持无压缩 +> 注意,v1.2.0~1.2.2暂时仅支持无压缩 diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs index de666c2..e7acec1 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_BuildTestDataCodeGen_Serialize.cs @@ -23,19 +23,8 @@ public override void Serialize(BuildTestDataCodeGen value, ref Nino.Serializatio return; } writer.Write(true); - writer.Write(ref value.a, sizeof(System.Byte)); - writer.Write(ref value.b, sizeof(System.SByte)); - writer.Write(ref value.c, sizeof(System.Int16)); - writer.Write(ref value.d, sizeof(System.UInt16)); - writer.Write(ref value.e, sizeof(System.Int32)); - writer.Write(ref value.f, sizeof(System.UInt32)); - writer.Write(ref value.g, sizeof(System.Int64)); - writer.Write(ref value.h, sizeof(System.UInt64)); - writer.Write(ref value.i, sizeof(System.Single)); - writer.Write(ref value.j, sizeof(System.Double)); - writer.Write(ref value.k, sizeof(System.Decimal)); - writer.Write(ref value.l, sizeof(System.Boolean)); - writer.Write(ref value.m, sizeof(System.Char)); + writer.Write(ref value.a, sizeof(System.Byte),ref value.b, sizeof(System.SByte),ref value.c, sizeof(System.Int16),ref value.d, sizeof(System.UInt16),ref value.e, sizeof(System.Int32),ref value.f, sizeof(System.UInt32),ref value.g, sizeof(System.Int64),ref value.h, sizeof(System.UInt64)); + writer.Write(ref value.i, sizeof(System.Single),ref value.j, sizeof(System.Double),ref value.k, sizeof(System.Decimal),ref value.l, sizeof(System.Boolean),ref value.m, sizeof(System.Char)); writer.Write(value.n); writer.Write(value.o); writer.Write(value.p); @@ -53,19 +42,8 @@ public override BuildTestDataCodeGen Deserialize(Nino.Serialization.Reader reade if(!reader.ReadBool()) return null; BuildTestDataCodeGen value = new BuildTestDataCodeGen(); - reader.Read(ref value.a, sizeof(System.Byte)); - reader.Read(ref value.b, sizeof(System.SByte)); - reader.Read(ref value.c, sizeof(System.Int16)); - reader.Read(ref value.d, sizeof(System.UInt16)); - reader.Read(ref value.e, sizeof(System.Int32)); - reader.Read(ref value.f, sizeof(System.UInt32)); - reader.Read(ref value.g, sizeof(System.Int64)); - reader.Read(ref value.h, sizeof(System.UInt64)); - reader.Read(ref value.i, sizeof(System.Single)); - reader.Read(ref value.j, sizeof(System.Double)); - reader.Read(ref value.k, sizeof(System.Decimal)); - reader.Read(ref value.l, sizeof(System.Boolean)); - reader.Read(ref value.m, sizeof(System.Char)); + reader.Read(ref value.a, sizeof(System.Byte),ref value.b, sizeof(System.SByte),ref value.c, sizeof(System.Int16),ref value.d, sizeof(System.UInt16),ref value.e, sizeof(System.Int32),ref value.f, sizeof(System.UInt32),ref value.g, sizeof(System.Int64),ref value.h, sizeof(System.UInt64)); + reader.Read(ref value.i, sizeof(System.Single),ref value.j, sizeof(System.Double),ref value.k, sizeof(System.Decimal),ref value.l, sizeof(System.Boolean),ref value.m, sizeof(System.Char)); value.n = reader.ReadString(); value.o = reader.ReadList(); value.p = reader.ReadList(); diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs index 9d42158..861a096 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_CustomTypeTest_Serialize.cs @@ -23,11 +23,10 @@ public override void Serialize(CustomTypeTest value, ref Nino.Serialization.Writ return; } writer.Write(true); - writer.WriteCommonVal(value.v3); - writer.Write(ref value.dt, sizeof(System.DateTime)); - writer.WriteCommonVal>(value.ni); + writer.Write(ref value.v3, sizeof(UnityEngine.Vector3),ref value.dt, sizeof(System.DateTime)); + writer.Write(value.ni); writer.Write(value.qs); - writer.WriteCommonVal(value.m); + writer.Write(ref value.m, sizeof(UnityEngine.Matrix4x4)); writer.Write(value.dict); writer.Write(value.dict2); } @@ -38,11 +37,10 @@ public override CustomTypeTest Deserialize(Nino.Serialization.Reader reader) if(!reader.ReadBool()) return null; CustomTypeTest value = new CustomTypeTest(); - value.v3 = reader.ReadCommonVal(); - reader.Read(ref value.dt, sizeof(System.DateTime)); - value.ni = reader.ReadCommonVal>(); + reader.Read(ref value.v3, sizeof(UnityEngine.Vector3),ref value.dt, sizeof(System.DateTime)); + value.ni = reader.ReadNullable(); value.qs = reader.ReadList(); - value.m = reader.ReadCommonVal(); + reader.Read(ref value.m, sizeof(UnityEngine.Matrix4x4)); value.dict = reader.ReadDictionary(); value.dict2 = reader.ReadDictionary(); return value; diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs index a896db9..082a81a 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_Data_Serialize.cs @@ -28,14 +28,7 @@ public override void Serialize(Data value, ref Nino.Serialization.Writer writer) { writer.Write(true); - writer.Write(ref value.x, sizeof(System.Int32)); - writer.Write(ref value.y, sizeof(System.Int16)); - writer.Write(ref value.z, sizeof(System.Int64)); - writer.Write(ref value.f, sizeof(System.Single)); - writer.Write(ref value.d, sizeof(System.Decimal)); - writer.Write(ref value.db, sizeof(System.Double)); - writer.Write(ref value.bo, sizeof(System.Boolean)); - writer.WriteEnum(value.en); + writer.Write(ref value.x, sizeof(System.Int32),ref value.y, sizeof(System.Int16),ref value.z, sizeof(System.Int64),ref value.f, sizeof(System.Single),ref value.d, sizeof(System.Decimal),ref value.db, sizeof(System.Double),ref value.bo, sizeof(System.Boolean),ref value.en, sizeof(Nino.Test.TestEnum)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -44,14 +37,7 @@ public override Data Deserialize(Nino.Serialization.Reader reader) if(!reader.ReadBool()) return default; Data value = new Data(); - reader.Read(ref value.x, sizeof(System.Int32)); - reader.Read(ref value.y, sizeof(System.Int16)); - reader.Read(ref value.z, sizeof(System.Int64)); - reader.Read(ref value.f, sizeof(System.Single)); - reader.Read(ref value.d, sizeof(System.Decimal)); - reader.Read(ref value.db, sizeof(System.Double)); - reader.Read(ref value.bo, sizeof(System.Boolean)); - reader.ReadEnum(ref value.en); + reader.Read(ref value.x, sizeof(System.Int32),ref value.y, sizeof(System.Int16),ref value.z, sizeof(System.Int64),ref value.f, sizeof(System.Single),ref value.d, sizeof(System.Decimal),ref value.db, sizeof(System.Double),ref value.bo, sizeof(System.Boolean),ref value.en, sizeof(Nino.Test.TestEnum)); return value; } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs index 82d6d3d..a35fa86 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_IncludeAllClassCodeGen_Serialize.cs @@ -28,10 +28,7 @@ public override void Serialize(IncludeAllClassCodeGen value, ref Nino.Serializat return; } writer.Write(true); - writer.Write(ref value.a, sizeof(System.Int32)); - writer.Write(ref value.b, sizeof(System.Int64)); - writer.Write(ref value.c, sizeof(System.Single)); - writer.Write(ref value.d, sizeof(System.Double)); + writer.Write(ref value.a, sizeof(System.Int32),ref value.b, sizeof(System.Int64),ref value.c, sizeof(System.Single),ref value.d, sizeof(System.Double)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -40,10 +37,7 @@ public override IncludeAllClassCodeGen Deserialize(Nino.Serialization.Reader rea if(!reader.ReadBool()) return null; IncludeAllClassCodeGen value = new IncludeAllClassCodeGen(); - reader.Read(ref value.a, sizeof(System.Int32)); - reader.Read(ref value.b, sizeof(System.Int64)); - reader.Read(ref value.c, sizeof(System.Single)); - reader.Read(ref value.d, sizeof(System.Double)); + reader.Read(ref value.a, sizeof(System.Int32),ref value.b, sizeof(System.Int64),ref value.c, sizeof(System.Single),ref value.d, sizeof(System.Double)); return value; } diff --git a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs index 3fde7a9..94dff11 100644 --- a/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs +++ b/Nino_Unity/Assets/Nino/Generated/Nino_Test_NotIncludeAllClass_Serialize.cs @@ -28,10 +28,7 @@ public override void Serialize(NotIncludeAllClass value, ref Nino.Serialization. return; } writer.Write(true); - writer.Write(ref value.a, sizeof(System.Int32)); - writer.Write(ref value.b, sizeof(System.Int64)); - writer.Write(ref value.c, sizeof(System.Single)); - writer.Write(ref value.d, sizeof(System.Double)); + writer.Write(ref value.a, sizeof(System.Int32),ref value.b, sizeof(System.Int64),ref value.c, sizeof(System.Single),ref value.d, sizeof(System.Double)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -40,10 +37,7 @@ public override NotIncludeAllClass Deserialize(Nino.Serialization.Reader reader) if(!reader.ReadBool()) return null; NotIncludeAllClass value = new NotIncludeAllClass(); - reader.Read(ref value.a, sizeof(System.Int32)); - reader.Read(ref value.b, sizeof(System.Int64)); - reader.Read(ref value.c, sizeof(System.Single)); - reader.Read(ref value.d, sizeof(System.Double)); + reader.Read(ref value.a, sizeof(System.Int32),ref value.b, sizeof(System.Int64),ref value.c, sizeof(System.Single),ref value.d, sizeof(System.Double)); return value; } diff --git a/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs b/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs index 1c83bdf..d3ef3e7 100644 --- a/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs +++ b/Nino_Unity/Assets/Nino/Serialization/CodeGenerator.cs @@ -1,12 +1,11 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Nino.Shared.Mgr; using Nino.Shared.Util; using System.Reflection; -using System.Collections.Generic; -using System.Runtime.CompilerServices; namespace Nino.Serialization { @@ -194,15 +193,60 @@ public override int GetSize({type} value) model = TypeModel.CreateModel(type); } - HashSet members = model.Members; + var members = model.Members; #region serialize //build params StringBuilder sb = new StringBuilder(); - foreach (var member in members) + List unmanagedMembers = new List(); + for (int i = 0; i < members.Count; i++) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var info = members[i]; + var member = info.Member; + var mt = info.Type; + + //try optimize + if (TypeModel.IsUnmanaged(mt) && member is FieldInfo) + { + unmanagedMembers.Clear(); + unmanagedMembers.Add(info); + for (int j = i + 1; j < members.Count; j++) + { + var info2 = members[j]; + var member2 = info2.Member; + var mt2 = info2.Type; + if (TypeModel.IsUnmanaged(mt2) && member2 is FieldInfo) + { + unmanagedMembers.Add(info2); + } + else + { + break; + } + } + + i += unmanagedMembers.Count - 1; + //batch write with batch size 8 + while (unmanagedMembers.Count > 0) + { + if (unmanagedMembers.Count <= 8) + { + sb.Append( + $" writer.Write({string.Join(",", unmanagedMembers.Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.Clear(); + } + else + { + sb.Append( + $" writer.Write({string.Join(",", unmanagedMembers.Take(8).Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.RemoveRange(0, 8); + } + } + + continue; + } + //enum if (mt.IsEnum) { @@ -219,6 +263,11 @@ public override int GetSize({type} value) { sb.Append($" writer.Write(value.{member.Name});\n"); } + //nullable + else if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + sb.Append($" writer.Write(value.{member.Name});\n"); + } //basic type else { @@ -241,9 +290,53 @@ public override int GetSize({type} value) #region deserialize sb.Clear(); - foreach (var member in members) + for (int i = 0; i < members.Count; i++) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var info = members[i]; + var member = info.Member; + var mt = info.Type; + + //try optimize + if (TypeModel.IsUnmanaged(mt) && member is FieldInfo) + { + unmanagedMembers.Clear(); + unmanagedMembers.Add(info); + for (int j = i + 1; j < members.Count; j++) + { + var info2 = members[j]; + var member2 = info2.Member; + var mt2 = info2.Type; + if (TypeModel.IsUnmanaged(mt2) && member2 is FieldInfo) + { + unmanagedMembers.Add(info2); + } + else + { + break; + } + } + + i += unmanagedMembers.Count - 1; + //batch write with batch size 8 + while (unmanagedMembers.Count > 0) + { + if (unmanagedMembers.Count <= 8) + { + sb.Append( + $" reader.Read({string.Join(",", unmanagedMembers.Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.Clear(); + } + else + { + sb.Append( + $" reader.Read({string.Join(",", unmanagedMembers.Take(8).Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.RemoveRange(0, 8); + } + } + + continue; + } + //enum if (mt.IsEnum) { @@ -292,6 +385,15 @@ public override int GetSize({type} value) sb.Append( $" value.{member.Name} = reader.ReadDictionary<{BeautifulLongTypeName(keyType)},{BeautifulLongTypeName(valueType)}>();\n"); } + //nullable + else if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + var args = mt.GetGenericArguments(); + Type keyType = args[0]; + + sb.Append( + $" value.{member.Name} = reader.ReadNullable<{BeautifulLongTypeName(keyType)}>();\n"); + } //not enum -> basic type else { @@ -315,16 +417,19 @@ public override int GetSize({type} value) sb.Clear(); if (TypeModel.IsFixedSizeType(type)) { - sb.Append($" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); + sb.Append( + $" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); } else { sb.Append(" int ret = 1;\n"); - foreach (var member in members) + foreach (var info in members) { + var member = info.Member; sb.Append( $" ret += Nino.Serialization.Serializer.GetSize(value.{member.Name});\n"); } + sb.Append(" return ret;"); } @@ -339,13 +444,15 @@ public override int GetSize({type} value) if (TypeModel.IsFixedSizeType(type)) { sb.Append(" int ret = 1;\n"); - foreach (var member in members) + foreach (var info in members) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var mt = info.Type; sb.Append( $" ret += sizeof({BeautifulLongTypeName(mt)});\n"); } - sb.Append($" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); + + sb.Append( + $" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); } //replace template fields @@ -517,6 +624,14 @@ private static string GetSerializeBasicTypeStatement(Type mt, string val, bool i return builder.ToString(); } + if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + StringBuilder builder = new StringBuilder(); + builder.Append(space).Append(Repeat(" ", indent)) + .Append($"writer.Write({val});\n"); + return builder.ToString(); + } + return $"writer.WriteCommonVal<{BeautifulLongTypeName(mt)}>({val})"; } } diff --git a/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs b/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs index 8273981..9c8fa41 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Deserializer.cs @@ -92,12 +92,24 @@ internal static T Deserialize(Span data, Reader reader, return ret; } + //enum + if (TryDeserializeEnum(type, reader, returnDispose, out var e)) + { + return e; + } + //code generated type if (TryDeserializeCodeGenType(type, reader, false, returnDispose, out ret)) { return ret; } + //unmanaged type + if (TryDeserializeUnmanagedType(type, reader, returnDispose, out var un)) + { + return un; + } + /* * GC DESERIALIZATION WHILE T IS STRUCT */ @@ -148,10 +160,6 @@ internal static object Deserialize(Type type, object val, Span data, Reade } } -#if ILRuntime - type = type.ResolveRealType(); -#endif - //basic type if (TryDeserializeWrapperType(type, reader, true, returnDispose, out object basicObj)) { @@ -163,13 +171,19 @@ internal static object Deserialize(Type type, object val, Span data, Reade { return e; } - + //code generated type if (TryDeserializeCodeGenType(type, reader, true, returnDispose, out object codeGenRet)) { return codeGenRet; } + //unmanaged type + if (TryDeserializeUnmanagedType(type, reader, returnDispose, out var un)) + { + return un; + } + /* * CUSTOM STRUCT/CLASS SERIALIZATION */ @@ -181,11 +195,7 @@ internal static object Deserialize(Type type, object val, Span data, Reade //create type if (val == null || val == ConstMgr.Null) { -#if ILRuntime - val = ILRuntimeResolver.CreateInstance(type); -#else val = Activator.CreateInstance(type); -#endif } //Get Attribute that indicates a class/struct to be serialized @@ -204,7 +214,7 @@ internal static object Deserialize(Type type, object val, Span data, Reade } //start Deserialize - foreach (var member in model.Members) + foreach (var info in model.Members) { //if end, skip if (reader.EndOfReader) @@ -212,10 +222,10 @@ internal static object Deserialize(Type type, object val, Span data, Reade break; } - type = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + type = info.Type; //read basic values - SetMember(member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); + SetMember(info.Member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); } if (returnDispose) @@ -384,6 +394,33 @@ private static bool TryDeserializeDict(Type type, Type genericDefType, Reader re return false; } + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeEnum(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out T obj) + { + obj = default; + if (TypeModel.IsEnum(type)) + { + reader.ReadEnum(ref obj); + if (returnDispose) + { + ObjectPool.Return(reader); + } + + return true; + } + + return false; + } + /// /// Try deserialize enum /// @@ -400,16 +437,6 @@ private static bool TryDeserializeEnum(Type type, Reader reader, { var underlyingType = Enum.GetUnderlyingType(type); var ret = reader.ReadEnum(underlyingType); -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeType) - { - if (underlyingType == ConstMgr.LongType - || underlyingType == ConstMgr.UIntType - || underlyingType == ConstMgr.ULongType) - obj = unchecked((long)ret); - obj = unchecked((int)ret); - } -#endif obj = Enum.ToObject(type, ret); if (returnDispose) { @@ -423,6 +450,58 @@ private static bool TryDeserializeEnum(Type type, Reader reader, return false; } + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeUnmanagedType(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out T obj) + { + obj = default; + if (TypeModel.IsUnmanaged(type)) + { + reader.ReadAsUnmanaged(ref obj, Marshal.SizeOf(type)); + if (returnDispose) + { + ObjectPool.Return(reader); + } + return true; + } + + return false; + } + + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeUnmanagedType(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out object obj) + { + obj = default; + if (TypeModel.IsUnmanaged(type)) + { + reader.ReadAsUnmanaged(ref obj, Marshal.SizeOf(type)); + if (returnDispose) + { + ObjectPool.Return(reader); + } + return true; + } + + return false; + } + /// /// Check for null /// diff --git a/Nino_Unity/Assets/Nino/Serialization/ILRuntimeResolver.cs b/Nino_Unity/Assets/Nino/Serialization/ILRuntimeResolver.cs deleted file mode 100644 index e3c564e..0000000 --- a/Nino_Unity/Assets/Nino/Serialization/ILRuntimeResolver.cs +++ /dev/null @@ -1,365 +0,0 @@ -using System; -using System.Text; -using System.Linq; -using Nino.Shared.Mgr; -using System.Reflection; -using System.Collections.Generic; -#if ILRuntime -#if DEBUG && !DISABLE_ILRUNTIME_DEBUG -using AutoList = System.Collections.Generic.List; -#else -using AutoList = ILRuntime.Other.UncheckedList; -#endif -#endif - -// ReSharper disable CognitiveComplexity -// ReSharper disable RedundantNameQualifier -// ReSharper disable RedundantExplicitArrayCreation - -namespace Nino.Serialization -{ -#if ILRuntime - /// - /// ILRuntime helper - /// - public static class ILRuntimeResolver - { - internal static ILRuntime.Runtime.Enviorment.AppDomain appDomain; - - private static readonly Dictionary IlRuntimeTypes = new Dictionary(); - - /// - /// Get ILType - /// - /// - /// - public static Type FindType(string metaName) - { - IlRuntimeTypes.TryGetValue(metaName, out Type type); - return type; - } - - /// - /// Create ILTypeInstance - /// - /// - /// - public static object CreateInstance(Type type) - { - if (appDomain != null) - { - string typeName = type.FullName; - if (FindType(typeName) != null) - { - return appDomain.Instantiate(typeName); - } - - if (typeName != null && appDomain.LoadedTypes.ContainsKey(typeName)) - { - IlRuntimeTypes[typeName] = type; - return appDomain.Instantiate(typeName); - } - } - - return Activator.CreateInstance(type); - } - - /// - /// Reg ILRuntime - /// - /// - public static unsafe void RegisterILRuntimeClrRedirection(ILRuntime.Runtime.Enviorment.AppDomain domain) - { - appDomain = domain; - //cache types - IlRuntimeTypes.Clear(); - var allTypes = domain.LoadedTypes.Values.Select(x => x.ReflectionType).ToArray(); - foreach (var t in allTypes) - { - if (t.FullName != null) - { - IlRuntimeTypes[t.FullName] = t; - TypeModel.AllTypes[t.GetHashCode()] = t; - } - } - - try - { - appDomain.RegisterCrossBindingAdaptor(new SerializationHelper1ILTypeInstanceAdapter()); - } - catch - { - //ignore - } - - //reg redirections - MethodBase method; - var type = typeof(Nino.Serialization.Serializer); - var genericMethods = new Dictionary>(); - List lst; - foreach (var m in type.GetMethods()) - { - if (m.IsGenericMethodDefinition) - { - if (!genericMethods.TryGetValue(m.Name, out lst)) - { - lst = new List(); - genericMethods[m.Name] = lst; - } - - lst.Add(m); - } - } - - var args = new Type[] { typeof(ILRuntime.Runtime.Intepreter.ILTypeInstance) }; - var ps = new Type[] { args[0], typeof(Nino.Serialization.CompressOption) }; - if (genericMethods.TryGetValue("Serialize", out lst)) - { - foreach (var m in lst) - { - if (ILRuntime.Runtime.Extensions.MatchGenericParameters(m, args, typeof(System.Byte[]), - ps)) - { - method = m.MakeGenericMethod(args); - appDomain.RegisterCLRMethodRedirection(method, Serialize_0); - - break; - } - } - } - - type = typeof(Nino.Serialization.Deserializer); - genericMethods.Clear(); - lst?.Clear(); - foreach (var m in type.GetMethods()) - { - if (m.IsGenericMethodDefinition) - { - if (!genericMethods.TryGetValue(m.Name, out lst)) - { - lst = new List(); - genericMethods[m.Name] = lst; - } - - lst.Add(m); - } - } - - //Deserialize - if (genericMethods.TryGetValue("Deserialize", out lst)) - { - foreach (var m in lst) - { - appDomain.RegisterCLRMethodRedirection(m, Deserialize_0); - } - } - } - - /// - /// Deserialize reg - /// - /// - /// - /// - /// - /// - /// - private static unsafe ILRuntime.Runtime.Stack.StackObject* Deserialize_0( - ILRuntime.Runtime.Intepreter.ILIntepreter intp, ILRuntime.Runtime.Stack.StackObject* esp, - AutoList mStack, - ILRuntime.CLR.Method.CLRMethod method, bool isNewObj) - { - var domain = intp.AppDomain; - var ret = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - - var ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 1); - var @option = (Nino.Serialization.CompressOption)ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - typeof(Nino.Serialization.CompressOption), - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - (ILRuntime.CLR.Utils.Extensions.TypeFlags)20); - intp.Free(ptrOfThisMethod); - - ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - var @data = ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack); - intp.Free(ptrOfThisMethod); - - //获取泛型参数的实际类型 - var genericArguments = method.GenericArguments; - var t = genericArguments[0]; - - object resultOfThisMethod = null; - if (@data is byte[] buf) - { - resultOfThisMethod = - Nino.Serialization.Deserializer.Deserialize(t.ReflectionType, buf, option); - } - else if (@data is ArraySegment seg) - { - resultOfThisMethod = - Nino.Serialization.Deserializer.Deserialize(t.ReflectionType, seg, option); - } - - return ILRuntime.Runtime.Intepreter.ILIntepreter.PushObject(ret, mStack, resultOfThisMethod); - } - - /// - /// Serialize reg - /// - /// - /// - /// - /// - /// - /// - private static unsafe ILRuntime.Runtime.Stack.StackObject* Serialize_0( - ILRuntime.Runtime.Intepreter.ILIntepreter intp, ILRuntime.Runtime.Stack.StackObject* esp, - AutoList mStack, - ILRuntime.CLR.Method.CLRMethod method, bool isNewObj) - { - var domain = intp.AppDomain; - var ret = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - - var ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 1); - var @option = (Nino.Serialization.CompressOption)ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - typeof(Nino.Serialization.CompressOption), - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - (ILRuntime.CLR.Utils.Extensions.TypeFlags)20); - intp.Free(ptrOfThisMethod); - - //获取泛型参数的实际类型 - var genericArguments = method.GenericArguments; - var t = genericArguments[0]; - ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - var val = ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - t.ReflectionType, - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - 0); - intp.Free(ptrOfThisMethod); - - var resultOfThisMethod = - Nino.Serialization.Serializer.Serialize(val, option); - - return ILRuntime.Runtime.Intepreter.ILIntepreter.PushObject(ret, mStack, resultOfThisMethod); - } - - /// - /// Resolve real type - /// - /// - /// - public static Type ResolveRealType(this Type type) - { - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - return wt.RealType; - } - - return type; - } - } - - public class SerializationHelper1ILTypeInstanceAdapter : ILRuntime.Runtime.Enviorment.CrossBindingAdaptor - { - public override Type BaseCLRType - { - get { return typeof(Nino.Serialization.NinoWrapperBase); } - } - - public override Type AdaptorType - { - get { return typeof(Adapter); } - } - - public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, - ILRuntime.Runtime.Intepreter.ILTypeInstance instance) - { - return new Adapter(appdomain, instance); - } - - public class Adapter : Nino.Serialization.NinoWrapperBase, - ILRuntime.Runtime.Enviorment.CrossBindingAdaptorType - { - bool isInvokingToString; - ILRuntime.Runtime.Intepreter.ILTypeInstance instance; - ILRuntime.Runtime.Enviorment.AppDomain appdomain; - - private ILRuntime.CLR.Method.IMethod write; - private ILRuntime.CLR.Method.IMethod read; - - public Adapter() - { - - } - - public Adapter(ILRuntime.Runtime.Enviorment.AppDomain appdomain, - ILRuntime.Runtime.Intepreter.ILTypeInstance instance) - { - this.appdomain = appdomain; - this.instance = instance; - } - - public ILRuntime.Runtime.Intepreter.ILTypeInstance ILInstance - { - get { return instance; } - } - - public override void Serialize(ILRuntime.Runtime.Intepreter.ILTypeInstance val, - Nino.Serialization.Writer writer) - { - if (write == null) - { - string Name = nameof(Serialize); - var ilType = instance.Type; - write = ilType.GetMethod(Name, 2); - } - - using (var ctx = appdomain.BeginInvoke(write)) - { - ctx.PushObject(instance); - ctx.PushObject(val); - ctx.PushObject(writer); - ctx.Invoke(); - } - } - - public override ILRuntime.Runtime.Intepreter.ILTypeInstance Deserialize(Nino.Serialization.Reader reader) - { - if (read == null) - { - string Name = nameof(Deserialize); - var ilType = instance.Type; - read = ilType.GetMethod(Name, 1); - } - - using (var ctx = appdomain.BeginInvoke(read)) - { - ctx.PushObject(instance); - ctx.PushObject(reader); - ctx.Invoke(); - return ctx.ReadObject(); - } - } - - public override string ToString() - { - ILRuntime.CLR.Method.IMethod m = appdomain.ObjectType.GetMethod("ToString", 0); - m = instance.Type.GetVirtualMethod(m); - if (m == null || m is ILRuntime.CLR.Method.ILMethod) - { - if (!isInvokingToString) - { - isInvokingToString = true; - string res = instance.ToString(); - isInvokingToString = false; - return res; - } - else - return instance.Type.FullName; - } - else - return instance.Type.FullName; - } - } - } -#endif -} \ No newline at end of file diff --git a/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs index fa1a1fc..03f8fac 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Reader.Generic.cs @@ -84,6 +84,27 @@ public T Read(int len) where T : unmanaged return ret; } + /// + /// Read unmanaged type + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable UnusedMember.Local + internal void ReadAsUnmanaged(ref T val, int len) + // ReSharper restore UnusedMember.Local + { + if (EndOfReader) + { + return; + } + + Span span = buffer.AsSpan(position, len); + var first = span[0]; + val = Unsafe.ReadUnaligned(ref first); + position += len; + } + /// /// Read unmanaged type /// @@ -103,6 +124,197 @@ public void Read(ref T val, int len) where T : unmanaged position += len; } + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2) where T1 : unmanaged where T2 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3) + where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4) where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged where T4 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7) + where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + val7 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T7))); + position += len7; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7, + ref T8 val8, int len8) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + where T8 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + val7 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T7))); + position += len7; + val8 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T8))); + position += len8; + } + /// /// Read nullable /// diff --git a/Nino_Unity/Assets/Nino/Serialization/Reader.cs b/Nino_Unity/Assets/Nino/Serialization/Reader.cs index 5109e8b..a22f87f 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Reader.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Reader.cs @@ -360,12 +360,7 @@ public Array ReadArray(Type type) while (i < len) { var obj = ReadCommonVal(elemType); -#if ILRuntime - arr.SetValue(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj), i++); - continue; -#else arr.SetValue(obj, i++); -#endif } return arr; @@ -392,17 +387,6 @@ public IList ReadList(Type type) //check null if (!ReadBool()) return null; var elemType = type.GenericTypeArguments[0]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - elemType = wt?.CLRType.GenericArguments[0].Value.ReflectionType; - } - - if(!elemType.IsGenericType) - { - elemType = elemType.ResolveRealType(); - } -#endif //read len int len = ReadLength(); @@ -413,12 +397,7 @@ public IList ReadList(Type type) while (i++ < len) { var obj = ReadCommonVal(elemType); -#if ILRuntime - arr?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj)); - continue; -#else arr?.Add(obj); -#endif } return arr; @@ -438,29 +417,7 @@ public IDictionary ReadDictionary(Type type) //parse dict type var args = type.GetGenericArguments(); Type keyType = args[0]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - keyType = wt?.CLRType.GenericArguments[0].Value.ReflectionType; - } - - if(!keyType.IsGenericType) - { - keyType = keyType.ResolveRealType(); - } -#endif Type valueType = args[1]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt2) - { - valueType = wt2?.CLRType.GenericArguments[1].Value.ReflectionType; - } - - if(!valueType.IsGenericType) - { - valueType = valueType.ResolveRealType(); - } -#endif var dict = Activator.CreateInstance(type) as IDictionary; @@ -477,13 +434,7 @@ public IDictionary ReadDictionary(Type type) var val = ReadCommonVal(valueType); //add -#if ILRuntime - dict?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(keyType, key), - ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(valueType, val)); - continue; -#else dict?.Add(key, val); -#endif } return dict; diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs index 7c60631..65dad70 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.Generic.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nino.Serialization { @@ -57,6 +58,27 @@ private static bool TrySerializeEnumType(Type type, ref T value, ref Writer w return true; } + /// + /// Attempt to serialize unmanaged type + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeUnmanagedType(Type type, ref T value, ref Writer writer) + { + //enum + if (!TypeModel.IsUnmanaged(type)) + { + return false; + } + + writer.WriteAsUnmanaged(ref value, Marshal.SizeOf()); + return true; + } + /// /// Attempt to serialize code gen type (first time only) /// diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs index 3f64695..ef9f858 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.Helper.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Nino.Shared.Mgr; namespace Nino.Serialization @@ -48,7 +49,7 @@ public static int GetFixedSize() return -1; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void SetFixedSize(int size) { @@ -60,7 +61,7 @@ public static int GetSize(in T[] val = default, Dictionary(in T[] val = default, Dictionary() * length + 1 + 4; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + 4 + length * size; @@ -82,7 +88,7 @@ public static int GetSize(in List val = default, Dictionary(in List val = default, Dictionary() * length + 1 + 4; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + 4 + length * size; } - + return GetSize(typeof(List), val, members); } @@ -113,6 +124,11 @@ public static int GetSize(in T? val = default, Dictionary } } + if (TypeModel.IsUnmanaged(type)) + { + return Unsafe.SizeOf() + 1; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + size; @@ -126,7 +142,7 @@ public static int GetSize(in T val = default, Dictionary var type = typeof(T); int size = 0; if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); - + //nullable if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { @@ -140,7 +156,7 @@ public static int GetSize(in T val = default, Dictionary { return size + size2; } - + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) { //code generated type @@ -161,13 +177,18 @@ public static int GetSize(in T val = default, Dictionary return size + wrapper.GetSize(val); } + if (TypeModel.IsUnmanaged(type)) + { + return Unsafe.SizeOf(); + } + return GetSize(type, val, members); } public static int GetSize(Type type, object obj, Dictionary members = null) { if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); - + int size = 0; bool isGeneric = type.IsGenericType; Type genericTypeDef = null; @@ -207,8 +228,13 @@ public static int GetSize(Type type, object obj, Dictionary return size + wrapper.GetSize(obj); } + if (TypeModel.IsUnmanaged(type)) + { + return Marshal.SizeOf(type); + } + size = 1; //null indicator - + if (type == ConstMgr.ObjectType) { type = obj.GetType(); @@ -377,31 +403,16 @@ public static int GetSize(Type type, object obj, Dictionary } var isFixed = true; - foreach (var member in model.Members) + foreach (var info in model.Members) { - Type memberType; - object memberObj; - switch (member) - { - case FieldInfo fi: - memberType = fi.FieldType; - memberObj = fi.GetValue(obj); - break; - case PropertyInfo pi: - memberType = pi.PropertyType; - memberObj = pi.GetValue(obj); - break; - default: - throw new Exception("Invalid member type"); - } - + object memberObj = info.GetValue(obj); if (members != null) { - members[member] = memberObj; + members[info.Member] = memberObj; } - size += GetSize(memberType, memberObj); - if (!FixedSizeCache.ContainsKey(memberType)) + size += GetSize(info.Type, memberObj); + if (!FixedSizeCache.ContainsKey(info.Type)) { isFixed = false; } diff --git a/Nino_Unity/Assets/Nino/Serialization/Serializer.cs b/Nino_Unity/Assets/Nino/Serialization/Serializer.cs index 8b6b4a2..5b2f0b7 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Serializer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Serializer.cs @@ -26,7 +26,13 @@ public static byte[] Serialize(in T val) } byte[] ret = new byte[length]; - Serialize(ret.AsSpan(), in val, fields); + if (val == null) + { + ObjectPool>.Return(fields); + return ret; + } + + Serialize(typeof(T), val, fields, ret.AsSpan(), 0); ObjectPool>.Return(fields); return ret; } @@ -73,6 +79,7 @@ public static byte[] Serialize(object val) ObjectPool>.Return(fields); return ret; } + Serialize(val.GetType(), val, fields, ret.AsSpan(), 0); ObjectPool>.Return(fields); return ret; @@ -96,18 +103,9 @@ public static int Serialize(Span buffer, object val) return Serialize(val.GetType(), val, null, buffer, 0); } - internal static int Serialize(Type type, T value, Dictionary fields ,Span buffer, int pos) + internal static int Serialize(Type type, T value, Dictionary fields, Span buffer, + int pos) { - //ILRuntime -#if ILRuntime - if(value is ILRuntime.Runtime.Intepreter.ILTypeInstance ins) - { - type = ins.Type.ReflectionType; - } - - type = type.ResolveRealType(); -#endif - Writer writer = new Writer(buffer, pos); //null check @@ -136,6 +134,11 @@ internal static int Serialize(Type type, T value, Dictionary(Type type, T value, Dictionary Members; + + public struct NinoMember + { + public MemberInfo Member; + public Type Type; + public Func GetValue; + + public NinoMember(MemberInfo member, Type type, Func getValue) + { + Member = member; + Type = type; + GetValue = getValue; + } + } - public HashSet Members; public bool Valid; public bool IncludeAll; @@ -95,12 +111,6 @@ internal class TypeModel /// internal static TypeCode GetTypeCode(Type type) { -#if ILRuntime - if (IsEnum(type) && type is ILRuntime.Reflection.ILRuntimeType) - { - type = Enum.GetUnderlyingType(type); - } -#endif var hash = type.GetTypeHashCode(); if (TypeCodes.TryGetValue(hash, out var ret)) { @@ -155,10 +165,9 @@ public static bool IsFixedSizeType(Type type) } // otherwise check recursively - foreach (var member in model.Members) + foreach (var info in model.Members) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; - if (!IsFixedSizeType(mt)) + if (!IsFixedSizeType(info.Type)) { ret = false; break; @@ -187,7 +196,8 @@ public static bool IsUnmanaged(Type type) .GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach (var field in fields) { - if (!IsUnmanaged(field.FieldType)) + if (field.GetCustomAttributes(CompilerGeneratedType, true).Length > 0 || + !IsUnmanaged(field.FieldType)) { ret = false; break; @@ -278,7 +288,7 @@ internal static TypeModel CreateModel(Type type) { Valid = true, //fetch members - Members = new HashSet(), + Members = new List(), }; //include all or not @@ -296,6 +306,11 @@ internal static TypeModel CreateModel(Type type) //iterate fields foreach (var f in fs) { + if (f.GetCustomAttributes(CompilerGeneratedType, true).Length > 0) + { + continue; + } + if (model.IncludeAll) { //skip nino ignore @@ -354,7 +369,14 @@ internal static TypeModel CreateModel(Type type) //add members to model foreach (var pair in dict) { - model.Members.Add(pair.Value); + if (pair.Value is FieldInfo fi) + { + model.Members.Add(new NinoMember(fi, fi.FieldType, fi.GetValue)); + } + else if (pair.Value is PropertyInfo pi) + { + model.Members.Add(new NinoMember(pi, pi.PropertyType, pi.GetValue)); + } } //release dict diff --git a/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs b/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs index 047f17b..5adbdcd 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Writer.Generic.cs @@ -27,6 +27,18 @@ public ref partial struct Writer public void WriteCommonVal(Type type, T val) => Position = Serializer.Serialize(type, val, null, buffer, Position); + /// + /// Write unmanaged type + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteAsUnmanaged(ref T val, int len) + { + Unsafe.WriteUnaligned(ref buffer[Position], val); + Position += len; + } + /// /// Write unmanaged type /// @@ -39,6 +51,163 @@ public void Write(ref T val, int len) where T : unmanaged Position += len; } + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2) + where T1 : unmanaged where T2 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3) + where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4) where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged where T4 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7) + where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + Unsafe.WriteUnaligned(ref buffer[Position], val7); + Position += len7; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7, + ref T8 val8, int len8) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + where T8 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + Unsafe.WriteUnaligned(ref buffer[Position], val7); + Position += len7; + Unsafe.WriteUnaligned(ref buffer[Position], val8); + Position += len8; + } + /// /// Write byte[] /// @@ -171,13 +340,7 @@ public void Write(T[] arr) while (i < len) { var obj = arr[i++]; -#if ILRuntime - var eType = obj is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : obj.GetType(); -#else var eType = obj.GetType(); -#endif WriteCommonVal(eType, obj); } } @@ -228,14 +391,7 @@ public void Write(List lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -268,14 +424,7 @@ public void Write(HashSet lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -308,14 +457,7 @@ public void Write(Queue lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -348,14 +490,7 @@ public void Write(Stack lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -392,24 +527,10 @@ public void Write(Dictionary dictionary) foreach (var c in keys) { //write key -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif //write val var val = dictionary[c]; -#if ILRuntime - eType = val is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns2 - ? ilIns2.Type.ReflectionType - : val.GetType(); - WriteCommonVal(eType, val); -#else WriteCommonVal(val); -#endif } } } diff --git a/Nino_Unity/Assets/Nino/Serialization/Writer.cs b/Nino_Unity/Assets/Nino/Serialization/Writer.cs index 20c3b68..3325915 100644 --- a/Nino_Unity/Assets/Nino/Serialization/Writer.cs +++ b/Nino_Unity/Assets/Nino/Serialization/Writer.cs @@ -259,13 +259,7 @@ public void Write(Array arr) while (i < len) { var obj = arr.GetValue(i++); -#if ILRuntime - var eType = obj is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : obj.GetType(); -#else var eType = obj.GetType(); -#endif WriteCommonVal(eType, obj); } } @@ -297,13 +291,7 @@ public void Write(IList arr) //write item foreach (var c in arr) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); -#else var eType = c.GetType(); -#endif WriteCommonVal(eType, c); } } @@ -338,23 +326,11 @@ public void Write(IDictionary dictionary) foreach (var c in keys) { //write key -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); -#else var eType = c.GetType(); -#endif WriteCommonVal(eType, c); //write val var val = dictionary[c]; -#if ILRuntime - eType = val is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns2 - ? ilIns2.Type.ReflectionType - : val.GetType(); -#else eType = val.GetType(); -#endif WriteCommonVal(eType, val); } } diff --git a/Nino_Unity/Assets/Nino/Test/BuildTest.cs b/Nino_Unity/Assets/Nino/Test/BuildTest.cs index d09ca22..ed13cd1 100644 --- a/Nino_Unity/Assets/Nino/Test/BuildTest.cs +++ b/Nino_Unity/Assets/Nino/Test/BuildTest.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.IO; using System.Linq; using UnityEngine; @@ -217,16 +218,24 @@ private void Start() //serialize else { + if(ninoBuffer.Length == 0) + { + ninoBuffer = new byte[Nino.Serialization.Serializer.GetSize(d2)]; + } sw.Reset(); sw.Start(); - ninoBuffer = Nino.Serialization.Serializer.Serialize(d2); + Span arr = stackalloc byte[Nino.Serialization.Serializer.GetSize(d2)]; + Nino.Serialization.Serializer.Serialize(arr, d2); sw.Stop(); + arr.CopyTo(ninoBuffer); var m1 = sw.ElapsedTicks; sw.Reset(); sw.Start(); //as everything are same, buffer has same length - ninoBuffer = Nino.Serialization.Serializer.Serialize(d1); + arr = stackalloc byte[Nino.Serialization.Serializer.GetSize(d1)]; + Nino.Serialization.Serializer.Serialize(arr, d1); sw.Stop(); + arr.CopyTo(ninoBuffer); var m2 = sw.ElapsedTicks; ninoResultText.text = $"Serialized BuildTestDataCodeGen as {ninoBuffer.Length} bytes in {((float)m1 / Stopwatch.Frequency) * 1000} ms,\n" + @@ -501,7 +510,8 @@ private void Start() { sw.Reset(); sw.Start(); - msgPackBuffer = MessagePackSerializer.Serialize(d2); + var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.None); + msgPackBuffer = MessagePackSerializer.Serialize(d2, lz4Options); sw.Stop(); var m1 = sw.ElapsedTicks; diff --git a/Nino_Unity/Assets/Nino/Test/BuildTest2.cs b/Nino_Unity/Assets/Nino/Test/BuildTest2.cs index 962d954..099e8fa 100644 --- a/Nino_Unity/Assets/Nino/Test/BuildTest2.cs +++ b/Nino_Unity/Assets/Nino/Test/BuildTest2.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.IO; using System.Linq; using UnityEngine; @@ -122,10 +123,17 @@ private void Start() //serialize else { + if(ninoBuffer.Length == 0) + { + ninoBuffer = new byte[Nino.Serialization.Serializer.GetSize(nd)]; + } sw.Reset(); sw.Start(); - ninoBuffer = Nino.Serialization.Serializer.Serialize(nd); + var arr = ArrayPool.Shared.Rent(Nino.Serialization.Serializer.GetSize(nd)); + Nino.Serialization.Serializer.Serialize(arr, nd); sw.Stop(); + Array.Copy(arr, ninoBuffer, ninoBuffer.Length); + ArrayPool.Shared.Return(arr); var m1 = sw.ElapsedTicks; ninoResultText.text = $"Serialized NestedData as {ninoBuffer.Length} bytes in {((float)m1 / Stopwatch.Frequency) * 1000} ms,\n{string.Join(",", ninoBuffer.Take(200))}"; @@ -311,7 +319,9 @@ private void Start() { sw.Reset(); sw.Start(); - msgPackBuffer = MessagePackSerializer.Serialize(nd); + + var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.None); + msgPackBuffer = MessagePackSerializer.Serialize(nd, lz4Options); sw.Stop(); var m1 = sw.ElapsedTicks; diff --git a/Nino_Unity/Assets/Nino/Test/Data.cs b/Nino_Unity/Assets/Nino/Test/Data.cs index 93649d8..706c9da 100644 --- a/Nino_Unity/Assets/Nino/Test/Data.cs +++ b/Nino_Unity/Assets/Nino/Test/Data.cs @@ -144,7 +144,7 @@ public override string ToString() } } - [NinoSerialize] + [NinoSerialize(false)] public partial class CustomTypeTest { [NinoMember(1)] public Vector3 v3; diff --git a/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.bytes b/Nino_Unity/Assets/Nino/Test/Editor/Serialization/Test11.bytes deleted file mode 100644 index 2b498cddb3e3db9e4646a3fb8de87a7602d6e147..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6656 zcmeHLeQ;b=6+iFp?#pJIhJ3VX+LCnJ5GYO9Y?`zbY-zSlKLSk~x@n;}O#8BVNniW& z-tyjV+B8H`2mER}0y@ZtjL<>wV^C!13^K?FIF*q>M*(HP8A1F*9UUD6sgAb(&e^xg zwn0b#@gKO!{oQlUz4zR6&i#Dbd&BJ%BBC(z*|S7XqU6*i_@7}C)s;)0s-!2%Ut0R4 zw(X^*{rfFHp7q>e&lrhk499VE@c}dL<(;_Y#JhK-<0I~%nV35_c2S_ZZxhirEksLR zocCaHv^Qy4e2$hRs)0l=NZ$cVapW#!qAHuj zt84TxAc{>uLAbf;{j*5xKi@Th#Sm^@Fi}=05Z`dK2gTWma*#0}v5YnUe+PA|F(%C^ zt6L5`S}Iy7x`JwxN}V> zSyFx+?rY6;YMkRXwHVBa<^^h;LpODyaP?}OgE!S6+(I?Z@tbNCZjl=2$W7G>w^)sH z;HH)cccB{R_)W!yYf$4H#wm1GCz>18I7jlt@&!dZw<|AS3~F4p?PPtnBF>v!gVgzUW{5M!V3yiICL|6;x1%yI3$j^iwexm?1u{s^d4oY;rag<<;^xfotJHgHLmix>*aCN{dTKsdH>fr~f^$8mP& zFr$auW*8!?R+lw{<#4fBydiz{1})fqyq8Bi6UjtJvZMV9Fxa0q@Oqfg^a-LLpzLHi zo%1Yb*yk3fG0I_-O}o;Rg&lmnG;P_{(~WWx{0s1`X@l(!fae5OyY5C6Er*r#cddi4 zDlt)nKw&hZxya}y#||vy_Jl<&Z7{U(+#Vqk8T>=~q+%H#-cM+chIG;u;}7ZH&;|4o zn(9=pZBsh^QHwx+RB)N#dcju&-yp92tNJC-)EFP7cvz>J@ck-Ai)c4h(mV9Fs-y?B zx1sHbx*v2@B*P(=r+_-WEb_ca76?v?d@0?J+RFql5j-k*MDR8A(#Z$1Cmjs%kpHTX z7lzkOb6W#0Od8z&iCP%Gk>*etVpBzF@wO72PL1KOXgVdrCxFTDSAkcnuK^F!H-TyT zHt^!mf$NsWSwFXNWQx=!KlsQ*If$C{!p;Z9LP{S4fj0k>AYu7&B-O*8#? zU1+pbFC^kEskDq^H$U z(08f_f%m9qfe)y+fR89m^XXe^De$C#_ef(J9(OFQfbg$~TaIh5Q@j-(qGSEhyvO>cwYoBP^no8{+F^fhpV(qLre|enr)dmQYH*Oc-TZ)UQW~cr3da}$UFfzm z@8m478{LttXZn818NAN3awhF^MxkTKGSG1&9;c}s4%2}=YP!vV{O~Z#XJjegH%A8S zv3@I8DrQg9P-EEEk&@Q^hBs{HHsdjD9&){dv(;?2Y;(8i`S50TWsfuDdLstAYS^<{ zrOiwp4vh7g-iYOYu!fDUGh_|tJ<%~U09)G&H%xCv#&NN1X}Ht0jl)9uGxbHs`#elk zCO5l+6&TLgOhpiJk>{)d%Z9NtwKB&t!_#pSuG{pBaioF#(0S9B2*QB*l}RsLeAMp- zM7No-MhsgtB?fI<8f|c0n=lW1d$4{2g_zvT%u3+(v&qSi%vv2H4m-Oh=Y> zqG-9qii#7GlEpb~xH%Lo*J(`@0 zyo@~zA1pr)YNuo9Q6iIb8Knp|L$_rNJFcIzGXAukh5do;#p}TIpl;O4m_C&8EvVv*Hzya)8nHJo3=jos$d}_29c-#0m`v&O%4bgrYraW2X zkx4Ec3gr7yGe)#!9B1$ZPQG#6EQNAqP<8}mXHc#R%GE)6c~GuF$wy`M^~K3c-wIzd z71CckcIGd4QaG+@QCvG(1VnW;vz0=&GpQKL^!YW{YBd!VWucmi`86q!4UuR(qD7-o z6+tCSxKAyWS81vt(n!^2G^Q0QLS#uL zt>1e~^{cTf(Me4{l+Y$Wciz;LPA``GzddnU<3Yz@)3?Thjk<0Xp0D_8jc?4`xx8nt zbIg3sGwjxQAC77(bB#IH?;bRrbpy$cp;bed54E=su1Xpm#(b?`RizJFS!lxXoRO8U zDLtxmUFk8USA_KHUZu}fx&l?D^vaN4Gf(Le+;|O<2x*lK5q_4G#TBNbW|to4Voy{H zzRMf=Dc7&+_=eiOxc+I`#txNuc2L;T&3$Ys!wd+)W6a7%v3hpTJ&rbu0cWN zyy^43+w!xvF}5AYeUy8|(V|?VFdraz+-nq(%|uiI-R*_I6y(C-SzLJequ{$21z*c3 z_@Rx0?`#zK#^3@U7hK@I&jr8HBVuoO`T=n9saGdS>+NG@y~wTj)^FwCRD#3}@r8)H zooEboV+k3z4!iZPwGn_uYaC(wC%!q$`~V=7kodyHzKs-T1263*1CILG|F5w(a11fSU`yy3zN-e>x)v@$|cu zR}|r`SxCI}OVo<68>m66f!kp-?g$%qL=QQ*8(gWsNH$DAY7Izz)EksTI~QCbJr+KV zVKms3Ln{mN;SbRCinK}Mt||O=;-$??a0PavhBv%RBb1df#^8|w&J^|iD1B(=v{Kp@ zt?ZVXjEtE*$EMOgNo;Cu+MeC$<3Zny{q2;19mULJl%qXIASZ1d*kYGhRMefo-D=~H z({e;rqitwEEUnoa{*K~k4CD4?>*L5*itZhOoFm1$i~cZI@cM(sD8#7`eO-*4$5&FW z#47$hbtX + public class CustomTypeTestWrapper : NinoWrapperBase { - public override void Serialize(Vector3 val, ref Writer writer) + public override void Serialize(CustomTypeTest val, ref Writer writer) { - writer.Write(val.x); - writer.Write(val.y); - writer.Write(val.z); + writer.Write(ref val.v3, sizeof(float) * 3); + writer.Write(ref val.m, sizeof(float) * 16); + writer.Write(val.ni); + writer.Write(val.qs); + writer.Write(val.dict); + writer.Write(val.dict2); } - public override Vector3 Deserialize(Reader reader) + public override CustomTypeTest Deserialize(Reader reader) { - return new Vector3(reader.Read(4), reader.Read(4), reader.Read(4)); + var ret = new CustomTypeTest(); + reader.Read(ref ret.v3, sizeof(float) * 3); + reader.Read(ref ret.m, sizeof(float) * 16); + ret.ni = reader.ReadNullable(); + ret.qs = reader.ReadList(); + ret.dict = reader.ReadDictionary(); + ret.dict2 = reader.ReadDictionary(); + return ret; } - public override int GetSize(Vector3 val) + public override int GetSize(CustomTypeTest val) { - return 12; - } - } - - public class QuaternionWrapper : NinoWrapperBase - { - public override void Serialize(Quaternion val, ref Writer writer) - { - writer.Write(val.x); - writer.Write(val.y); - writer.Write(val.z); - writer.Write(val.w); - } - - public override Quaternion Deserialize(Reader reader) - { - return new Quaternion(reader.Read(4), reader.Read(4), reader.Read(4), - reader.Read(4)); - } - - public override int GetSize(Quaternion val) - { - return 16; - } - } - - public class Matrix4x4Wrapper : NinoWrapperBase - { - public override void Serialize(Matrix4x4 val, ref Writer writer) - { - writer.Write(val.m00); - writer.Write(val.m01); - writer.Write(val.m02); - writer.Write(val.m03); - writer.Write(val.m10); - writer.Write(val.m11); - writer.Write(val.m12); - writer.Write(val.m13); - writer.Write(val.m20); - writer.Write(val.m21); - writer.Write(val.m22); - writer.Write(val.m23); - writer.Write(val.m30); - writer.Write(val.m31); - writer.Write(val.m32); - writer.Write(val.m33); - } - - public override Matrix4x4 Deserialize(Reader reader) - { - return new Matrix4x4( - new Vector4(reader.Read(4), reader.Read(4), reader.Read(4), reader.Read(4)), - new Vector4(reader.Read(4), reader.Read(4), reader.Read(4), reader.Read(4)), - new Vector4(reader.Read(4), reader.Read(4), reader.Read(4), reader.Read(4)), - new Vector4(reader.Read(4), reader.Read(4), reader.Read(4), - reader.Read(4))); - } - - public override int GetSize(Matrix4x4 val) - { - return 64; + int ret = 1; + ret += sizeof(float) * 3; + ret += sizeof(float) * 16; + ret += Serializer.GetSize(val.ni); + ret += Serializer.GetSize(val.qs); + ret += Serializer.GetSize(val.dict); + ret += Serializer.GetSize(val.dict2); + return ret; } } @@ -96,9 +53,7 @@ public class Test7 public static void Main() { //register wrappers - WrapperManifest.AddWrapper(typeof(Vector3), new Vector3Wrapper()); - WrapperManifest.AddWrapper(typeof(Quaternion), new QuaternionWrapper()); - WrapperManifest.AddWrapper(typeof(Matrix4x4), new Matrix4x4Wrapper()); + WrapperManifest.AddWrapper(typeof(CustomTypeTest), new CustomTypeTestWrapper()); //custom type CustomTypeTest c = new CustomTypeTest() { diff --git a/README.md b/README.md index 9206fa5..d8f9dc5 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Definite useful and high performance modules for C# projects, especially for Uni ``` ```bash - PM> Install-Package Nino.Serialization -Version 1.2.1 + PM> Install-Package Nino.Serialization -Version 1.2.2 ``` - 使用src下的代码(复制进自己项目即可) diff --git a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs index bf745a2..160f4f9 100644 --- a/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs +++ b/src/Nino.Benchmark/Generated/Nino_Benchmark_Models_Data_Serialize.cs @@ -28,14 +28,7 @@ public override void Serialize(Data value, ref Nino.Serialization.Writer writer) { writer.Write(true); - writer.Write(ref value.X, sizeof(System.Int32)); - writer.Write(ref value.Y, sizeof(System.Int16)); - writer.Write(ref value.Z, sizeof(System.Int64)); - writer.Write(ref value.F, sizeof(System.Single)); - writer.Write(ref value.D, sizeof(System.Decimal)); - writer.Write(ref value.Db, sizeof(System.Double)); - writer.Write(ref value.Bo, sizeof(System.Boolean)); - writer.WriteEnum(value.En); + writer.Write(ref value.X, sizeof(System.Int32),ref value.Y, sizeof(System.Int16),ref value.Z, sizeof(System.Int64),ref value.F, sizeof(System.Single),ref value.D, sizeof(System.Decimal),ref value.Db, sizeof(System.Double),ref value.Bo, sizeof(System.Boolean),ref value.En, sizeof(Nino.Benchmark.Models.TestEnum)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -44,14 +37,7 @@ public override Data Deserialize(Nino.Serialization.Reader reader) if(!reader.ReadBool()) return default; Data value = new Data(); - reader.Read(ref value.X, sizeof(System.Int32)); - reader.Read(ref value.Y, sizeof(System.Int16)); - reader.Read(ref value.Z, sizeof(System.Int64)); - reader.Read(ref value.F, sizeof(System.Single)); - reader.Read(ref value.D, sizeof(System.Decimal)); - reader.Read(ref value.Db, sizeof(System.Double)); - reader.Read(ref value.Bo, sizeof(System.Boolean)); - reader.ReadEnum(ref value.En); + reader.Read(ref value.X, sizeof(System.Int32),ref value.Y, sizeof(System.Int16),ref value.Z, sizeof(System.Int64),ref value.F, sizeof(System.Single),ref value.D, sizeof(System.Decimal),ref value.Db, sizeof(System.Double),ref value.Bo, sizeof(System.Boolean),ref value.En, sizeof(Nino.Benchmark.Models.TestEnum)); return value; } diff --git a/src/Nino.Serialization/CodeGenerator.cs b/src/Nino.Serialization/CodeGenerator.cs index 1c83bdf..d3ef3e7 100644 --- a/src/Nino.Serialization/CodeGenerator.cs +++ b/src/Nino.Serialization/CodeGenerator.cs @@ -1,12 +1,11 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Nino.Shared.Mgr; using Nino.Shared.Util; using System.Reflection; -using System.Collections.Generic; -using System.Runtime.CompilerServices; namespace Nino.Serialization { @@ -194,15 +193,60 @@ public override int GetSize({type} value) model = TypeModel.CreateModel(type); } - HashSet members = model.Members; + var members = model.Members; #region serialize //build params StringBuilder sb = new StringBuilder(); - foreach (var member in members) + List unmanagedMembers = new List(); + for (int i = 0; i < members.Count; i++) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var info = members[i]; + var member = info.Member; + var mt = info.Type; + + //try optimize + if (TypeModel.IsUnmanaged(mt) && member is FieldInfo) + { + unmanagedMembers.Clear(); + unmanagedMembers.Add(info); + for (int j = i + 1; j < members.Count; j++) + { + var info2 = members[j]; + var member2 = info2.Member; + var mt2 = info2.Type; + if (TypeModel.IsUnmanaged(mt2) && member2 is FieldInfo) + { + unmanagedMembers.Add(info2); + } + else + { + break; + } + } + + i += unmanagedMembers.Count - 1; + //batch write with batch size 8 + while (unmanagedMembers.Count > 0) + { + if (unmanagedMembers.Count <= 8) + { + sb.Append( + $" writer.Write({string.Join(",", unmanagedMembers.Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.Clear(); + } + else + { + sb.Append( + $" writer.Write({string.Join(",", unmanagedMembers.Take(8).Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.RemoveRange(0, 8); + } + } + + continue; + } + //enum if (mt.IsEnum) { @@ -219,6 +263,11 @@ public override int GetSize({type} value) { sb.Append($" writer.Write(value.{member.Name});\n"); } + //nullable + else if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + sb.Append($" writer.Write(value.{member.Name});\n"); + } //basic type else { @@ -241,9 +290,53 @@ public override int GetSize({type} value) #region deserialize sb.Clear(); - foreach (var member in members) + for (int i = 0; i < members.Count; i++) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var info = members[i]; + var member = info.Member; + var mt = info.Type; + + //try optimize + if (TypeModel.IsUnmanaged(mt) && member is FieldInfo) + { + unmanagedMembers.Clear(); + unmanagedMembers.Add(info); + for (int j = i + 1; j < members.Count; j++) + { + var info2 = members[j]; + var member2 = info2.Member; + var mt2 = info2.Type; + if (TypeModel.IsUnmanaged(mt2) && member2 is FieldInfo) + { + unmanagedMembers.Add(info2); + } + else + { + break; + } + } + + i += unmanagedMembers.Count - 1; + //batch write with batch size 8 + while (unmanagedMembers.Count > 0) + { + if (unmanagedMembers.Count <= 8) + { + sb.Append( + $" reader.Read({string.Join(",", unmanagedMembers.Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.Clear(); + } + else + { + sb.Append( + $" reader.Read({string.Join(",", unmanagedMembers.Take(8).Select(x => $"ref value.{x.Member.Name}, sizeof({BeautifulLongTypeName(x.Type)})"))});\n"); + unmanagedMembers.RemoveRange(0, 8); + } + } + + continue; + } + //enum if (mt.IsEnum) { @@ -292,6 +385,15 @@ public override int GetSize({type} value) sb.Append( $" value.{member.Name} = reader.ReadDictionary<{BeautifulLongTypeName(keyType)},{BeautifulLongTypeName(valueType)}>();\n"); } + //nullable + else if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + var args = mt.GetGenericArguments(); + Type keyType = args[0]; + + sb.Append( + $" value.{member.Name} = reader.ReadNullable<{BeautifulLongTypeName(keyType)}>();\n"); + } //not enum -> basic type else { @@ -315,16 +417,19 @@ public override int GetSize({type} value) sb.Clear(); if (TypeModel.IsFixedSizeType(type)) { - sb.Append($" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); + sb.Append( + $" return Nino.Serialization.Serializer.GetFixedSize<{BeautifulLongTypeName(type)}>();"); } else { sb.Append(" int ret = 1;\n"); - foreach (var member in members) + foreach (var info in members) { + var member = info.Member; sb.Append( $" ret += Nino.Serialization.Serializer.GetSize(value.{member.Name});\n"); } + sb.Append(" return ret;"); } @@ -339,13 +444,15 @@ public override int GetSize({type} value) if (TypeModel.IsFixedSizeType(type)) { sb.Append(" int ret = 1;\n"); - foreach (var member in members) + foreach (var info in members) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + var mt = info.Type; sb.Append( $" ret += sizeof({BeautifulLongTypeName(mt)});\n"); } - sb.Append($" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); + + sb.Append( + $" Nino.Serialization.Serializer.SetFixedSize<{BeautifulLongTypeName(type)}>(ret);"); } //replace template fields @@ -517,6 +624,14 @@ private static string GetSerializeBasicTypeStatement(Type mt, string val, bool i return builder.ToString(); } + if (mt.IsGenericType && mt.GetGenericTypeDefinition() == ConstMgr.NullableDefType) + { + StringBuilder builder = new StringBuilder(); + builder.Append(space).Append(Repeat(" ", indent)) + .Append($"writer.Write({val});\n"); + return builder.ToString(); + } + return $"writer.WriteCommonVal<{BeautifulLongTypeName(mt)}>({val})"; } } diff --git a/src/Nino.Serialization/Deserializer.cs b/src/Nino.Serialization/Deserializer.cs index 8273981..9c8fa41 100644 --- a/src/Nino.Serialization/Deserializer.cs +++ b/src/Nino.Serialization/Deserializer.cs @@ -92,12 +92,24 @@ internal static T Deserialize(Span data, Reader reader, return ret; } + //enum + if (TryDeserializeEnum(type, reader, returnDispose, out var e)) + { + return e; + } + //code generated type if (TryDeserializeCodeGenType(type, reader, false, returnDispose, out ret)) { return ret; } + //unmanaged type + if (TryDeserializeUnmanagedType(type, reader, returnDispose, out var un)) + { + return un; + } + /* * GC DESERIALIZATION WHILE T IS STRUCT */ @@ -148,10 +160,6 @@ internal static object Deserialize(Type type, object val, Span data, Reade } } -#if ILRuntime - type = type.ResolveRealType(); -#endif - //basic type if (TryDeserializeWrapperType(type, reader, true, returnDispose, out object basicObj)) { @@ -163,13 +171,19 @@ internal static object Deserialize(Type type, object val, Span data, Reade { return e; } - + //code generated type if (TryDeserializeCodeGenType(type, reader, true, returnDispose, out object codeGenRet)) { return codeGenRet; } + //unmanaged type + if (TryDeserializeUnmanagedType(type, reader, returnDispose, out var un)) + { + return un; + } + /* * CUSTOM STRUCT/CLASS SERIALIZATION */ @@ -181,11 +195,7 @@ internal static object Deserialize(Type type, object val, Span data, Reade //create type if (val == null || val == ConstMgr.Null) { -#if ILRuntime - val = ILRuntimeResolver.CreateInstance(type); -#else val = Activator.CreateInstance(type); -#endif } //Get Attribute that indicates a class/struct to be serialized @@ -204,7 +214,7 @@ internal static object Deserialize(Type type, object val, Span data, Reade } //start Deserialize - foreach (var member in model.Members) + foreach (var info in model.Members) { //if end, skip if (reader.EndOfReader) @@ -212,10 +222,10 @@ internal static object Deserialize(Type type, object val, Span data, Reade break; } - type = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; + type = info.Type; //read basic values - SetMember(member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); + SetMember(info.Member, val, Deserialize(type, ConstMgr.Null, Span.Empty, reader, false)); } if (returnDispose) @@ -384,6 +394,33 @@ private static bool TryDeserializeDict(Type type, Type genericDefType, Reader re return false; } + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeEnum(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out T obj) + { + obj = default; + if (TypeModel.IsEnum(type)) + { + reader.ReadEnum(ref obj); + if (returnDispose) + { + ObjectPool.Return(reader); + } + + return true; + } + + return false; + } + /// /// Try deserialize enum /// @@ -400,16 +437,6 @@ private static bool TryDeserializeEnum(Type type, Reader reader, { var underlyingType = Enum.GetUnderlyingType(type); var ret = reader.ReadEnum(underlyingType); -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeType) - { - if (underlyingType == ConstMgr.LongType - || underlyingType == ConstMgr.UIntType - || underlyingType == ConstMgr.ULongType) - obj = unchecked((long)ret); - obj = unchecked((int)ret); - } -#endif obj = Enum.ToObject(type, ret); if (returnDispose) { @@ -423,6 +450,58 @@ private static bool TryDeserializeEnum(Type type, Reader reader, return false; } + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeUnmanagedType(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out T obj) + { + obj = default; + if (TypeModel.IsUnmanaged(type)) + { + reader.ReadAsUnmanaged(ref obj, Marshal.SizeOf(type)); + if (returnDispose) + { + ObjectPool.Return(reader); + } + return true; + } + + return false; + } + + /// + /// Try deserialize enum + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryDeserializeUnmanagedType(Type type, Reader reader, + [MarshalAs(UnmanagedType.U1)] bool returnDispose, out object obj) + { + obj = default; + if (TypeModel.IsUnmanaged(type)) + { + reader.ReadAsUnmanaged(ref obj, Marshal.SizeOf(type)); + if (returnDispose) + { + ObjectPool.Return(reader); + } + return true; + } + + return false; + } + /// /// Check for null /// diff --git a/src/Nino.Serialization/ILRuntimeResolver.cs b/src/Nino.Serialization/ILRuntimeResolver.cs deleted file mode 100644 index e3c564e..0000000 --- a/src/Nino.Serialization/ILRuntimeResolver.cs +++ /dev/null @@ -1,365 +0,0 @@ -using System; -using System.Text; -using System.Linq; -using Nino.Shared.Mgr; -using System.Reflection; -using System.Collections.Generic; -#if ILRuntime -#if DEBUG && !DISABLE_ILRUNTIME_DEBUG -using AutoList = System.Collections.Generic.List; -#else -using AutoList = ILRuntime.Other.UncheckedList; -#endif -#endif - -// ReSharper disable CognitiveComplexity -// ReSharper disable RedundantNameQualifier -// ReSharper disable RedundantExplicitArrayCreation - -namespace Nino.Serialization -{ -#if ILRuntime - /// - /// ILRuntime helper - /// - public static class ILRuntimeResolver - { - internal static ILRuntime.Runtime.Enviorment.AppDomain appDomain; - - private static readonly Dictionary IlRuntimeTypes = new Dictionary(); - - /// - /// Get ILType - /// - /// - /// - public static Type FindType(string metaName) - { - IlRuntimeTypes.TryGetValue(metaName, out Type type); - return type; - } - - /// - /// Create ILTypeInstance - /// - /// - /// - public static object CreateInstance(Type type) - { - if (appDomain != null) - { - string typeName = type.FullName; - if (FindType(typeName) != null) - { - return appDomain.Instantiate(typeName); - } - - if (typeName != null && appDomain.LoadedTypes.ContainsKey(typeName)) - { - IlRuntimeTypes[typeName] = type; - return appDomain.Instantiate(typeName); - } - } - - return Activator.CreateInstance(type); - } - - /// - /// Reg ILRuntime - /// - /// - public static unsafe void RegisterILRuntimeClrRedirection(ILRuntime.Runtime.Enviorment.AppDomain domain) - { - appDomain = domain; - //cache types - IlRuntimeTypes.Clear(); - var allTypes = domain.LoadedTypes.Values.Select(x => x.ReflectionType).ToArray(); - foreach (var t in allTypes) - { - if (t.FullName != null) - { - IlRuntimeTypes[t.FullName] = t; - TypeModel.AllTypes[t.GetHashCode()] = t; - } - } - - try - { - appDomain.RegisterCrossBindingAdaptor(new SerializationHelper1ILTypeInstanceAdapter()); - } - catch - { - //ignore - } - - //reg redirections - MethodBase method; - var type = typeof(Nino.Serialization.Serializer); - var genericMethods = new Dictionary>(); - List lst; - foreach (var m in type.GetMethods()) - { - if (m.IsGenericMethodDefinition) - { - if (!genericMethods.TryGetValue(m.Name, out lst)) - { - lst = new List(); - genericMethods[m.Name] = lst; - } - - lst.Add(m); - } - } - - var args = new Type[] { typeof(ILRuntime.Runtime.Intepreter.ILTypeInstance) }; - var ps = new Type[] { args[0], typeof(Nino.Serialization.CompressOption) }; - if (genericMethods.TryGetValue("Serialize", out lst)) - { - foreach (var m in lst) - { - if (ILRuntime.Runtime.Extensions.MatchGenericParameters(m, args, typeof(System.Byte[]), - ps)) - { - method = m.MakeGenericMethod(args); - appDomain.RegisterCLRMethodRedirection(method, Serialize_0); - - break; - } - } - } - - type = typeof(Nino.Serialization.Deserializer); - genericMethods.Clear(); - lst?.Clear(); - foreach (var m in type.GetMethods()) - { - if (m.IsGenericMethodDefinition) - { - if (!genericMethods.TryGetValue(m.Name, out lst)) - { - lst = new List(); - genericMethods[m.Name] = lst; - } - - lst.Add(m); - } - } - - //Deserialize - if (genericMethods.TryGetValue("Deserialize", out lst)) - { - foreach (var m in lst) - { - appDomain.RegisterCLRMethodRedirection(m, Deserialize_0); - } - } - } - - /// - /// Deserialize reg - /// - /// - /// - /// - /// - /// - /// - private static unsafe ILRuntime.Runtime.Stack.StackObject* Deserialize_0( - ILRuntime.Runtime.Intepreter.ILIntepreter intp, ILRuntime.Runtime.Stack.StackObject* esp, - AutoList mStack, - ILRuntime.CLR.Method.CLRMethod method, bool isNewObj) - { - var domain = intp.AppDomain; - var ret = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - - var ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 1); - var @option = (Nino.Serialization.CompressOption)ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - typeof(Nino.Serialization.CompressOption), - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - (ILRuntime.CLR.Utils.Extensions.TypeFlags)20); - intp.Free(ptrOfThisMethod); - - ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - var @data = ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack); - intp.Free(ptrOfThisMethod); - - //获取泛型参数的实际类型 - var genericArguments = method.GenericArguments; - var t = genericArguments[0]; - - object resultOfThisMethod = null; - if (@data is byte[] buf) - { - resultOfThisMethod = - Nino.Serialization.Deserializer.Deserialize(t.ReflectionType, buf, option); - } - else if (@data is ArraySegment seg) - { - resultOfThisMethod = - Nino.Serialization.Deserializer.Deserialize(t.ReflectionType, seg, option); - } - - return ILRuntime.Runtime.Intepreter.ILIntepreter.PushObject(ret, mStack, resultOfThisMethod); - } - - /// - /// Serialize reg - /// - /// - /// - /// - /// - /// - /// - private static unsafe ILRuntime.Runtime.Stack.StackObject* Serialize_0( - ILRuntime.Runtime.Intepreter.ILIntepreter intp, ILRuntime.Runtime.Stack.StackObject* esp, - AutoList mStack, - ILRuntime.CLR.Method.CLRMethod method, bool isNewObj) - { - var domain = intp.AppDomain; - var ret = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - - var ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 1); - var @option = (Nino.Serialization.CompressOption)ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - typeof(Nino.Serialization.CompressOption), - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - (ILRuntime.CLR.Utils.Extensions.TypeFlags)20); - intp.Free(ptrOfThisMethod); - - //获取泛型参数的实际类型 - var genericArguments = method.GenericArguments; - var t = genericArguments[0]; - ptrOfThisMethod = ILRuntime.Runtime.Intepreter.ILIntepreter.Minus(esp, 2); - var val = ILRuntime.CLR.Utils.Extensions.CheckCLRTypes( - t.ReflectionType, - ILRuntime.Runtime.Stack.StackObject.ToObject(ptrOfThisMethod, domain, mStack), - 0); - intp.Free(ptrOfThisMethod); - - var resultOfThisMethod = - Nino.Serialization.Serializer.Serialize(val, option); - - return ILRuntime.Runtime.Intepreter.ILIntepreter.PushObject(ret, mStack, resultOfThisMethod); - } - - /// - /// Resolve real type - /// - /// - /// - public static Type ResolveRealType(this Type type) - { - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - return wt.RealType; - } - - return type; - } - } - - public class SerializationHelper1ILTypeInstanceAdapter : ILRuntime.Runtime.Enviorment.CrossBindingAdaptor - { - public override Type BaseCLRType - { - get { return typeof(Nino.Serialization.NinoWrapperBase); } - } - - public override Type AdaptorType - { - get { return typeof(Adapter); } - } - - public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, - ILRuntime.Runtime.Intepreter.ILTypeInstance instance) - { - return new Adapter(appdomain, instance); - } - - public class Adapter : Nino.Serialization.NinoWrapperBase, - ILRuntime.Runtime.Enviorment.CrossBindingAdaptorType - { - bool isInvokingToString; - ILRuntime.Runtime.Intepreter.ILTypeInstance instance; - ILRuntime.Runtime.Enviorment.AppDomain appdomain; - - private ILRuntime.CLR.Method.IMethod write; - private ILRuntime.CLR.Method.IMethod read; - - public Adapter() - { - - } - - public Adapter(ILRuntime.Runtime.Enviorment.AppDomain appdomain, - ILRuntime.Runtime.Intepreter.ILTypeInstance instance) - { - this.appdomain = appdomain; - this.instance = instance; - } - - public ILRuntime.Runtime.Intepreter.ILTypeInstance ILInstance - { - get { return instance; } - } - - public override void Serialize(ILRuntime.Runtime.Intepreter.ILTypeInstance val, - Nino.Serialization.Writer writer) - { - if (write == null) - { - string Name = nameof(Serialize); - var ilType = instance.Type; - write = ilType.GetMethod(Name, 2); - } - - using (var ctx = appdomain.BeginInvoke(write)) - { - ctx.PushObject(instance); - ctx.PushObject(val); - ctx.PushObject(writer); - ctx.Invoke(); - } - } - - public override ILRuntime.Runtime.Intepreter.ILTypeInstance Deserialize(Nino.Serialization.Reader reader) - { - if (read == null) - { - string Name = nameof(Deserialize); - var ilType = instance.Type; - read = ilType.GetMethod(Name, 1); - } - - using (var ctx = appdomain.BeginInvoke(read)) - { - ctx.PushObject(instance); - ctx.PushObject(reader); - ctx.Invoke(); - return ctx.ReadObject(); - } - } - - public override string ToString() - { - ILRuntime.CLR.Method.IMethod m = appdomain.ObjectType.GetMethod("ToString", 0); - m = instance.Type.GetVirtualMethod(m); - if (m == null || m is ILRuntime.CLR.Method.ILMethod) - { - if (!isInvokingToString) - { - isInvokingToString = true; - string res = instance.ToString(); - isInvokingToString = false; - return res; - } - else - return instance.Type.FullName; - } - else - return instance.Type.FullName; - } - } - } -#endif -} \ No newline at end of file diff --git a/src/Nino.Serialization/Nino.Serialization.csproj b/src/Nino.Serialization/Nino.Serialization.csproj index 60de09d..a4f4476 100644 --- a/src/Nino.Serialization/Nino.Serialization.csproj +++ b/src/Nino.Serialization/Nino.Serialization.csproj @@ -18,10 +18,13 @@ https://github.com/JasonXuDeveloper/Nino en-001 true - 1.2.1 + 1.2.2 true - Nino.Serialization v1.2.1 -- [optimization] better generator and better size computation + Nino.Serialization v1.2.2 +- [optimization] better generator and better size computation +- [optimization] faster serialization/deserialization +- [optimization] lowerge +- [remove] no longer support ILRuntime git diff --git a/src/Nino.Serialization/Reader.Generic.cs b/src/Nino.Serialization/Reader.Generic.cs index fa1a1fc..03f8fac 100644 --- a/src/Nino.Serialization/Reader.Generic.cs +++ b/src/Nino.Serialization/Reader.Generic.cs @@ -84,6 +84,27 @@ public T Read(int len) where T : unmanaged return ret; } + /// + /// Read unmanaged type + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable UnusedMember.Local + internal void ReadAsUnmanaged(ref T val, int len) + // ReSharper restore UnusedMember.Local + { + if (EndOfReader) + { + return; + } + + Span span = buffer.AsSpan(position, len); + var first = span[0]; + val = Unsafe.ReadUnaligned(ref first); + position += len; + } + /// /// Read unmanaged type /// @@ -103,6 +124,197 @@ public void Read(ref T val, int len) where T : unmanaged position += len; } + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2) where T1 : unmanaged where T2 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3) + where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4) where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged where T4 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7) + where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + val7 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T7))); + position += len7; + } + + /// + /// Read unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7, + ref T8 val8, int len8) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + where T8 : unmanaged + { + if (EndOfReader) + { + return; + } + + val1 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T1))); + position += len1; + val2 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T2))); + position += len2; + val3 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T3))); + position += len3; + val4 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T4))); + position += len4; + val5 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T5))); + position += len5; + val6 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T6))); + position += len6; + val7 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T7))); + position += len7; + val8 = MemoryMarshal.Read(buffer.AsSpan(position, sizeof(T8))); + position += len8; + } + /// /// Read nullable /// diff --git a/src/Nino.Serialization/Reader.cs b/src/Nino.Serialization/Reader.cs index 5109e8b..a22f87f 100644 --- a/src/Nino.Serialization/Reader.cs +++ b/src/Nino.Serialization/Reader.cs @@ -360,12 +360,7 @@ public Array ReadArray(Type type) while (i < len) { var obj = ReadCommonVal(elemType); -#if ILRuntime - arr.SetValue(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj), i++); - continue; -#else arr.SetValue(obj, i++); -#endif } return arr; @@ -392,17 +387,6 @@ public IList ReadList(Type type) //check null if (!ReadBool()) return null; var elemType = type.GenericTypeArguments[0]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - elemType = wt?.CLRType.GenericArguments[0].Value.ReflectionType; - } - - if(!elemType.IsGenericType) - { - elemType = elemType.ResolveRealType(); - } -#endif //read len int len = ReadLength(); @@ -413,12 +397,7 @@ public IList ReadList(Type type) while (i++ < len) { var obj = ReadCommonVal(elemType); -#if ILRuntime - arr?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(elemType, obj)); - continue; -#else arr?.Add(obj); -#endif } return arr; @@ -438,29 +417,7 @@ public IDictionary ReadDictionary(Type type) //parse dict type var args = type.GetGenericArguments(); Type keyType = args[0]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt) - { - keyType = wt?.CLRType.GenericArguments[0].Value.ReflectionType; - } - - if(!keyType.IsGenericType) - { - keyType = keyType.ResolveRealType(); - } -#endif Type valueType = args[1]; -#if ILRuntime - if (type is ILRuntime.Reflection.ILRuntimeWrapperType wt2) - { - valueType = wt2?.CLRType.GenericArguments[1].Value.ReflectionType; - } - - if(!valueType.IsGenericType) - { - valueType = valueType.ResolveRealType(); - } -#endif var dict = Activator.CreateInstance(type) as IDictionary; @@ -477,13 +434,7 @@ public IDictionary ReadDictionary(Type type) var val = ReadCommonVal(valueType); //add -#if ILRuntime - dict?.Add(ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(keyType, key), - ILRuntime.CLR.Utils.Extensions.CheckCLRTypes(valueType, val)); - continue; -#else dict?.Add(key, val); -#endif } return dict; diff --git a/src/Nino.Serialization/Serializer.Generic.cs b/src/Nino.Serialization/Serializer.Generic.cs index 7c60631..65dad70 100644 --- a/src/Nino.Serialization/Serializer.Generic.cs +++ b/src/Nino.Serialization/Serializer.Generic.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Nino.Serialization { @@ -57,6 +58,27 @@ private static bool TrySerializeEnumType(Type type, ref T value, ref Writer w return true; } + /// + /// Attempt to serialize unmanaged type + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrySerializeUnmanagedType(Type type, ref T value, ref Writer writer) + { + //enum + if (!TypeModel.IsUnmanaged(type)) + { + return false; + } + + writer.WriteAsUnmanaged(ref value, Marshal.SizeOf()); + return true; + } + /// /// Attempt to serialize code gen type (first time only) /// diff --git a/src/Nino.Serialization/Serializer.Helper.cs b/src/Nino.Serialization/Serializer.Helper.cs index 3f64695..ef9f858 100644 --- a/src/Nino.Serialization/Serializer.Helper.cs +++ b/src/Nino.Serialization/Serializer.Helper.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Nino.Shared.Mgr; namespace Nino.Serialization @@ -48,7 +49,7 @@ public static int GetFixedSize() return -1; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void SetFixedSize(int size) { @@ -60,7 +61,7 @@ public static int GetSize(in T[] val = default, Dictionary(in T[] val = default, Dictionary() * length + 1 + 4; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + 4 + length * size; @@ -82,7 +88,7 @@ public static int GetSize(in List val = default, Dictionary(in List val = default, Dictionary() * length + 1 + 4; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + 4 + length * size; } - + return GetSize(typeof(List), val, members); } @@ -113,6 +124,11 @@ public static int GetSize(in T? val = default, Dictionary } } + if (TypeModel.IsUnmanaged(type)) + { + return Unsafe.SizeOf() + 1; + } + if (FixedSizeCache.TryGetValue(type, out var size)) { return 1 + size; @@ -126,7 +142,7 @@ public static int GetSize(in T val = default, Dictionary var type = typeof(T); int size = 0; if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); - + //nullable if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { @@ -140,7 +156,7 @@ public static int GetSize(in T val = default, Dictionary { return size + size2; } - + if (!WrapperManifest.TryGetWrapper(type, out var wrapper)) { //code generated type @@ -161,13 +177,18 @@ public static int GetSize(in T val = default, Dictionary return size + wrapper.GetSize(val); } + if (TypeModel.IsUnmanaged(type)) + { + return Unsafe.SizeOf(); + } + return GetSize(type, val, members); } public static int GetSize(Type type, object obj, Dictionary members = null) { if (TypeModel.IsEnum(type)) type = type.GetEnumUnderlyingType(); - + int size = 0; bool isGeneric = type.IsGenericType; Type genericTypeDef = null; @@ -207,8 +228,13 @@ public static int GetSize(Type type, object obj, Dictionary return size + wrapper.GetSize(obj); } + if (TypeModel.IsUnmanaged(type)) + { + return Marshal.SizeOf(type); + } + size = 1; //null indicator - + if (type == ConstMgr.ObjectType) { type = obj.GetType(); @@ -377,31 +403,16 @@ public static int GetSize(Type type, object obj, Dictionary } var isFixed = true; - foreach (var member in model.Members) + foreach (var info in model.Members) { - Type memberType; - object memberObj; - switch (member) - { - case FieldInfo fi: - memberType = fi.FieldType; - memberObj = fi.GetValue(obj); - break; - case PropertyInfo pi: - memberType = pi.PropertyType; - memberObj = pi.GetValue(obj); - break; - default: - throw new Exception("Invalid member type"); - } - + object memberObj = info.GetValue(obj); if (members != null) { - members[member] = memberObj; + members[info.Member] = memberObj; } - size += GetSize(memberType, memberObj); - if (!FixedSizeCache.ContainsKey(memberType)) + size += GetSize(info.Type, memberObj); + if (!FixedSizeCache.ContainsKey(info.Type)) { isFixed = false; } diff --git a/src/Nino.Serialization/Serializer.cs b/src/Nino.Serialization/Serializer.cs index 8b6b4a2..5b2f0b7 100644 --- a/src/Nino.Serialization/Serializer.cs +++ b/src/Nino.Serialization/Serializer.cs @@ -26,7 +26,13 @@ public static byte[] Serialize(in T val) } byte[] ret = new byte[length]; - Serialize(ret.AsSpan(), in val, fields); + if (val == null) + { + ObjectPool>.Return(fields); + return ret; + } + + Serialize(typeof(T), val, fields, ret.AsSpan(), 0); ObjectPool>.Return(fields); return ret; } @@ -73,6 +79,7 @@ public static byte[] Serialize(object val) ObjectPool>.Return(fields); return ret; } + Serialize(val.GetType(), val, fields, ret.AsSpan(), 0); ObjectPool>.Return(fields); return ret; @@ -96,18 +103,9 @@ public static int Serialize(Span buffer, object val) return Serialize(val.GetType(), val, null, buffer, 0); } - internal static int Serialize(Type type, T value, Dictionary fields ,Span buffer, int pos) + internal static int Serialize(Type type, T value, Dictionary fields, Span buffer, + int pos) { - //ILRuntime -#if ILRuntime - if(value is ILRuntime.Runtime.Intepreter.ILTypeInstance ins) - { - type = ins.Type.ReflectionType; - } - - type = type.ResolveRealType(); -#endif - Writer writer = new Writer(buffer, pos); //null check @@ -136,6 +134,11 @@ internal static int Serialize(Type type, T value, Dictionary(Type type, T value, Dictionary Members; + + public struct NinoMember + { + public MemberInfo Member; + public Type Type; + public Func GetValue; + + public NinoMember(MemberInfo member, Type type, Func getValue) + { + Member = member; + Type = type; + GetValue = getValue; + } + } - public HashSet Members; public bool Valid; public bool IncludeAll; @@ -95,12 +111,6 @@ internal class TypeModel /// internal static TypeCode GetTypeCode(Type type) { -#if ILRuntime - if (IsEnum(type) && type is ILRuntime.Reflection.ILRuntimeType) - { - type = Enum.GetUnderlyingType(type); - } -#endif var hash = type.GetTypeHashCode(); if (TypeCodes.TryGetValue(hash, out var ret)) { @@ -155,10 +165,9 @@ public static bool IsFixedSizeType(Type type) } // otherwise check recursively - foreach (var member in model.Members) + foreach (var info in model.Members) { - var mt = member is FieldInfo fi ? fi.FieldType : ((PropertyInfo)member).PropertyType; - if (!IsFixedSizeType(mt)) + if (!IsFixedSizeType(info.Type)) { ret = false; break; @@ -187,7 +196,8 @@ public static bool IsUnmanaged(Type type) .GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); foreach (var field in fields) { - if (!IsUnmanaged(field.FieldType)) + if (field.GetCustomAttributes(CompilerGeneratedType, true).Length > 0 || + !IsUnmanaged(field.FieldType)) { ret = false; break; @@ -278,7 +288,7 @@ internal static TypeModel CreateModel(Type type) { Valid = true, //fetch members - Members = new HashSet(), + Members = new List(), }; //include all or not @@ -296,6 +306,11 @@ internal static TypeModel CreateModel(Type type) //iterate fields foreach (var f in fs) { + if (f.GetCustomAttributes(CompilerGeneratedType, true).Length > 0) + { + continue; + } + if (model.IncludeAll) { //skip nino ignore @@ -354,7 +369,14 @@ internal static TypeModel CreateModel(Type type) //add members to model foreach (var pair in dict) { - model.Members.Add(pair.Value); + if (pair.Value is FieldInfo fi) + { + model.Members.Add(new NinoMember(fi, fi.FieldType, fi.GetValue)); + } + else if (pair.Value is PropertyInfo pi) + { + model.Members.Add(new NinoMember(pi, pi.PropertyType, pi.GetValue)); + } } //release dict diff --git a/src/Nino.Serialization/Writer.Generic.cs b/src/Nino.Serialization/Writer.Generic.cs index 047f17b..5adbdcd 100644 --- a/src/Nino.Serialization/Writer.Generic.cs +++ b/src/Nino.Serialization/Writer.Generic.cs @@ -27,6 +27,18 @@ public ref partial struct Writer public void WriteCommonVal(Type type, T val) => Position = Serializer.Serialize(type, val, null, buffer, Position); + /// + /// Write unmanaged type + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteAsUnmanaged(ref T val, int len) + { + Unsafe.WriteUnaligned(ref buffer[Position], val); + Position += len; + } + /// /// Write unmanaged type /// @@ -39,6 +51,163 @@ public void Write(ref T val, int len) where T : unmanaged Position += len; } + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2) + where T1 : unmanaged where T2 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3) + where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4) where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged where T4 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, int len3, + ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7) + where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + Unsafe.WriteUnaligned(ref buffer[Position], val7); + Position += len7; + } + + /// + /// Write unmanaged type + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T1 val1, int len1, ref T2 val2, int len2, ref T3 val3, + int len3, ref T4 val4, int len4, ref T5 val5, int len5, ref T6 val6, int len6, ref T7 val7, int len7, + ref T8 val8, int len8) where T1 : unmanaged + where T2 : unmanaged + where T3 : unmanaged + where T4 : unmanaged + where T5 : unmanaged + where T6 : unmanaged + where T7 : unmanaged + where T8 : unmanaged + { + Unsafe.WriteUnaligned(ref buffer[Position], val1); + Position += len1; + Unsafe.WriteUnaligned(ref buffer[Position], val2); + Position += len2; + Unsafe.WriteUnaligned(ref buffer[Position], val3); + Position += len3; + Unsafe.WriteUnaligned(ref buffer[Position], val4); + Position += len4; + Unsafe.WriteUnaligned(ref buffer[Position], val5); + Position += len5; + Unsafe.WriteUnaligned(ref buffer[Position], val6); + Position += len6; + Unsafe.WriteUnaligned(ref buffer[Position], val7); + Position += len7; + Unsafe.WriteUnaligned(ref buffer[Position], val8); + Position += len8; + } + /// /// Write byte[] /// @@ -171,13 +340,7 @@ public void Write(T[] arr) while (i < len) { var obj = arr[i++]; -#if ILRuntime - var eType = obj is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : obj.GetType(); -#else var eType = obj.GetType(); -#endif WriteCommonVal(eType, obj); } } @@ -228,14 +391,7 @@ public void Write(List lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -268,14 +424,7 @@ public void Write(HashSet lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -308,14 +457,7 @@ public void Write(Queue lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -348,14 +490,7 @@ public void Write(Stack lst) //write item foreach (var c in lst) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif } } @@ -392,24 +527,10 @@ public void Write(Dictionary dictionary) foreach (var c in keys) { //write key -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); - WriteCommonVal(eType, c); -#else WriteCommonVal(c); -#endif //write val var val = dictionary[c]; -#if ILRuntime - eType = val is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns2 - ? ilIns2.Type.ReflectionType - : val.GetType(); - WriteCommonVal(eType, val); -#else WriteCommonVal(val); -#endif } } } diff --git a/src/Nino.Serialization/Writer.cs b/src/Nino.Serialization/Writer.cs index 20c3b68..3325915 100644 --- a/src/Nino.Serialization/Writer.cs +++ b/src/Nino.Serialization/Writer.cs @@ -259,13 +259,7 @@ public void Write(Array arr) while (i < len) { var obj = arr.GetValue(i++); -#if ILRuntime - var eType = obj is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : obj.GetType(); -#else var eType = obj.GetType(); -#endif WriteCommonVal(eType, obj); } } @@ -297,13 +291,7 @@ public void Write(IList arr) //write item foreach (var c in arr) { -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); -#else var eType = c.GetType(); -#endif WriteCommonVal(eType, c); } } @@ -338,23 +326,11 @@ public void Write(IDictionary dictionary) foreach (var c in keys) { //write key -#if ILRuntime - var eType = c is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns - ? ilIns.Type.ReflectionType - : c.GetType(); -#else var eType = c.GetType(); -#endif WriteCommonVal(eType, c); //write val var val = dictionary[c]; -#if ILRuntime - eType = val is ILRuntime.Runtime.Intepreter.ILTypeInstance ilIns2 - ? ilIns2.Type.ReflectionType - : val.GetType(); -#else eType = val.GetType(); -#endif WriteCommonVal(eType, val); } }