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.
This commit is contained in:
Loretta 2026-01-27 19:01:03 +01:00
parent d0e2637741
commit 94dfa1b5f5
2 changed files with 12 additions and 17 deletions

View File

@ -169,7 +169,7 @@ public static partial class AcBinaryDeserializer
/// <summary>
/// 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.
/// </summary>
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<byte, int>(_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

View File

@ -237,7 +237,7 @@ public static partial class AcBinarySerializer
/// <summary>
/// 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[].
/// </summary>
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<byte, int>(_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