1// Copyright 2011 Google Inc. All Rights Reserved. 2 3package com.google.common.hash; 4 5import com.google.common.base.Preconditions; 6import com.google.common.base.Throwables; 7 8import java.io.ByteArrayOutputStream; 9import java.io.IOException; 10 11/** 12 * Skeleton implementation of {@link HashFunction}, appropriate for non-streaming algorithms. 13 * All the hash computation done using {@linkplain #newHasher()} are delegated to the {@linkplain 14 * #hashBytes(byte[], int, int)} method. 15 * 16 * @author andreou@google.com (Dimitris Andreou) 17 */ 18abstract class AbstractNonStreamingHashFunction implements HashFunction { 19 @Override 20 public Hasher newHasher() { 21 return new BufferingHasher(32); 22 } 23 24 @Override 25 public Hasher newHasher(int expectedInputSize) { 26 Preconditions.checkArgument(expectedInputSize >= 0); 27 return new BufferingHasher(expectedInputSize); 28 } 29 30 /** 31 * In-memory stream-based implementation of Hasher. 32 */ 33 private final class BufferingHasher extends AbstractHasher { 34 final ExposedByteArrayOutputStream stream; 35 static final int BOTTOM_BYTE = 0xFF; 36 37 BufferingHasher(int expectedInputSize) { 38 this.stream = new ExposedByteArrayOutputStream(expectedInputSize); 39 } 40 41 @Override 42 public Hasher putByte(byte b) { 43 stream.write(b); 44 return this; 45 } 46 47 @Override 48 public Hasher putBytes(byte[] bytes) { 49 try { 50 stream.write(bytes); 51 } catch (IOException e) { 52 throw Throwables.propagate(e); 53 } 54 return this; 55 } 56 57 @Override 58 public Hasher putBytes(byte[] bytes, int off, int len) { 59 stream.write(bytes, off, len); 60 return this; 61 } 62 63 @Override 64 public Hasher putShort(short s) { 65 stream.write(s & BOTTOM_BYTE); 66 stream.write((s >>> 8) & BOTTOM_BYTE); 67 return this; 68 } 69 70 @Override 71 public Hasher putInt(int i) { 72 stream.write(i & BOTTOM_BYTE); 73 stream.write((i >>> 8) & BOTTOM_BYTE); 74 stream.write((i >>> 16) & BOTTOM_BYTE); 75 stream.write((i >>> 24) & BOTTOM_BYTE); 76 return this; 77 } 78 79 @Override 80 public Hasher putLong(long l) { 81 for (int i = 0; i < 64; i += 8) { 82 stream.write((byte) ((l >>> i) & BOTTOM_BYTE)); 83 } 84 return this; 85 } 86 87 @Override 88 public Hasher putChar(char c) { 89 stream.write(c & BOTTOM_BYTE); 90 stream.write((c >>> 8) & BOTTOM_BYTE); 91 return this; 92 } 93 94 @Override 95 public <T> Hasher putObject(T instance, Funnel<? super T> funnel) { 96 funnel.funnel(instance, this); 97 return this; 98 } 99 100 @Override 101 public HashCode hash() { 102 return hashBytes(stream.byteArray(), 0, stream.length()); 103 } 104 } 105 106 // Just to access the byte[] without introducing an unnecessary copy 107 private static final class ExposedByteArrayOutputStream extends ByteArrayOutputStream { 108 ExposedByteArrayOutputStream(int expectedInputSize) { 109 super(expectedInputSize); 110 } 111 byte[] byteArray() { 112 return buf; 113 } 114 int length() { 115 return count; 116 } 117 } 118} 119