11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2011 The Guava Authors 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in compliance with the License. You may obtain a copy of the License at 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software distributed under the License 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * or implied. See the License for the specific language governing permissions and limitations under 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the License. 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.hash; 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.base.Preconditions.checkArgument; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Preconditions; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.ByteBuffer; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.ByteOrder; 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.charset.Charset; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Skeleton implementation of {@link HashFunction}. Provides default implementations which 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * invokes the appropriate method on {@link #newHasher()}, then return the result of 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link Hasher#hash}. 291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Invocations of {@link #newHasher(int)} also delegate to {@linkplain #newHasher()}, ignoring 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the expected input size parameter. 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Kevin Bourrillion 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertabstract class AbstractStreamingHashFunction implements HashFunction { 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public HashCode hashString(CharSequence input) { 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return newHasher().putString(input).hash(); 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public HashCode hashString(CharSequence input, Charset charset) { 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return newHasher().putString(input, charset).hash(); 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public HashCode hashLong(long input) { 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return newHasher().putLong(input).hash(); 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public HashCode hashBytes(byte[] input) { 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return newHasher().putBytes(input).hash(); 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public HashCode hashBytes(byte[] input, int off, int len) { 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return newHasher().putBytes(input, off, len).hash(); 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public Hasher newHasher(int expectedInputSize) { 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(expectedInputSize >= 0); 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return newHasher(); 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A convenience base class for implementors of {@code Hasher}; handles accumulating data 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * until an entire "chunk" (of implementation-dependent length) is ready to be hashed. 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author kevinb@google.com (Kevin Bourrillion) 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author andreou@google.com (Dimitris Andreou) 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // TODO(kevinb): this class still needs some design-and-document-for-inheritance love 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected static abstract class AbstractStreamingHasher extends AbstractHasher { 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** Buffer via which we pass data to the hash algorithm (the implementor) */ 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final ByteBuffer buffer; 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** Number of bytes to be filled before process() invocation(s). */ 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final int bufferSize; 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** Number of bytes processed per process() invocation. */ 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final int chunkSize; 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Constructor for use by subclasses. This hasher instance will process chunks of the specified 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * size. 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param chunkSize the number of bytes available per {@link #process(ByteBuffer)} invocation; 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * must be at least 4 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected AbstractStreamingHasher(int chunkSize) { 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this(chunkSize, chunkSize); 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Constructor for use by subclasses. This hasher instance will process chunks of the specified 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * size, using an internal buffer of {@code bufferSize} size, which must be a multiple of 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code chunkSize}. 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param chunkSize the number of bytes available per {@link #process(ByteBuffer)} invocation; 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * must be at least 4 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param bufferSize the size of the internal buffer. Must be a multiple of chunkSize 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected AbstractStreamingHasher(int chunkSize, int bufferSize) { 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // TODO(kevinb): check more preconditions (as bufferSize >= chunkSize) if this is ever public 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkArgument(bufferSize % chunkSize == 0); 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // TODO(user): benchmark performance difference with longer buffer 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.buffer = ByteBuffer 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .allocate(bufferSize + 7) // always space for a single primitive 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .order(ByteOrder.LITTLE_ENDIAN); 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.bufferSize = bufferSize; 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.chunkSize = chunkSize; 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Processes the available bytes of the buffer (at most {@code chunk} bytes). 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected abstract void process(ByteBuffer bb); 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This is invoked for the last bytes of the input, which are not enough to 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * fill a whole chunk. The passed {@code ByteBuffer} is guaranteed to be 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * non-empty. 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This implementation simply pads with zeros and delegates to 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link #process(ByteBuffer)}. 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert protected void processRemaining(ByteBuffer bb) { 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bb.position(bb.limit()); // move at the end 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bb.limit(chunkSize + 7); // get ready to pad with longs 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert while (bb.position() < chunkSize) { 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bb.putLong(0); 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bb.limit(chunkSize); 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bb.flip(); 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert process(bb); 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Hasher putBytes(byte[] bytes) { 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return putBytes(bytes, 0, bytes.length); 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Hasher putBytes(byte[] bytes, int off, int len) { 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return putBytes(ByteBuffer.wrap(bytes, off, len).order(ByteOrder.LITTLE_ENDIAN)); 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Hasher putBytes(ByteBuffer readBuffer) { 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // If we have room for all of it, this is easy 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (readBuffer.remaining() <= buffer.remaining()) { 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.put(readBuffer); 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munchIfFull(); 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // First add just enough to fill buffer size, and munch that 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int bytesToCopy = bufferSize - buffer.position(); 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < bytesToCopy; i++) { 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.put(readBuffer.get()); 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munch(); // buffer becomes empty here, since chunkSize divides bufferSize 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Now process directly from the rest of the input buffer 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert while (readBuffer.remaining() >= chunkSize) { 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert process(readBuffer); 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Finally stick the remainder back in our usual buffer 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.put(readBuffer); 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Hasher putString(CharSequence charSequence) { 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < charSequence.length(); i++) { 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert putChar(charSequence.charAt(i)); 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Hasher putByte(byte b) { 1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.put(b); 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munchIfFull(); 1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Hasher putShort(short s) { 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.putShort(s); 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munchIfFull(); 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Hasher putChar(char c) { 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.putChar(c); 1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munchIfFull(); 1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Hasher putInt(int i) { 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.putInt(i); 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munchIfFull(); 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Hasher putLong(long l) { 2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.putLong(l); 2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munchIfFull(); 2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final <T> Hasher putObject(T instance, Funnel<? super T> funnel) { 2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert funnel.funnel(instance, this); 2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return this; 2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final HashCode hash() { 2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munch(); 2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.flip(); 2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (buffer.remaining() > 0) { 2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert processRemaining(buffer); 2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return makeHash(); 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert abstract HashCode makeHash(); 2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Process pent-up data in chunks 2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void munchIfFull() { 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (buffer.remaining() < 8) { 2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // buffer is full; not enough room for a primitive. We have at least one full chunk. 2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert munch(); 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void munch() { 2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.flip(); 2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert while (buffer.remaining() >= chunkSize) { 2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // we could limit the buffer to ensure process() does not read more than 2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // chunkSize number of bytes, but we trust the implementations 2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert process(buffer); 2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buffer.compact(); // preserve any remaining data that do not make a full chunk 2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 250