aboutsummaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/hash/Murmur3_32HashFunction.java
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/hash/Murmur3_32HashFunction.java')
-rw-r--r--guava/src/com/google/common/hash/Murmur3_32HashFunction.java159
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;
}