using System; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Shader.HashTable { /// /// State of a hash calculation. /// struct HashState { // This is using a slightly modified implementation of FastHash64. // Reference: https://github.com/ztanml/fast-hash/blob/master/fasthash.c private const ulong M = 0x880355f21e6d1965UL; private ulong _hash; private int _start; /// /// One shot hash calculation for a given data. /// /// Data to be hashed /// Hash of the given data public static uint CalcHash(ReadOnlySpan data) { HashState state = new(); state.Initialize(); state.Continue(data); return state.Finalize(data); } /// /// Initializes the hash state. /// public void Initialize() { _hash = 23; } /// /// Calculates the hash of the given data. /// /// /// The full data must be passed on . /// If this is not the first time the method is called, then must start with the data passed on the last call. /// If a smaller slice of the data was already hashed before, only the additional data will be hashed. /// This can be used for additive hashing of data in chuncks. /// /// Data to be hashed public void Continue(ReadOnlySpan data) { ulong h = _hash; ReadOnlySpan dataAsUlong = MemoryMarshal.Cast(data[_start..]); for (int i = 0; i < dataAsUlong.Length; i++) { ulong value = dataAsUlong[i]; h ^= Mix(value); h *= M; } _hash = h; _start = data.Length & ~7; } /// /// Performs the hash finalization step, and returns the calculated hash. /// /// /// The full data must be passed on . /// must start with the data passed on the last call to . /// No internal state is changed, so one can still continue hashing data with /// after calling this method. /// /// Data to be hashed /// Hash of all the data hashed with this public readonly uint Finalize(ReadOnlySpan data) { ulong h = _hash; int remainder = data.Length & 7; if (remainder != 0) { ulong v = 0; for (int i = data.Length - remainder; i < data.Length; i++) { v |= (ulong)data[i] << ((i - remainder) * 8); } h ^= Mix(v); h *= M; } h = Mix(h); return (uint)(h - (h >> 32)); } /// /// Hash mix function. /// /// Hash to mix /// Mixed hash private static ulong Mix(ulong h) { h ^= h >> 23; h *= 0x2127599bf4325c37UL; h ^= h >> 47; return h; } } }