diff options
Diffstat (limited to 'guava/src/com/google/common/hash/Murmur3_32HashFunction.java')
-rw-r--r-- | guava/src/com/google/common/hash/Murmur3_32HashFunction.java | 159 |
1 files changed, 48 insertions, 111 deletions
diff --git a/guava/src/com/google/common/hash/Murmur3_32HashFunction.java b/guava/src/com/google/common/hash/Murmur3_32HashFunction.java index c6637de..5c03b92 100644 --- a/guava/src/com/google/common/hash/Murmur3_32HashFunction.java +++ b/guava/src/com/google/common/hash/Murmur3_32HashFunction.java @@ -12,42 +12,23 @@ * the License. */ -/* - * MurmurHash3 was written by Austin Appleby, and is placed in the public - * domain. The author hereby disclaims copyright to this source code. - */ - -/* - * Source: - * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp - * (Modified to adapt to Guava coding conventions and to use the HashFunction interface) - */ - package com.google.common.hash; import static com.google.common.primitives.UnsignedBytes.toInt; -import com.google.common.primitives.Chars; -import com.google.common.primitives.Ints; -import com.google.common.primitives.Longs; - import java.io.Serializable; import java.nio.ByteBuffer; /** * See http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp * MurmurHash3_x86_32 - * - * @author Austin Appleby - * @author Dimitris Andreou - * @author Kurt Alfred Kluever + * + * @author aappleby@google.com (Austin Appleby) + * @author andreou@google.com (Dimitris Andreou) */ final class Murmur3_32HashFunction extends AbstractStreamingHashFunction implements Serializable { - private static final int C1 = 0xcc9e2d51; - private static final int C2 = 0x1b873593; - private final int seed; - + Murmur3_32HashFunction(int seed) { this.seed = seed; } @@ -60,107 +41,63 @@ final class Murmur3_32HashFunction extends AbstractStreamingHashFunction impleme return new Murmur3_32Hasher(seed); } - @Override - public String toString() { - return "Hashing.murmur3_32(" + seed + ")"; - } - - @Override public HashCode hashInt(int input) { - int k1 = mixK1(input); - int h1 = mixH1(seed, k1); - - return fmix(h1, Ints.BYTES); - } - - @Override public HashCode hashLong(long input) { - int low = (int) input; - int high = (int) (input >>> 32); - - int k1 = mixK1(low); - int h1 = mixH1(seed, k1); - - k1 = mixK1(high); - h1 = mixH1(h1, k1); - - return fmix(h1, Longs.BYTES); - } - - // TODO(user): Maybe implement #hashBytes instead? - @Override public HashCode hashString(CharSequence input) { - int h1 = seed; - - // step through the CharSequence 2 chars at a time - for (int i = 1; i < input.length(); i += 2) { - int k1 = input.charAt(i - 1) | (input.charAt(i) << 16); - k1 = mixK1(k1); - h1 = mixH1(h1, k1); - } - - // deal with any remaining characters - if ((input.length() & 1) == 1) { - int k1 = input.charAt(input.length() - 1); - k1 = mixK1(k1); - h1 ^= k1; - } - - return fmix(h1, Chars.BYTES * input.length()); - } - - private static int mixK1(int k1) { - k1 *= C1; - k1 = Integer.rotateLeft(k1, 15); - k1 *= C2; - return k1; - } - - private static int mixH1(int h1, int k1) { - h1 ^= k1; - h1 = Integer.rotateLeft(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - return h1; - } - - // Finalization mix - force all bits of a hash block to avalanche - private static HashCode fmix(int h1, int length) { - h1 ^= length; - h1 ^= h1 >>> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >>> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >>> 16; - return HashCodes.fromInt(h1); - } - private static final class Murmur3_32Hasher extends AbstractStreamingHasher { - private static final int CHUNK_SIZE = 4; - private int h1; - private int length; + int h1; + int c1 = 0xcc9e2d51; + int c2 = 0x1b873593; + int len; Murmur3_32Hasher(int seed) { - super(CHUNK_SIZE); - this.h1 = seed; - this.length = 0; + super(4); + h1 = seed; } @Override protected void process(ByteBuffer bb) { - int k1 = Murmur3_32HashFunction.mixK1(bb.getInt()); - h1 = Murmur3_32HashFunction.mixH1(h1, k1); - length += CHUNK_SIZE; + int k1 = bb.getInt(); + len += 4; + + k1 *= c1; + k1 = Integer.rotateLeft(k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = Integer.rotateLeft(h1, 13); + h1 = h1 * 5 + 0xe6546b64; } - + @Override protected void processRemaining(ByteBuffer bb) { - length += bb.remaining(); + len += bb.remaining(); int k1 = 0; - for (int i = 0; bb.hasRemaining(); i += 8) { - k1 ^= toInt(bb.get()) << i; + switch (bb.remaining()) { + case 3: + k1 ^= toInt(bb.get(2)) << 16; + // fall through + case 2: + k1 ^= toInt(bb.get(1)) << 8; + // fall through + case 1: + k1 ^= toInt(bb.get(0)); + // fall through + default: + k1 *= c1; + k1 = Integer.rotateLeft(k1, 15); + k1 *= c2; + h1 ^= k1; } - h1 ^= Murmur3_32HashFunction.mixK1(k1); } - + @Override public HashCode makeHash() { - return Murmur3_32HashFunction.fmix(h1, length); + h1 ^= len; + + h1 ^= h1 >>> 16; + h1 *= 0x85ebca6b; + h1 ^= h1 >>> 13; + h1 *= 0xc2b2ae35; + h1 ^= h1 >>> 16; + + return HashCodes.fromInt(h1); } } - + private static final long serialVersionUID = 0L; } |