Editor/HumanoidRetargeter/Embedded/ValveResourceFormat/ThirdParty/MurmurHash2.cs
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using HumanoidRetargeterVrf.Utils;
namespace HumanoidRetargeterVrf.ThirdParty
{
    /// <summary>
    /// Provides MurmurHash2 hashing algorithm implementation.
    /// </summary>
    public static class MurmurHash2
    {
        private const uint M = 0x5bd1e995;
        private const int R = 24;

        /// <summary>
        /// Computes a MurmurHash2 hash for the given string.
        /// </summary>
        /// <param name="data">The string to hash.</param>
        /// <param name="seed">The hash seed.</param>
        /// <returns>The hash value.</returns>
        public static uint Hash(string data, uint seed) => Hash(data.AsSpan(), seed);

        /// <summary>
        /// Computes a MurmurHash2 hash for the given character span.
        /// </summary>
        /// <param name="data">The character span to hash.</param>
        /// <param name="seed">The hash seed.</param>
        /// <returns>The hash value.</returns>
        public static uint Hash(ReadOnlySpan<char> data, uint seed)
        {
            var length = data.Length;

            if (length == 0)
            {
                return 0;
            }

            var h = seed ^ (uint)length;
            var currentIndex = 0;
            while (length >= 4)
            {
                var k = (uint)(data[currentIndex++] | data[currentIndex++] << 8 | data[currentIndex++] << 16 | data[currentIndex++] << 24);
                k *= M;
                k ^= k >> R;
                k *= M;

                h *= M;
                h ^= k;
                length -= 4;
            }

            switch (length)
            {
                case 3:
                    h ^= (ushort)(data[currentIndex++] | data[currentIndex++] << 8);
                    h ^= (uint)(data[currentIndex] << 16);
                    h *= M;
                    break;
                case 2:
                    h ^= (ushort)(data[currentIndex++] | data[currentIndex] << 8);
                    h *= M;
                    break;
                case 1:
                    h ^= data[currentIndex];
                    h *= M;
                    break;
                default:
                    break;
            }

            h ^= h >> 13;
            h *= M;
            h ^= h >> 15;

            return h;
        }
    }
}