using System.Buffers.Binary; using System.Text; namespace Godosa.Core.Runs; /// FNV-1a 64 over state bytes (numbers little-endian, strings UTF-8) for comparing runs. public sealed class StateDigest { private const ulong Offset = 14695981039346656037UL, Prime = 1099511628211UL; public ulong Value { get; private set; } = Offset; public string Hex => Value.ToString("x16"); public static ulong Of(ReadOnlySpan bytes) { var d = new StateDigest(); d.Add(bytes); return d.Value; } public void Add(ReadOnlySpan bytes) { var h = Value; foreach (var b in bytes) h = (h ^ b) * Prime; Value = h; } public void Add(byte b) => Value = (Value ^ b) * Prime; public void Add(uint v) { Span b = stackalloc byte[4]; BinaryPrimitives.WriteUInt32LittleEndian(b, v); Add(b); } public void Add(int v) => Add(unchecked((uint)v)); public void Add(ulong v) { Span b = stackalloc byte[8]; BinaryPrimitives.WriteUInt64LittleEndian(b, v); Add(b); } public void Add(long v) => Add(unchecked((ulong)v)); public void Add(float v) => Add(BitConverter.SingleToUInt32Bits(v)); public void Add(double v) => Add(BitConverter.DoubleToUInt64Bits(v)); public void Add(string s) => Add(Encoding.UTF8.GetBytes(s)); }