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