aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/src/Godosa.Core/Runs/StateDigest.cs
blob: a7adaf2635ac8c6f01b815f052b23c0b430400fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System.Buffers.Binary;
using System.Text;

namespace Godosa.Core.Runs;

/// <summary>FNV-1a 64 over state bytes (numbers little-endian, strings UTF-8) for comparing runs.</summary>
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<byte> bytes)
    {
        var d = new StateDigest();
        d.Add(bytes);
        return d.Value;
    }

    public void Add(ReadOnlySpan<byte> 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<byte> 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<byte> 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));
}