Rephrase Fingerprint in terms of guava HashFunction.

This minimizes API divergence and allows us to make use of performance enhancements in guava, such as https://github.com/google/guava/issues/1197.

--
MOS_MIGRATED_REVID=127108107
diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/Digest.java b/src/main/java/com/google/devtools/build/lib/actions/cache/Digest.java
index c5653ac..0698919 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/cache/Digest.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/cache/Digest.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.actions.cache;
 
+import com.google.common.hash.HashCode;
 import com.google.devtools.build.lib.util.Fingerprint;
 import com.google.devtools.build.lib.util.VarInt;
 
@@ -107,7 +108,7 @@
 
   @Override
   public String toString() {
-    return Fingerprint.hexDigest(digest);
+    return HashCode.fromBytes(digest).toString();
   }
 
   private static byte[] getDigest(Fingerprint fp, String execPath, Metadata md) {
diff --git a/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java b/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java
index a461041..75737c3 100644
--- a/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java
+++ b/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java
@@ -17,11 +17,12 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.common.collect.Iterables;
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.util.Map;
 import java.util.UUID;
 
@@ -34,18 +35,14 @@
  */
 public final class Fingerprint {
 
-  private final MessageDigest md;
+  private Hasher hasher;
+  private static final HashFunction MD5_HASH_FUNCTION = Hashing.md5();
 
   /**
-   * Creates and initializes a new MD5 object; if this fails, Java must be
-   * installed incorrectly.
+   * Creates and initializes a new Hasher.
    */
   public Fingerprint() {
-    try {
-      md = MessageDigest.getInstance("md5");
-    } catch (NoSuchAlgorithmException e) {
-      throw new IllegalStateException("MD5 not available", e);
-    }
+    reset();
   }
 
   /**
@@ -57,7 +54,9 @@
    * @see java.security.MessageDigest#digest()
    */
   public byte[] digestAndReset() {
-    return md.digest();
+    byte[] bytes = hasher.hash().asBytes();
+    reset();
+    return bytes;
   }
 
   /**
@@ -68,23 +67,9 @@
    * @return the MD5 digest as a 32-character string of hexadecimal digits
    */
   public String hexDigestAndReset() {
-    return hexDigest(digestAndReset());
-  }
-
-  /**
-   * Returns a string representation of an MD5 digest.
-   *
-   * @param digest the MD5 digest, perhaps from a previous call to digest
-   * @return the digest as a 32-character string of hexadecimal digits
-   */
-  public static String hexDigest(byte[] digest) {
-    StringBuilder b = new StringBuilder(32);
-    for (int i = 0; i < digest.length; i++) {
-      int n = digest[i];
-      b.append("0123456789abcdef".charAt((n >> 4) & 0xF));
-      b.append("0123456789abcdef".charAt(n & 0xF));
-    }
-    return b.toString();
+    String hexDigest = hasher.hash().toString();
+    reset();
+    return hexDigest;
   }
 
   /**
@@ -94,7 +79,7 @@
    * @see java.security.MessageDigest#update(byte[])
    */
   public Fingerprint addBytes(byte[] input) {
-    md.update(input);
+    hasher.putBytes(input);
     return this;
   }
 
@@ -107,7 +92,7 @@
    * @see java.security.MessageDigest#update(byte[], int, int)
    */
   public Fingerprint addBytes(byte[] input, int offset, int len) {
-    md.update(input, offset, len);
+    hasher.putBytes(input, offset, len);
     return this;
   }
 
@@ -133,13 +118,7 @@
    * @param input the integer with which to update the digest
    */
   public Fingerprint addInt(int input) {
-    md.update(new byte[] {
-        (byte) input,
-        (byte) (input >>  8),
-        (byte) (input >> 16),
-        (byte) (input >> 24),
-    });
-
+    hasher.putInt(input);
     return this;
   }
 
@@ -149,17 +128,7 @@
    * @param input the long with which to update the digest
    */
   public Fingerprint addLong(long input) {
-    md.update(new byte[]{
-        (byte) input,
-        (byte) (input >> 8),
-        (byte) (input >> 16),
-        (byte) (input >> 24),
-        (byte) (input >> 32),
-        (byte) (input >> 40),
-        (byte) (input >> 48),
-        (byte) (input >> 56),
-    });
-
+    hasher.putLong(input);
     return this;
   }
 
@@ -199,7 +168,8 @@
   public Fingerprint addString(String input) {
     byte[] bytes = input.getBytes(UTF_8);
     addInt(bytes.length);
-    md.update(bytes);
+    // Note that Hasher#putString() would not include the length of {@code input}.
+    hasher.putBytes(bytes);
     return this;
   }
 
@@ -231,7 +201,7 @@
     for (int i = 0; i < input.length(); i++) {
       bytes[i] = (byte) input.charAt(i);
     }
-    md.update(bytes);
+    hasher.putBytes(bytes);
     return this;
   }
 
@@ -321,7 +291,7 @@
    * Reset the Fingerprint for additional use as though previous digesting had not been done.
    */
   public void reset() {
-    md.reset();
+    hasher = MD5_HASH_FUNCTION.newHasher();
   }
 
   // -------- Convenience methods ----------------------------
@@ -333,8 +303,6 @@
    * @param input the String from which to compute the digest
    */
   public static String md5Digest(String input) {
-    Fingerprint f = new Fingerprint();
-    f.addBytes(input.getBytes(UTF_8));
-    return f.hexDigestAndReset();
+    return MD5_HASH_FUNCTION.hashString(input, UTF_8).toString();
   }
 }