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));
}