diff --git a/AyCode.Core.Serializers.SourceGenerator/AcBinarySourceGenerator.cs b/AyCode.Core.Serializers.SourceGenerator/AcBinarySourceGenerator.cs index f07a866..1cadf4e 100644 --- a/AyCode.Core.Serializers.SourceGenerator/AcBinarySourceGenerator.cs +++ b/AyCode.Core.Serializers.SourceGenerator/AcBinarySourceGenerator.cs @@ -2020,6 +2020,11 @@ public class AcBinarySourceGenerator : IIncrementalGenerator /// /// Emits inline string read from type code. Handles all string wire formats. + /// FixStr (range 34-65) is checked first as hot path for short strings. + /// Remaining codes use switch for O(1) JIT jump-table dispatch: + /// String=16, StringInterned=17, StringEmpty=18, StringInternFirst=19, Null=0. + /// This eliminates the sequential if-else chain that penalized StringInterned + /// (the hot path for repeated interned strings) with 4 comparisons. /// private static void EmitReadString(StringBuilder sb, string a, string tc, string i) { @@ -2029,24 +2034,36 @@ public class AcBinarySourceGenerator : IIncrementalGenerator sb.AppendLine($"{i} var flen = BinaryTypeCode.DecodeFixStrLength({tc});"); sb.AppendLine($"{i} {a} = flen == 0 ? string.Empty : context.ReadStringUtf8(flen);"); sb.AppendLine($"{i}}}"); - sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.String)"); + // Switch gives O(1) dispatch via JIT jump table for codes 0, 16-19. + // StringInterned (17) is the hot path for repeated interned strings — no longer buried at 4th else-if. + sb.AppendLine($"{i}else switch ({tc})"); sb.AppendLine($"{i}{{"); - sb.AppendLine($"{i} var slen = (int)context.ReadVarUInt();"); - sb.AppendLine($"{i} {a} = slen == 0 ? string.Empty : context.ReadStringUtf8(slen);"); + sb.AppendLine($"{i} case BinaryTypeCode.StringInterned:"); + sb.AppendLine($"{i} {a} = context.GetInternedString((int)context.ReadVarUInt());"); + sb.AppendLine($"{i} break;"); + sb.AppendLine($"{i} case BinaryTypeCode.String:"); + sb.AppendLine($"{i} {{"); + sb.AppendLine($"{i} var slen = (int)context.ReadVarUInt();"); + sb.AppendLine($"{i} {a} = slen == 0 ? string.Empty : context.ReadStringUtf8(slen);"); + sb.AppendLine($"{i} break;"); + sb.AppendLine($"{i} }}"); + sb.AppendLine($"{i} case BinaryTypeCode.StringInternFirst:"); + sb.AppendLine($"{i} {{"); + sb.AppendLine($"{i} context.DisableStringCaching();"); + sb.AppendLine($"{i} var sci = (int)context.ReadVarUInt();"); + sb.AppendLine($"{i} var slen2 = (int)context.ReadVarUInt();"); + sb.AppendLine($"{i} var sv = slen2 == 0 ? string.Empty : context.ReadStringUtf8(slen2);"); + sb.AppendLine($"{i} context.RegisterInternedValueAt(sci, sv);"); + sb.AppendLine($"{i} {a} = sv;"); + sb.AppendLine($"{i} break;"); + sb.AppendLine($"{i} }}"); + sb.AppendLine($"{i} case BinaryTypeCode.Null:"); + sb.AppendLine($"{i} {a} = null;"); + sb.AppendLine($"{i} break;"); + sb.AppendLine($"{i} case BinaryTypeCode.StringEmpty:"); + sb.AppendLine($"{i} {a} = string.Empty;"); + sb.AppendLine($"{i} break;"); sb.AppendLine($"{i}}}"); - sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.StringInternFirst)"); - sb.AppendLine($"{i}{{"); - sb.AppendLine($"{i} context.DisableStringCaching();"); - sb.AppendLine($"{i} var sci = (int)context.ReadVarUInt();"); - sb.AppendLine($"{i} var slen2 = (int)context.ReadVarUInt();"); - sb.AppendLine($"{i} var sv = slen2 == 0 ? string.Empty : context.ReadStringUtf8(slen2);"); - sb.AppendLine($"{i} context.RegisterInternedValueAt(sci, sv);"); - sb.AppendLine($"{i} {a} = sv;"); - sb.AppendLine($"{i}}}"); - sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.StringInterned)"); - sb.AppendLine($"{i} {a} = context.GetInternedString((int)context.ReadVarUInt());"); - sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.Null) {a} = null;"); - sb.AppendLine($"{i}else if ({tc} == BinaryTypeCode.StringEmpty) {a} = string.Empty;"); } /// diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializerOptions.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializerOptions.cs index 6b01f75..681e792 100644 --- a/AyCode.Core/Serializers/Binaries/AcBinarySerializerOptions.cs +++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializerOptions.cs @@ -83,7 +83,6 @@ public sealed class AcBinarySerializerOptions : AcSerializerOptions /// Default: false (no overhead) /// public bool UseMetadata { get; set; } = false; - public bool UseGeneratedCode { get; set; } = true; ///