• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.hash;
16 
17 import static com.google.common.base.Preconditions.checkArgument;
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static com.google.common.base.Preconditions.checkState;
20 
21 import com.google.common.base.Preconditions;
22 import com.google.common.primitives.Ints;
23 import com.google.common.primitives.UnsignedInts;
24 import com.google.errorprone.annotations.CanIgnoreReturnValue;
25 import java.io.Serializable;
26 import javax.annotation.CheckForNull;
27 
28 /**
29  * An immutable hash code of arbitrary bit length.
30  *
31  * @author Dimitris Andreou
32  * @author Kurt Alfred Kluever
33  * @since 11.0
34  */
35 @ElementTypesAreNonnullByDefault
36 public abstract class HashCode {
HashCode()37   HashCode() {}
38 
39   /** Returns the number of bits in this hash code; a positive multiple of 8. */
bits()40   public abstract int bits();
41 
42   /**
43    * Returns the first four bytes of {@linkplain #asBytes() this hashcode's bytes}, converted to an
44    * {@code int} value in little-endian order.
45    *
46    * @throws IllegalStateException if {@code bits() < 32}
47    */
asInt()48   public abstract int asInt();
49 
50   /**
51    * Returns the first eight bytes of {@linkplain #asBytes() this hashcode's bytes}, converted to a
52    * {@code long} value in little-endian order.
53    *
54    * @throws IllegalStateException if {@code bits() < 64}
55    */
asLong()56   public abstract long asLong();
57 
58   /**
59    * If this hashcode has enough bits, returns {@code asLong()}, otherwise returns a {@code long}
60    * value with {@code asBytes()} as the least-significant bytes and {@code 0x00} as the remaining
61    * most-significant bytes.
62    *
63    * @since 14.0 (since 11.0 as {@code Hashing.padToLong(HashCode)})
64    */
padToLong()65   public abstract long padToLong();
66 
67   /**
68    * Returns the value of this hash code as a byte array. The caller may modify the byte array;
69    * changes to it will <i>not</i> be reflected in this {@code HashCode} object or any other arrays
70    * returned by this method.
71    */
72   // TODO(user): consider ByteString here, when that is available
asBytes()73   public abstract byte[] asBytes();
74 
75   /**
76    * Copies bytes from this hash code into {@code dest}.
77    *
78    * @param dest the byte array into which the hash code will be written
79    * @param offset the start offset in the data
80    * @param maxLength the maximum number of bytes to write
81    * @return the number of bytes written to {@code dest}
82    * @throws IndexOutOfBoundsException if there is not enough room in {@code dest}
83    */
84   @CanIgnoreReturnValue
writeBytesTo(byte[] dest, int offset, int maxLength)85   public int writeBytesTo(byte[] dest, int offset, int maxLength) {
86     maxLength = Ints.min(maxLength, bits() / 8);
87     Preconditions.checkPositionIndexes(offset, offset + maxLength, dest.length);
88     writeBytesToImpl(dest, offset, maxLength);
89     return maxLength;
90   }
91 
writeBytesToImpl(byte[] dest, int offset, int maxLength)92   abstract void writeBytesToImpl(byte[] dest, int offset, int maxLength);
93 
94   /**
95    * Returns a mutable view of the underlying bytes for the given {@code HashCode} if it is a
96    * byte-based hashcode. Otherwise it returns {@link HashCode#asBytes}. Do <i>not</i> mutate this
97    * array or else you will break the immutability contract of {@code HashCode}.
98    */
getBytesInternal()99   byte[] getBytesInternal() {
100     return asBytes();
101   }
102 
103   /**
104    * Returns whether this {@code HashCode} and that {@code HashCode} have the same value, given that
105    * they have the same number of bits.
106    */
equalsSameBits(HashCode that)107   abstract boolean equalsSameBits(HashCode that);
108 
109   /**
110    * Creates a 32-bit {@code HashCode} representation of the given int value. The underlying bytes
111    * are interpreted in little endian order.
112    *
113    * @since 15.0 (since 12.0 in HashCodes)
114    */
fromInt(int hash)115   public static HashCode fromInt(int hash) {
116     return new IntHashCode(hash);
117   }
118 
119   private static final class IntHashCode extends HashCode implements Serializable {
120     final int hash;
121 
IntHashCode(int hash)122     IntHashCode(int hash) {
123       this.hash = hash;
124     }
125 
126     @Override
bits()127     public int bits() {
128       return 32;
129     }
130 
131     @Override
asBytes()132     public byte[] asBytes() {
133       return new byte[] {(byte) hash, (byte) (hash >> 8), (byte) (hash >> 16), (byte) (hash >> 24)};
134     }
135 
136     @Override
asInt()137     public int asInt() {
138       return hash;
139     }
140 
141     @Override
asLong()142     public long asLong() {
143       throw new IllegalStateException("this HashCode only has 32 bits; cannot create a long");
144     }
145 
146     @Override
padToLong()147     public long padToLong() {
148       return UnsignedInts.toLong(hash);
149     }
150 
151     @Override
writeBytesToImpl(byte[] dest, int offset, int maxLength)152     void writeBytesToImpl(byte[] dest, int offset, int maxLength) {
153       for (int i = 0; i < maxLength; i++) {
154         dest[offset + i] = (byte) (hash >> (i * 8));
155       }
156     }
157 
158     @Override
equalsSameBits(HashCode that)159     boolean equalsSameBits(HashCode that) {
160       return hash == that.asInt();
161     }
162 
163     private static final long serialVersionUID = 0;
164   }
165 
166   /**
167    * Creates a 64-bit {@code HashCode} representation of the given long value. The underlying bytes
168    * are interpreted in little endian order.
169    *
170    * @since 15.0 (since 12.0 in HashCodes)
171    */
fromLong(long hash)172   public static HashCode fromLong(long hash) {
173     return new LongHashCode(hash);
174   }
175 
176   private static final class LongHashCode extends HashCode implements Serializable {
177     final long hash;
178 
LongHashCode(long hash)179     LongHashCode(long hash) {
180       this.hash = hash;
181     }
182 
183     @Override
bits()184     public int bits() {
185       return 64;
186     }
187 
188     @Override
asBytes()189     public byte[] asBytes() {
190       return new byte[] {
191         (byte) hash,
192         (byte) (hash >> 8),
193         (byte) (hash >> 16),
194         (byte) (hash >> 24),
195         (byte) (hash >> 32),
196         (byte) (hash >> 40),
197         (byte) (hash >> 48),
198         (byte) (hash >> 56)
199       };
200     }
201 
202     @Override
asInt()203     public int asInt() {
204       return (int) hash;
205     }
206 
207     @Override
asLong()208     public long asLong() {
209       return hash;
210     }
211 
212     @Override
padToLong()213     public long padToLong() {
214       return hash;
215     }
216 
217     @Override
writeBytesToImpl(byte[] dest, int offset, int maxLength)218     void writeBytesToImpl(byte[] dest, int offset, int maxLength) {
219       for (int i = 0; i < maxLength; i++) {
220         dest[offset + i] = (byte) (hash >> (i * 8));
221       }
222     }
223 
224     @Override
equalsSameBits(HashCode that)225     boolean equalsSameBits(HashCode that) {
226       return hash == that.asLong();
227     }
228 
229     private static final long serialVersionUID = 0;
230   }
231 
232   /**
233    * Creates a {@code HashCode} from a byte array. The array is defensively copied to preserve the
234    * immutability contract of {@code HashCode}. The array cannot be empty.
235    *
236    * @since 15.0 (since 12.0 in HashCodes)
237    */
fromBytes(byte[] bytes)238   public static HashCode fromBytes(byte[] bytes) {
239     checkArgument(bytes.length >= 1, "A HashCode must contain at least 1 byte.");
240     return fromBytesNoCopy(bytes.clone());
241   }
242 
243   /**
244    * Creates a {@code HashCode} from a byte array. The array is <i>not</i> copied defensively, so it
245    * must be handed-off so as to preserve the immutability contract of {@code HashCode}.
246    */
fromBytesNoCopy(byte[] bytes)247   static HashCode fromBytesNoCopy(byte[] bytes) {
248     return new BytesHashCode(bytes);
249   }
250 
251   private static final class BytesHashCode extends HashCode implements Serializable {
252     final byte[] bytes;
253 
BytesHashCode(byte[] bytes)254     BytesHashCode(byte[] bytes) {
255       this.bytes = checkNotNull(bytes);
256     }
257 
258     @Override
bits()259     public int bits() {
260       return bytes.length * 8;
261     }
262 
263     @Override
asBytes()264     public byte[] asBytes() {
265       return bytes.clone();
266     }
267 
268     @Override
asInt()269     public int asInt() {
270       checkState(
271           bytes.length >= 4,
272           "HashCode#asInt() requires >= 4 bytes (it only has %s bytes).",
273           bytes.length);
274       return (bytes[0] & 0xFF)
275           | ((bytes[1] & 0xFF) << 8)
276           | ((bytes[2] & 0xFF) << 16)
277           | ((bytes[3] & 0xFF) << 24);
278     }
279 
280     @Override
asLong()281     public long asLong() {
282       checkState(
283           bytes.length >= 8,
284           "HashCode#asLong() requires >= 8 bytes (it only has %s bytes).",
285           bytes.length);
286       return padToLong();
287     }
288 
289     @Override
padToLong()290     public long padToLong() {
291       long retVal = (bytes[0] & 0xFF);
292       for (int i = 1; i < Math.min(bytes.length, 8); i++) {
293         retVal |= (bytes[i] & 0xFFL) << (i * 8);
294       }
295       return retVal;
296     }
297 
298     @Override
writeBytesToImpl(byte[] dest, int offset, int maxLength)299     void writeBytesToImpl(byte[] dest, int offset, int maxLength) {
300       System.arraycopy(bytes, 0, dest, offset, maxLength);
301     }
302 
303     @Override
getBytesInternal()304     byte[] getBytesInternal() {
305       return bytes;
306     }
307 
308     @Override
equalsSameBits(HashCode that)309     boolean equalsSameBits(HashCode that) {
310       // We don't use MessageDigest.isEqual() here because its contract does not guarantee
311       // constant-time evaluation (no short-circuiting).
312       if (this.bytes.length != that.getBytesInternal().length) {
313         return false;
314       }
315 
316       boolean areEqual = true;
317       for (int i = 0; i < this.bytes.length; i++) {
318         areEqual &= (this.bytes[i] == that.getBytesInternal()[i]);
319       }
320       return areEqual;
321     }
322 
323     private static final long serialVersionUID = 0;
324   }
325 
326   /**
327    * Creates a {@code HashCode} from a hexadecimal ({@code base 16}) encoded string. The string must
328    * be at least 2 characters long, and contain only valid, lower-cased hexadecimal characters.
329    *
330    * <p>This method accepts the exact format generated by {@link #toString}. If you require more
331    * lenient {@code base 16} decoding, please use {@link com.google.common.io.BaseEncoding#decode}
332    * (and pass the result to {@link #fromBytes}).
333    *
334    * @since 15.0
335    */
fromString(String string)336   public static HashCode fromString(String string) {
337     checkArgument(
338         string.length() >= 2, "input string (%s) must have at least 2 characters", string);
339     checkArgument(
340         string.length() % 2 == 0,
341         "input string (%s) must have an even number of characters",
342         string);
343 
344     byte[] bytes = new byte[string.length() / 2];
345     for (int i = 0; i < string.length(); i += 2) {
346       int ch1 = decode(string.charAt(i)) << 4;
347       int ch2 = decode(string.charAt(i + 1));
348       bytes[i / 2] = (byte) (ch1 + ch2);
349     }
350     return fromBytesNoCopy(bytes);
351   }
352 
decode(char ch)353   private static int decode(char ch) {
354     if (ch >= '0' && ch <= '9') {
355       return ch - '0';
356     }
357     if (ch >= 'a' && ch <= 'f') {
358       return ch - 'a' + 10;
359     }
360     throw new IllegalArgumentException("Illegal hexadecimal character: " + ch);
361   }
362 
363   /**
364    * Returns {@code true} if {@code object} is a {@link HashCode} instance with the identical byte
365    * representation to this hash code.
366    *
367    * <p><b>Security note:</b> this method uses a constant-time (not short-circuiting) implementation
368    * to protect against <a href="http://en.wikipedia.org/wiki/Timing_attack">timing attacks</a>.
369    */
370   @Override
equals(@heckForNull Object object)371   public final boolean equals(@CheckForNull Object object) {
372     if (object instanceof HashCode) {
373       HashCode that = (HashCode) object;
374       return bits() == that.bits() && equalsSameBits(that);
375     }
376     return false;
377   }
378 
379   /**
380    * Returns a "Java hash code" for this {@code HashCode} instance; this is well-defined (so, for
381    * example, you can safely put {@code HashCode} instances into a {@code HashSet}) but is otherwise
382    * probably not what you want to use.
383    */
384   @Override
hashCode()385   public final int hashCode() {
386     // If we have at least 4 bytes (32 bits), just take the first 4 bytes. Since this is
387     // already a (presumably) high-quality hash code, any four bytes of it will do.
388     if (bits() >= 32) {
389       return asInt();
390     }
391     // If we have less than 4 bytes, use them all.
392     byte[] bytes = getBytesInternal();
393     int val = (bytes[0] & 0xFF);
394     for (int i = 1; i < bytes.length; i++) {
395       val |= ((bytes[i] & 0xFF) << (i * 8));
396     }
397     return val;
398   }
399 
400   /**
401    * Returns a string containing each byte of {@link #asBytes}, in order, as a two-digit unsigned
402    * hexadecimal number in lower case.
403    *
404    * <p>Note that if the output is considered to be a single hexadecimal number, whether this string
405    * is big-endian or little-endian depends on the byte order of {@link #asBytes}. This may be
406    * surprising for implementations of {@code HashCode} that represent the number in big-endian
407    * since everything else in the hashing API uniformly treats multibyte values as little-endian.
408    *
409    * <p>To create a {@code HashCode} from its string representation, see {@link #fromString}.
410    */
411   @Override
toString()412   public final String toString() {
413     byte[] bytes = getBytesInternal();
414     StringBuilder sb = new StringBuilder(2 * bytes.length);
415     for (byte b : bytes) {
416       sb.append(hexDigits[(b >> 4) & 0xf]).append(hexDigits[b & 0xf]);
417     }
418     return sb.toString();
419   }
420 
421   private static final char[] hexDigits = "0123456789abcdef".toCharArray();
422 }
423