Skip to content

Instantly share code, notes, and snippets.

@rdev5
Forked from automatonic/MurMurHash3.cs
Last active November 4, 2015 17:25
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 rdev5/5bf9916849ad578b0439 to your computer and use it in GitHub Desktop.
Save rdev5/5bf9916849ad578b0439 to your computer and use it in GitHub Desktop.
MurMurHash3 .Net (C#) implementation
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TinyWAF.Helpers
{
public static class MurmurHash3
{
// Source: https://gist.github.com/rdev5/5bf9916849ad578b0439
const uint seed = 144;
// Source: http://stackoverflow.com/a/1879470/901156
public static Stream CreateStreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
public static int Hash(string input)
{
const uint c1 = 0xcc9e2d51;
const uint c2 = 0x1b873593;
uint h1 = seed;
uint k1 = 0;
uint streamLength = 0;
// TODO: Parallelize
var chunk = new byte[4];
var reader = Encoding.UTF8.GetBytes(input);
for (var i = 0; i < reader.Length; i += 4)
{
switch(reader.Length - i)
{
case 3:
k1 = (uint)
(chunk[0]
| chunk[1] << 8
| chunk[2] << 16);
k1 *= c1;
k1 = rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
break;
case 2:
k1 = (uint)
(chunk[0]
| chunk[1] << 8);
k1 *= c1;
k1 = rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
break;
case 1:
k1 = (uint)(chunk[0]);
k1 *= c1;
k1 = rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
break;
default:
chunk[0] = reader[i];
chunk[1] = reader[i + 1];
chunk[2] = reader[i + 2];
chunk[3] = reader[i + 3];
/* Get four bytes from the input into an uint */
k1 = (uint)
(chunk[0]
| chunk[1] << 8
| chunk[2] << 16
| chunk[3] << 24);
/* bitmagic hash */
k1 *= c1;
k1 = rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = rotl32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
break;
}
}
// finalization, magic chants to wrap it all up
h1 ^= (uint)reader.Length;
h1 = fmix(h1);
// ignore overflow
unchecked
{
return (int)h1;
}
}
public static int Hash(Stream stream)
{
const uint c1 = 0xcc9e2d51;
const uint c2 = 0x1b873593;
uint h1 = seed;
uint k1 = 0;
uint streamLength = 0;
using (BinaryReader reader = new BinaryReader(stream))
{
byte[] chunk = reader.ReadBytes(4);
while (chunk.Length > 0)
{
streamLength += (uint)chunk.Length;
switch(chunk.Length)
{
case 4:
/* Get four bytes from the input into an uint */
k1 = (uint)
(chunk[0]
| chunk[1] << 8
| chunk[2] << 16
| chunk[3] << 24);
/* bitmagic hash */
k1 *= c1;
k1 = rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = rotl32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
break;
case 3:
k1 = (uint)
(chunk[0]
| chunk[1] << 8
| chunk[2] << 16);
k1 *= c1;
k1 = rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
break;
case 2:
k1 = (uint)
(chunk[0]
| chunk[1] << 8);
k1 *= c1;
k1 = rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
break;
case 1:
k1 = (uint)(chunk[0]);
k1 *= c1;
k1 = rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
break;
}
chunk = reader.ReadBytes(4);
}
}
// finalization, magic chants to wrap it all up
h1 ^= streamLength;
h1 = fmix(h1);
unchecked //ignore overflow
{
return (int)h1;
}
}
private static uint rotl32(uint x, byte r)
{
return (x << r) | (x >> (32 - r));
}
private static uint fmix(uint h)
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment