aboutsummaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/hash/MessageDigestHashFunction.java
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/hash/MessageDigestHashFunction.java')
-rw-r--r--guava/src/com/google/common/hash/MessageDigestHashFunction.java193
1 files changed, 104 insertions, 89 deletions
diff --git a/guava/src/com/google/common/hash/MessageDigestHashFunction.java b/guava/src/com/google/common/hash/MessageDigestHashFunction.java
index 029a494..03c6471 100644
--- a/guava/src/com/google/common/hash/MessageDigestHashFunction.java
+++ b/guava/src/com/google/common/hash/MessageDigestHashFunction.java
@@ -14,60 +14,37 @@
package com.google.common.hash;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Preconditions.checkPositionIndexes;
-import java.io.Serializable;
+import com.google.common.primitives.Chars;
+import com.google.common.primitives.Ints;
+import com.google.common.primitives.Longs;
+import com.google.common.primitives.Shorts;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
/**
- * {@link HashFunction} adapter for {@link MessageDigest} instances.
+ * {@link HashFunction} adapter for {@link MessageDigest}s.
*
- * @author Kevin Bourrillion
- * @author Dimitris Andreou
+ * @author kevinb@google.com (Kevin Bourrillion)
+ * @author andreou@google.com (Dimitris Andreou)
*/
-final class MessageDigestHashFunction extends AbstractStreamingHashFunction
- implements Serializable {
- private final MessageDigest prototype;
- private final int bytes;
- private final boolean supportsClone;
- private final String toString;
-
- MessageDigestHashFunction(String algorithmName, String toString) {
- this.prototype = getMessageDigest(algorithmName);
- this.bytes = prototype.getDigestLength();
- this.toString = checkNotNull(toString);
- this.supportsClone = supportsClone();
- }
-
- MessageDigestHashFunction(String algorithmName, int bytes, String toString) {
- this.toString = checkNotNull(toString);
- this.prototype = getMessageDigest(algorithmName);
- int maxLength = prototype.getDigestLength();
- checkArgument(bytes >= 4 && bytes <= maxLength,
- "bytes (%s) must be >= 4 and < %s", bytes, maxLength);
- this.bytes = bytes;
- this.supportsClone = supportsClone();
- }
+final class MessageDigestHashFunction extends AbstractStreamingHashFunction {
+ private final String algorithmName;
+ private final int bits;
- private boolean supportsClone() {
- try {
- prototype.clone();
- return true;
- } catch (CloneNotSupportedException e) {
- return false;
- }
+ MessageDigestHashFunction(String algorithmName) {
+ this.algorithmName = algorithmName;
+ this.bits = getMessageDigest(algorithmName).getDigestLength() * 8;
}
- @Override public int bits() {
- return bytes * Byte.SIZE;
- }
-
- @Override public String toString() {
- return toString;
+ public int bits() {
+ return bits;
}
private static MessageDigest getMessageDigest(String algorithmName) {
@@ -79,80 +56,118 @@ final class MessageDigestHashFunction extends AbstractStreamingHashFunction
}
@Override public Hasher newHasher() {
- if (supportsClone) {
- try {
- return new MessageDigestHasher((MessageDigest) prototype.clone(), bytes);
- } catch (CloneNotSupportedException e) {
- // falls through
- }
- }
- return new MessageDigestHasher(getMessageDigest(prototype.getAlgorithm()), bytes);
+ return new MessageDigestHasher(getMessageDigest(algorithmName));
}
- private static final class SerializedForm implements Serializable {
- private final String algorithmName;
- private final int bytes;
- private final String toString;
+ private static class MessageDigestHasher implements Hasher {
+ private final MessageDigest digest;
+ private final ByteBuffer scratch; // lazy convenience
+ private boolean done;
- private SerializedForm(String algorithmName, int bytes, String toString) {
- this.algorithmName = algorithmName;
- this.bytes = bytes;
- this.toString = toString;
+ private MessageDigestHasher(MessageDigest digest) {
+ this.digest = digest;
+ this.scratch = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
}
- private Object readResolve() {
- return new MessageDigestHashFunction(algorithmName, bytes, toString);
+ @Override public Hasher putByte(byte b) {
+ checkNotDone();
+ digest.update(b);
+ return this;
}
- private static final long serialVersionUID = 0;
- }
+ @Override public Hasher putBytes(byte[] bytes) {
+ checkNotDone();
+ digest.update(bytes);
+ return this;
+ }
- Object writeReplace() {
- return new SerializedForm(prototype.getAlgorithm(), bytes, toString);
- }
+ @Override public Hasher putBytes(byte[] bytes, int off, int len) {
+ checkNotDone();
+ checkPositionIndexes(off, off + len, bytes.length);
+ digest.update(bytes, off, len);
+ return this;
+ }
- /**
- * Hasher that updates a message digest.
- */
- private static final class MessageDigestHasher extends AbstractByteHasher {
+ @Override public Hasher putShort(short s) {
+ checkNotDone();
+ scratch.putShort(s);
+ digest.update(scratch.array(), 0, Shorts.BYTES);
+ scratch.clear();
+ return this;
+ }
- private final MessageDigest digest;
- private final int bytes;
- private boolean done;
+ @Override public Hasher putInt(int i) {
+ checkNotDone();
+ scratch.putInt(i);
+ digest.update(scratch.array(), 0, Ints.BYTES);
+ scratch.clear();
+ return this;
+ }
- private MessageDigestHasher(MessageDigest digest, int bytes) {
- this.digest = digest;
- this.bytes = bytes;
+ @Override public Hasher putLong(long l) {
+ checkNotDone();
+ scratch.putLong(l);
+ digest.update(scratch.array(), 0, Longs.BYTES);
+ scratch.clear();
+ return this;
}
- @Override
- protected void update(byte b) {
+ @Override public Hasher putFloat(float f) {
checkNotDone();
- digest.update(b);
+ scratch.putFloat(f);
+ digest.update(scratch.array(), 0, 4);
+ scratch.clear();
+ return this;
}
- @Override
- protected void update(byte[] b) {
+ @Override public Hasher putDouble(double d) {
checkNotDone();
- digest.update(b);
+ scratch.putDouble(d);
+ digest.update(scratch.array(), 0, 8);
+ scratch.clear();
+ return this;
+ }
+
+ @Override public Hasher putBoolean(boolean b) {
+ return putByte(b ? (byte) 1 : (byte) 0);
+ }
+
+ @Override public Hasher putChar(char c) {
+ checkNotDone();
+ scratch.putChar(c);
+ digest.update(scratch.array(), 0, Chars.BYTES);
+ scratch.clear();
+ return this;
+ }
+
+ @Override public Hasher putString(CharSequence charSequence) {
+ for (int i = 0; i < charSequence.length(); i++) {
+ putChar(charSequence.charAt(i));
+ }
+ return this;
+ }
+
+ @Override public Hasher putString(CharSequence charSequence, Charset charset) {
+ try {
+ return putBytes(charSequence.toString().getBytes(charset.name()));
+ } catch (java.io.UnsupportedEncodingException impossible) {
+ throw new AssertionError(impossible);
+ }
}
- @Override
- protected void update(byte[] b, int off, int len) {
+ @Override public <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
checkNotDone();
- digest.update(b, off, len);
+ funnel.funnel(instance, this);
+ return this;
}
private void checkNotDone() {
checkState(!done, "Cannot use Hasher after calling #hash() on it");
}
- @Override
public HashCode hash() {
done = true;
- return (bytes == digest.getDigestLength())
- ? HashCodes.fromBytesNoCopy(digest.digest())
- : HashCodes.fromBytesNoCopy(Arrays.copyOf(digest.digest(), bytes));
+ return HashCodes.fromBytes(digest.digest());
}
}
}