Skip to content

Commit 572baa2

Browse files
committed
Implement Net Standard 1.6 version of MurmurHash library
1 parent 9179b52 commit 572baa2

13 files changed

+1016
-0
lines changed

MurmurHash-net-core/Extensions.cs

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/// Copyright 2012 Darren Kopp
2+
///
3+
/// Licensed under the Apache License, Version 2.0 (the "License");
4+
/// you may not use this file except in compliance with the License.
5+
/// You may obtain a copy of the License at
6+
///
7+
/// http://www.apache.org/licenses/LICENSE-2.0
8+
///
9+
/// Unless required by applicable law or agreed to in writing, software
10+
/// distributed under the License is distributed on an "AS IS" BASIS,
11+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
/// See the License for the specific language governing permissions and
13+
/// limitations under the License.
14+
15+
using System;
16+
using System.Runtime.CompilerServices;
17+
18+
namespace Murmur
19+
{
20+
internal static class Extensions
21+
{
22+
#if NETFX45
23+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
24+
#endif
25+
internal static uint ToUInt32(this byte[] data, int start)
26+
{
27+
return BitConverter.IsLittleEndian
28+
? (uint)(data[start] | data[start + 1] << 8 | data[start + 2] << 16 | data[start + 3] << 24)
29+
: (uint)(data[start] << 24 | data[start + 1] << 16 | data[start + 2] << 8 | data[start + 3]);
30+
}
31+
32+
#if NETFX45
33+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
34+
#endif
35+
internal static ulong ToUInt64(this byte[] data, int start)
36+
{
37+
if (BitConverter.IsLittleEndian)
38+
{
39+
uint i1 = (uint)(data[start] | data[start + 1] << 8 | data[start + 2] << 16 | data[start + 3] << 24);
40+
ulong i2 = (ulong)(data[start + 4] | data[start + 5] << 8 | data[start + 6] << 16 | data[start + 7] << 24);
41+
return (i1 | i2 << 32);
42+
}
43+
else
44+
{
45+
ulong i1 = (ulong)(data[start] << 24 | data[start + 1] << 16 | data[start + 2] << 8 | data[start + 3]);
46+
uint i2 = (uint)(data[start + 4] << 24 | data[start + 5] << 16 | data[start + 6] << 8 | data[start + 7]);
47+
return (i2 | i1 << 32);
48+
49+
//int i1 = (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3));
50+
//int i2 = (*(pbyte + 4) << 24) | (*(pbyte + 5) << 16) | (*(pbyte + 6) << 8) | (*(pbyte + 7));
51+
//return (uint)i2 | ((long)i1 << 32);
52+
}
53+
}
54+
55+
#if NETFX45
56+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
57+
#endif
58+
internal static uint RotateLeft(this uint x, byte r)
59+
{
60+
return (x << r) | (x >> (32 - r));
61+
}
62+
63+
#if NETFX45
64+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
65+
#endif
66+
internal static ulong RotateLeft(this ulong x, byte r)
67+
{
68+
return (x << r) | (x >> (64 - r));
69+
}
70+
71+
#if NETFX45
72+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
73+
#endif
74+
internal static uint FMix(this uint h)
75+
{
76+
// pipelining friendly algorithm
77+
h = (h ^ (h >> 16)) * 0x85ebca6b;
78+
h = (h ^ (h >> 13)) * 0xc2b2ae35;
79+
return h ^ (h >> 16);
80+
}
81+
82+
#if NETFX45
83+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
84+
#endif
85+
internal static ulong FMix(this ulong h)
86+
{
87+
// pipelining friendly algorithm
88+
h = (h ^ (h >> 33)) * 0xff51afd7ed558ccd;
89+
h = (h ^ (h >> 33)) * 0xc4ceb9fe1a85ec53;
90+
91+
return (h ^ (h >> 33));
92+
}
93+
}
94+
}
2.81 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/// Copyright 2012 Darren Kopp
2+
///
3+
/// Licensed under the Apache License, Version 2.0 (the "License");
4+
/// you may not use this file except in compliance with the License.
5+
/// You may obtain a copy of the License at
6+
///
7+
/// http://www.apache.org/licenses/LICENSE-2.0
8+
///
9+
/// Unless required by applicable law or agreed to in writing, software
10+
/// distributed under the License is distributed on an "AS IS" BASIS,
11+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
/// See the License for the specific language governing permissions and
13+
/// limitations under the License.
14+
15+
using System;
16+
using System.Runtime.CompilerServices;
17+
18+
namespace Murmur
19+
{
20+
internal class Murmur128ManagedX64 : Murmur128
21+
{
22+
const ulong C1 = 0x87c37b91114253d5;
23+
const ulong C2 = 0x4cf5ad432745937f;
24+
25+
internal Murmur128ManagedX64(uint seed = 0)
26+
: base(seed)
27+
{
28+
Reset();
29+
}
30+
31+
private int Length { get; set; }
32+
private ulong H1 { get; set; }
33+
private ulong H2 { get; set; }
34+
35+
private void Reset()
36+
{
37+
// initialize hash values to seed values
38+
H1 = H2 = Seed;
39+
// reset our length back to 0
40+
Length = 0;
41+
}
42+
43+
public override void Initialize()
44+
{
45+
Reset();
46+
}
47+
48+
protected override void HashCore(byte[] array, int ibStart, int cbSize)
49+
{
50+
// increment our length
51+
Length += cbSize;
52+
Body(array, ibStart, cbSize);
53+
}
54+
55+
#if NETFX45
56+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
57+
#endif
58+
private void Body(byte[] data, int start, int length)
59+
{
60+
int remainder = length & 15;
61+
int alignedLength = start + (length - remainder);
62+
for (int i = start; i < alignedLength; i += 16)
63+
{
64+
H1 ^= (data.ToUInt64(i) * C1).RotateLeft(31) * C2;
65+
H1 = (H1.RotateLeft(27) + H2) * 5 + 0x52dce729;
66+
67+
H2 ^= (data.ToUInt64(i + 8) * C2).RotateLeft(33) * C1;
68+
H2 = (H2.RotateLeft(31) + H1) * 5 + 0x38495ab5;
69+
}
70+
71+
if (remainder > 0)
72+
Tail(data, alignedLength, remainder);
73+
}
74+
75+
#if NETFX45
76+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
77+
#endif
78+
private void Tail(byte[] tail, int start, int remaining)
79+
{
80+
// create our keys and initialize to 0
81+
ulong k1 = 0, k2 = 0;
82+
83+
// determine how many bytes we have left to work with based on length
84+
switch (remaining)
85+
{
86+
case 15: k2 ^= (ulong)tail[start + 14] << 48; goto case 14;
87+
case 14: k2 ^= (ulong)tail[start + 13] << 40; goto case 13;
88+
case 13: k2 ^= (ulong)tail[start + 12] << 32; goto case 12;
89+
case 12: k2 ^= (ulong)tail[start + 11] << 24; goto case 11;
90+
case 11: k2 ^= (ulong)tail[start + 10] << 16; goto case 10;
91+
case 10: k2 ^= (ulong)tail[start + 9] << 8; goto case 9;
92+
case 9: k2 ^= (ulong)tail[start + 8] << 0; goto case 8;
93+
case 8: k1 ^= (ulong)tail[start + 7] << 56; goto case 7;
94+
case 7: k1 ^= (ulong)tail[start + 6] << 48; goto case 6;
95+
case 6: k1 ^= (ulong)tail[start + 5] << 40; goto case 5;
96+
case 5: k1 ^= (ulong)tail[start + 4] << 32; goto case 4;
97+
case 4: k1 ^= (ulong)tail[start + 3] << 24; goto case 3;
98+
case 3: k1 ^= (ulong)tail[start + 2] << 16; goto case 2;
99+
case 2: k1 ^= (ulong)tail[start + 1] << 8; goto case 1;
100+
case 1: k1 ^= (ulong)tail[start] << 0; break;
101+
}
102+
103+
H2 ^= (k2 * C2).RotateLeft(33) * C1;
104+
H1 ^= (k1 * C1).RotateLeft(31) * C2;
105+
}
106+
107+
protected override byte[] HashFinal()
108+
{
109+
ulong len = (ulong)Length;
110+
H1 ^= len; H2 ^= len;
111+
112+
H1 += H2;
113+
H2 += H1;
114+
115+
H1 = H1.FMix();
116+
H2 = H2.FMix();
117+
118+
H1 += H2;
119+
H2 += H1;
120+
121+
var result = new byte[16];
122+
Array.Copy(BitConverter.GetBytes(H1), 0, result, 0, 8);
123+
Array.Copy(BitConverter.GetBytes(H2), 0, result, 8, 8);
124+
125+
return result;
126+
}
127+
}
128+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/// Copyright 2012 Darren Kopp
2+
///
3+
/// Licensed under the Apache License, Version 2.0 (the "License");
4+
/// you may not use this file except in compliance with the License.
5+
/// You may obtain a copy of the License at
6+
///
7+
/// http://www.apache.org/licenses/LICENSE-2.0
8+
///
9+
/// Unless required by applicable law or agreed to in writing, software
10+
/// distributed under the License is distributed on an "AS IS" BASIS,
11+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
/// See the License for the specific language governing permissions and
13+
/// limitations under the License.
14+
15+
using System;
16+
using System.Runtime.CompilerServices;
17+
18+
namespace Murmur
19+
{
20+
internal class Murmur128ManagedX86 : Murmur128
21+
{
22+
const uint C1 = 0x239b961bU;
23+
const uint C2 = 0xab0e9789U;
24+
const uint C3 = 0x38b34ae5U;
25+
const uint C4 = 0xa1e38b93U;
26+
27+
internal Murmur128ManagedX86(uint seed = 0)
28+
: base(seed)
29+
{
30+
Reset();
31+
}
32+
33+
private uint H1 { get; set; }
34+
private uint H2 { get; set; }
35+
private uint H3 { get; set; }
36+
private uint H4 { get; set; }
37+
private int Length { get; set; }
38+
39+
private void Reset()
40+
{
41+
// initialize hash values to seed values
42+
H1 = H2 = H3 = H4 = Seed;
43+
Length = 0;
44+
}
45+
46+
public override void Initialize()
47+
{
48+
Reset();
49+
}
50+
51+
protected override void HashCore(byte[] array, int ibStart, int cbSize)
52+
{
53+
// store the length of the hash (for use later)
54+
Length += cbSize;
55+
Body(array, ibStart, cbSize);
56+
}
57+
58+
#if NETFX45
59+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
60+
#endif
61+
private void Body(byte[] data, int start, int length)
62+
{
63+
int remainder = length & 15;
64+
int alignedLength = start + (length - remainder);
65+
for (int i = start; i < alignedLength; i += 16)
66+
{
67+
uint k1 = data.ToUInt32(i),
68+
k2 = data.ToUInt32(i + 4),
69+
k3 = data.ToUInt32(i + 8),
70+
k4 = data.ToUInt32(i + 12);
71+
72+
H1 ^= (k1 * C1).RotateLeft(15) * C2;
73+
H1 = (H1.RotateLeft(19) + H2) * 5 + 0x561ccd1b;
74+
75+
H2 ^= (k2 * C2).RotateLeft(16) * C3;
76+
H2 = (H2.RotateLeft(17) + H3) * 5 + 0x0bcaa747;
77+
78+
H3 ^= (k3 * C3).RotateLeft(17) * C4;
79+
H3 = (H3.RotateLeft(15) + H4) * 5 + 0x96cd1c35;
80+
81+
H4 ^= (k4 * C4).RotateLeft(18) * C1;
82+
H4 = (H4.RotateLeft(13) + H1) * 5 + 0x32ac3b17;
83+
}
84+
85+
if (remainder > 0)
86+
Tail(data, alignedLength, remainder);
87+
}
88+
89+
#if NETFX45
90+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
91+
#endif
92+
private void Tail(byte[] tail, int position, int remainder)
93+
{
94+
// create our keys and initialize to 0
95+
uint k1 = 0, k2 = 0, k3 = 0, k4 = 0;
96+
97+
// determine how many bytes we have left to work with based on length
98+
switch (remainder)
99+
{
100+
case 15: k4 ^= (uint)tail[position + 14] << 16; goto case 14;
101+
case 14: k4 ^= (uint)tail[position + 13] << 8; goto case 13;
102+
case 13: k4 ^= (uint)tail[position + 12] << 0; goto case 12;
103+
case 12: k3 ^= (uint)tail[position + 11] << 24; goto case 11;
104+
case 11: k3 ^= (uint)tail[position + 10] << 16; goto case 10;
105+
case 10: k3 ^= (uint)tail[position + 9] << 8; goto case 9;
106+
case 9: k3 ^= (uint)tail[position + 8] << 0; goto case 8;
107+
case 8: k2 ^= (uint)tail[position + 7] << 24; goto case 7;
108+
case 7: k2 ^= (uint)tail[position + 6] << 16; goto case 6;
109+
case 6: k2 ^= (uint)tail[position + 5] << 8; goto case 5;
110+
case 5: k2 ^= (uint)tail[position + 4] << 0; goto case 4;
111+
case 4: k1 ^= (uint)tail[position + 3] << 24; goto case 3;
112+
case 3: k1 ^= (uint)tail[position + 2] << 16; goto case 2;
113+
case 2: k1 ^= (uint)tail[position + 1] << 8; goto case 1;
114+
case 1: k1 ^= (uint)tail[position] << 0; break;
115+
}
116+
117+
H4 ^= (k4 * C4).RotateLeft(18) * C1;
118+
H3 ^= (k3 * C3).RotateLeft(17) * C4;
119+
H2 ^= (k2 * C2).RotateLeft(16) * C3;
120+
H1 ^= (k1 * C1).RotateLeft(15) * C2;
121+
}
122+
123+
protected override byte[] HashFinal()
124+
{
125+
uint len = (uint)Length;
126+
H1 ^= len; H2 ^= len; H3 ^= len; H4 ^= len;
127+
128+
H1 += (H2 + H3 + H4);
129+
H2 += H1; H3 += H1; H4 += H1;
130+
131+
H1 = H1.FMix();
132+
H2 = H2.FMix();
133+
H3 = H3.FMix();
134+
H4 = H4.FMix();
135+
136+
H1 += (H2 + H3 + H4);
137+
H2 += H1; H3 += H1; H4 += H1;
138+
139+
var result = new byte[16];
140+
Array.Copy(BitConverter.GetBytes(H1), 0, result, 0, 4);
141+
Array.Copy(BitConverter.GetBytes(H2), 0, result, 4, 4);
142+
Array.Copy(BitConverter.GetBytes(H3), 0, result, 8, 4);
143+
Array.Copy(BitConverter.GetBytes(H4), 0, result, 12, 4);
144+
145+
return result;
146+
}
147+
}
148+
}

0 commit comments

Comments
 (0)