From 94dfa1b5f53c372f35dc7672b1b55e849b8ae4bc Mon Sep 17 00:00:00 2001 From: Loretta Date: Tue, 27 Jan 2026 19:01:03 +0100 Subject: [PATCH] Switch interned string footer to VarUInt encoding Update serializer and deserializer to use VarUInt for (position, cacheIndex) pairs in interned string footers, replacing fixed int32 format. This reduces serialized size and improves efficiency for small values. Adjust deserializer to read VarUInt pairs into a flat int[] array. Update comments and docs accordingly. --- ...yDeserializer.BinaryDeserializationContext.cs | 16 ++++++++-------- ...inarySerializer.BinarySerializationContext.cs | 13 ++++--------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.BinaryDeserializationContext.cs b/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.BinaryDeserializationContext.cs index 88de2d6..25fe89b 100644 --- a/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.BinaryDeserializationContext.cs +++ b/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.BinaryDeserializationContext.cs @@ -169,7 +169,7 @@ public static partial class AcBinaryDeserializer /// /// Reads string intern footer: [dupCount][pos0][idx0][pos1][idx1]... - /// Fixed int32 format for ultra-fast MemoryMarshal.Cast bulk read. + /// VarUInt format read into flat int[] for fast hot path access. /// private void ReadFooterStringIndices(int footerPosition) { @@ -179,7 +179,7 @@ public static partial class AcBinaryDeserializer // Seek to footer _position = footerPosition; - // Read dup count (still VarUInt for backward compat header) + // Read dup count var dupCount = (int)ReadVarUInt(); if (dupCount == 0) { @@ -189,14 +189,14 @@ public static partial class AcBinaryDeserializer } else { - // Bulk read: dupCount * 2 int32s (position, cacheIndex pairs) + // Read VarUInt pairs into flat int[] var intCount = dupCount * 2; - var byteCount = intCount * sizeof(int); - EnsureAvailable(byteCount); - _dupData = new int[intCount]; - MemoryMarshal.Cast(_buffer.Slice(_position, byteCount)).CopyTo(_dupData); - _position += byteCount; + for (var i = 0; i < dupCount; i++) + { + _dupData[i * 2] = (int)ReadVarUInt(); // position + _dupData[i * 2 + 1] = (int)ReadVarUInt(); // cacheIndex + } _internStringCache = new string[dupCount]; // Cache first dup position for ultra-fast hot path diff --git a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs index ef5fd5a..c85c47f 100644 --- a/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs +++ b/AyCode.Core/Serializers/Binaries/AcBinarySerializer.BinarySerializationContext.cs @@ -237,7 +237,7 @@ public static partial class AcBinarySerializer /// /// Writes the footer with (position, cacheIndex) pairs sorted by position. - /// Fixed int32 format for ultra-fast MemoryMarshal.Cast bulk read in deserializer. + /// VarUInt format for compact size, deserializer reads into flat int[]. /// public void WriteInternedStringFooter() { @@ -261,17 +261,12 @@ public static partial class AcBinarySerializer // Sort by StreamPosition (ascending) for deserializer sequential check entries.Sort((a, b) => a.Position.CompareTo(b.Position)); - // Write pairs as fixed int32s: [pos0][idx0][pos1][idx1]... - // This allows MemoryMarshal.Cast bulk read in deserializer - var byteCount = _nextCacheIndex * 2 * sizeof(int); - EnsureCapacity(byteCount); - var dest = MemoryMarshal.Cast(_buffer.AsSpan(_position, byteCount)); + // Write pairs as VarUInt for compact size for (var i = 0; i < _nextCacheIndex; i++) { - dest[i * 2] = entries[i].Position; - dest[i * 2 + 1] = entries[i].CacheIndex; + WriteVarUInt((uint)entries[i].Position); + WriteVarUInt((uint)entries[i].CacheIndex); } - _position += byteCount; } #endregion