Skip to content

Instantly share code, notes, and snippets.

@andreinitescu
Forked from KirillOsenkov/FnvHash.cs
Created January 6, 2021 06:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreinitescu/9a0ff5c120d3e7053b3b3f0a39e3551b to your computer and use it in GitHub Desktop.
Save andreinitescu/9a0ff5c120d3e7053b3b3f0a39e3551b to your computer and use it in GitHub Desktop.
/// <summary>
/// A hash combiner that is implemented with the Fowler/Noll/Vo algorithm (FNV-1a). This is a mutable struct for performance reasons.
/// Taken from https://gist.github.com/StephenCleary/4f6568e5ab5bee7845943fdaef8426d2
/// </summary>
public struct FnvHash
{
/// <summary>
/// The starting point of the FNV hash.
/// </summary>
public const long Offset = 2166136261;
/// <summary>
/// The prime number used to compute the FNV hash.
/// </summary>
private const long Prime = 16777619;
/// <summary>
/// Gets the current result of the hash function.
/// </summary>
public long HashCode { get; private set; }
public FnvHash(long hash)
{
HashCode = hash;
}
/// <summary>
/// Creates a new FNV hash initialized to <see cref="Offset"/>.
/// </summary>
public static FnvHash Create()
{
var result = new FnvHash();
result.HashCode = Offset;
return result;
}
public static long GetHashCode(string text)
{
var hash = Create();
for (int i = 0; i < text.Length; i++)
{
hash.Combine(text[i]);
}
return hash.HashCode;
}
public static long Combine(long left, long right)
{
var fnv = new FnvHash(left);
fnv.Combine(right);
return fnv.HashCode;
}
/// <summary>
/// Adds the specified byte to the hash.
/// </summary>
/// <param name="data">The byte to hash.</param>
public void Combine(byte data)
{
unchecked
{
HashCode ^= data;
HashCode *= Prime;
}
}
public void Combine(char data)
{
unchecked
{
var sh = (ushort)data;
Combine(unchecked((byte)sh));
Combine(unchecked((byte)(sh >> 8)));
}
}
/// <summary>
/// Adds the specified integer to this hash, in little-endian order.
/// </summary>
/// <param name="data">The integer to hash.</param>
public void Combine(int data)
{
Combine(unchecked((byte)data));
Combine(unchecked((byte)(data >> 8)));
Combine(unchecked((byte)(data >> 16)));
Combine(unchecked((byte)(data >> 24)));
}
public void Combine(long data)
{
Combine(unchecked((byte)data));
Combine(unchecked((byte)(data >> 8)));
Combine(unchecked((byte)(data >> 16)));
Combine(unchecked((byte)(data >> 24)));
Combine(unchecked((byte)(data >> 32)));
Combine(unchecked((byte)(data >> 40)));
Combine(unchecked((byte)(data >> 48)));
Combine(unchecked((byte)(data >> 56)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment