Enable FastWire mode for binary string serialization

Activate FastWire encoding for both serialization and deserialization, using UTF-16 and fixed-width lengths for strings. WireMode is now public and defaults to FastWire. Removes unused ObjectEnd marker, clarifying object end handling. This improves string (de)serialization speed at the cost of larger output.
This commit is contained in:
Loretta 2026-03-03 13:53:58 +01:00
parent a1a2a90ef7
commit bbed1caf44
6 changed files with 38 additions and 38 deletions

View File

@ -330,15 +330,15 @@ public static partial class AcBinaryDeserializer
} }
// FastWire: length is char count, data is UTF-16 (2 bytes per char) // FastWire: length is char count, data is UTF-16 (2 bytes per char)
//if (FastWire) if (FastWire)
//{ {
// var byteLen = length * 2; var byteLen = length * 2;
// EnsureAvailable(byteLen); EnsureAvailable(byteLen);
// var chars = MemoryMarshal.Cast<byte, char>(_buffer.AsSpan(_position, byteLen)); var chars = MemoryMarshal.Cast<byte, char>(_buffer.AsSpan(_position, byteLen));
// var value = new string(chars); var value = new string(chars);
// _position += byteLen; _position += byteLen;
// return value; return value;
//} }
EnsureAvailable(length); EnsureAvailable(length);

View File

@ -63,7 +63,7 @@ public static partial class AcBinaryDeserializer
public bool HasMetadata; public bool HasMetadata;
public bool IsMergeMode; public bool IsMergeMode;
public bool RemoveOrphanedItems; public bool RemoveOrphanedItems;
//public bool FastWire; public bool FastWire;
// Options-derived properties // Options-derived properties
public byte MinStringInternLength => Options.MinStringInternLength; public byte MinStringInternLength => Options.MinStringInternLength;
@ -139,7 +139,7 @@ public static partial class AcBinaryDeserializer
HasMetadata = false; HasMetadata = false;
IsMergeMode = false; IsMergeMode = false;
RemoveOrphanedItems = false; RemoveOrphanedItems = false;
//FastWire = Options.WireMode == WireMode.Fast; FastWire = Options.WireMode == WireMode.Fast;
ChainTracker = null; ChainTracker = null;
} }

View File

@ -242,7 +242,7 @@ public static partial class AcBinarySerializer
/// Reference handling is safe because generated code inlines TryConsumeWritePlanEntry for IId types. /// Reference handling is safe because generated code inlines TryConsumeWritePlanEntry for IId types.
/// </summary> /// </summary>
public bool IsDirectObjectWrite => !UseMetadata; public bool IsDirectObjectWrite => !UseMetadata;
//public bool FastWire { get; private set; } public bool FastWire { get; private set; }
public byte MinStringInternLength => Options.MinStringInternLength; public byte MinStringInternLength => Options.MinStringInternLength;
public byte MaxStringInternLength => Options.MaxStringInternLength; public byte MaxStringInternLength => Options.MaxStringInternLength;
public BinaryPropertyFilter? PropertyFilter => Options.PropertyFilter; public BinaryPropertyFilter? PropertyFilter => Options.PropertyFilter;
@ -281,7 +281,7 @@ public static partial class AcBinarySerializer
HasPropertyFilter = Options.PropertyFilter != null; HasPropertyFilter = Options.PropertyFilter != null;
InternBit = 1 << (int)Options.UseStringInterning; InternBit = 1 << (int)Options.UseStringInterning;
HasStringInterning = Options.UseStringInterning != StringInterningMode.None; HasStringInterning = Options.UseStringInterning != StringInterningMode.None;
//FastWire = Options.WireMode == WireMode.Fast; FastWire = Options.WireMode == WireMode.Fast;
} }
public override void Clear() public override void Clear()
@ -630,17 +630,17 @@ public static partial class AcBinarySerializer
public void WriteStringUtf8(string value) public void WriteStringUtf8(string value)
{ {
//if (FastWire) if (FastWire)
//{ {
// // UTF-16: char count (fixed uint) + raw char data (zero-encoding memcopy) // UTF-16: char count (VarUInt) + raw char data (zero-encoding memcopy)
// var charLen = value.Length; var charLen = value.Length;
// var byteLen = charLen * 2; var byteLen = charLen * 2;
// WriteRaw(charLen); WriteVarUInt((uint)charLen);
// EnsureCapacity(byteLen); EnsureCapacity(byteLen);
// MemoryMarshal.AsBytes(value.AsSpan()).CopyTo(_buffer.AsSpan(_position, byteLen)); MemoryMarshal.AsBytes(value.AsSpan()).CopyTo(_buffer.AsSpan(_position, byteLen));
// _position += byteLen; _position += byteLen;
// return; return;
//} }
var charLength = value.Length; var charLength = value.Length;

View File

@ -1023,12 +1023,12 @@ public static partial class AcBinarySerializer
} }
// FastWire: skip FixStr optimization (UTF-8 specific), write String marker + UTF-16 data // FastWire: skip FixStr optimization (UTF-8 specific), write String marker + UTF-16 data
//if (context.FastWire) if (context.FastWire)
//{ {
// context.WriteByte(BinaryTypeCode.String); context.WriteByte(BinaryTypeCode.String);
// context.WriteStringUtf8(value); context.WriteStringUtf8(value);
// return; return;
//} }
// Fast path for short strings: check length first (cheap), then ASCII // Fast path for short strings: check length first (cheap), then ASCII
// FixStr encodes type+length in single byte for strings <= 31 chars // FixStr encodes type+length in single byte for strings <= 31 chars

View File

@ -85,6 +85,13 @@ public sealed class AcBinarySerializerOptions : AcSerializerOptions
public bool UseMetadata { get; set; } = false; public bool UseMetadata { get; set; } = false;
public bool UseGeneratedCode { get; set; } = true; public bool UseGeneratedCode { get; set; } = true;
/// <summary>
/// Wire encoding mode.
/// Compact: VarInt + UTF-8 (default, smaller output).
/// Fast: Fixed-width integers + UTF-16 (larger output, faster encode/decode).
/// </summary>
public WireMode WireMode { get; set; } = WireMode.Fast;
/// <summary> /// <summary>
/// Controls how string interning is applied during serialization. /// Controls how string interning is applied during serialization.
/// None: No interning, all strings written inline. /// None: No interning, all strings written inline.
@ -94,13 +101,6 @@ public sealed class AcBinarySerializerOptions : AcSerializerOptions
/// </summary> /// </summary>
public StringInterningMode UseStringInterning { get; set; } = StringInterningMode.Attribute; public StringInterningMode UseStringInterning { get; set; } = StringInterningMode.Attribute;
/// <summary>
/// Wire encoding mode.
/// Compact: VarInt + UTF-8 (default, smaller output).
/// Fast: Fixed-width integers + UTF-16 (larger output, faster encode/decode).
/// </summary>
//public WireMode WireMode { get; set; } = WireMode.Compact;
/// <summary> /// <summary>
/// When true, checks for duplicate property name hashes during serialization (UseMetadata mode). /// When true, checks for duplicate property name hashes during serialization (UseMetadata mode).
/// Throws exception if FNV-1a hash collision is detected between property names of the same type. /// Throws exception if FNV-1a hash collision is detected between property names of the same type.

View File

@ -44,7 +44,7 @@ internal static class BinaryTypeCode
// Complex types (25-31) // Complex types (25-31)
public const byte Object = 25; // Start of object (non-tracked OR first occurrence when ref tracking) public const byte Object = 25; // Start of object (non-tracked OR first occurrence when ref tracking)
public const byte ObjectEnd = 26; // End of object marker //public const byte ObjectEnd = 26; // UNUSED — property count is known at compile-time (SGen) or reflection-time (runtime), no end marker needed
public const byte ObjectRef = 27; // Reference to previously serialized object (2+ occurrence) public const byte ObjectRef = 27; // Reference to previously serialized object (2+ occurrence)
public const byte Array = 28; // Start of array/list public const byte Array = 28; // Start of array/list
public const byte Dictionary = 29; // Start of dictionary public const byte Dictionary = 29; // Start of dictionary