diff --git a/README.txt b/README.txt index 2aeba02..5e56833 100644 --- a/README.txt +++ b/README.txt @@ -6,5 +6,7 @@ As such, unless otherwise noted, this code has been authored by Yonik Seeley and placed into the public domain to allow people to use or license as they see fit. -util/hash/MurmurHash3: a fast, high quality hash function. +util/hash/MurmurHash3: + A fast, high quality hash function. This version can also calculate + the hash of the UTF-8 encoding of a String without converting to a UTF-8 byte[]. diff --git a/src/util/hash/MurmurHash3.java b/src/util/hash/MurmurHash3.java index 4e95e77..d0a9e43 100644 --- a/src/util/hash/MurmurHash3.java +++ b/src/util/hash/MurmurHash3.java @@ -1,24 +1,63 @@ package util.hash; /** - * The MurmurHash3 algorithm was created by Austin Appleby. This java port was authored by - * Yonik Seeley and is placed into the public domain. The author hereby disclaims copyright - * to this source code. + * The MurmurHash3 algorithm was created by Austin Appleby and placed in the public domain. + * This java port was authored by Yonik Seeley and also placed into the public domain. + * The author hereby disclaims copyright to this source code. *
* This produces exactly the same hash values as the final C++ * version of MurmurHash3 and is thus suitable for producing the same hash values across * platforms. *
* The 32 bit x86 version of this hash should be the fastest variant for relatively short keys like ids. + * murmurhash3_x64_128 is a good choice for longer strings or if you need more than 32 bits of hash. *
* Note - The x86 and x64 versions do _not_ produce the same results, as the * algorithms are optimized for their respective platforms. *
* See http://github.com/yonik/java_util for future updates to this file.
*/
-public class MurmurHash3 {
+public final class MurmurHash3 {
+
+ /** 128 bits of state */
+ public static final class LongPair {
+ public long val1;
+ public long val2;
+ }
+
+ public static final int fmix32(int h) {
+ h ^= h >>> 16;
+ h *= 0x85ebca6b;
+ h ^= h >>> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >>> 16;
+ return h;
+ }
+
+ public static final long fmix64(long k) {
+ k ^= k >>> 33;
+ k *= 0xff51afd7ed558ccdL;
+ k ^= k >>> 33;
+ k *= 0xc4ceb9fe1a85ec53L;
+ k ^= k >>> 33;
+ return k;
+ }
+
+ /** Gets a long from a byte buffer in little endian byte order. */
+ public static final long getLongLittleEndian(byte[] buf, int offset) {
+ return ((long)buf[offset+7] << 56) // no mask needed
+ | ((buf[offset+6] & 0xffL) << 48)
+ | ((buf[offset+5] & 0xffL) << 40)
+ | ((buf[offset+4] & 0xffL) << 32)
+ | ((buf[offset+3] & 0xffL) << 24)
+ | ((buf[offset+2] & 0xffL) << 16)
+ | ((buf[offset+1] & 0xffL) << 8)
+ | ((buf[offset ] & 0xffL)); // no shift needed
+ }
+
/** Returns the MurmurHash3_x86_32 hash. */
+ @SuppressWarnings("fallthrough")
public static int murmurhash3_x86_32(byte[] data, int offset, int len, int seed) {
final int c1 = 0xcc9e2d51;
@@ -196,4 +235,67 @@ else if (code < 0xD800 || code > 0xDFFF || pos>=end) {
return h1;
}
+
+ /** Returns the MurmurHash3_x64_128 hash, placing the result in "out". */
+ @SuppressWarnings("fallthrough")
+ public static void murmurhash3_x64_128(byte[] key, int offset, int len, int seed, LongPair out) {
+ // The original algorithm does have a 32 bit unsigned seed.
+ // We have to mask to match the behavior of the unsigned types and prevent sign extension.
+ long h1 = seed & 0x00000000FFFFFFFFL;
+ long h2 = seed & 0x00000000FFFFFFFFL;
+
+ final long c1 = 0x87c37b91114253d5L;
+ final long c2 = 0x4cf5ad432745937fL;
+
+ int roundedEnd = offset + (len & 0xFFFFFFF0); // round down to 16 byte block
+ for (int i=offset; i