From 0ff40a6777f393685213b59f69d25ed29fb22378 Mon Sep 17 00:00:00 2001 From: Loretta Date: Sun, 1 Mar 2026 07:22:13 +0100 Subject: [PATCH] Refactor string read logic; remove UseGeneratedCode option Refactored EmitReadString to use a switch for O(1) dispatch of string wire formats, improving performance and clarity. Updated comments to document the new approach and its benefits. Removed the UseGeneratedCode property from AcBinarySerializerOptions. --- .../AcBinarySourceGenerator.cs | 49 +++++++++++++------ .../Binaries/AcBinarySerializerOptions.cs | 1 - 2 files changed, 33 insertions(+), 17 deletions(-) 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; ///