Home | History | Annotate | Download | only in hash
      1 /*
      2  * Copyright (C) 2012 The Guava Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.hash;
     18 
     19 import static com.google.common.base.Preconditions.checkNotNull;
     20 import static com.google.common.base.Preconditions.checkPositionIndexes;
     21 
     22 import com.google.common.primitives.Chars;
     23 import com.google.common.primitives.Ints;
     24 import com.google.common.primitives.Longs;
     25 import com.google.common.primitives.Shorts;
     26 
     27 import java.nio.ByteBuffer;
     28 import java.nio.ByteOrder;
     29 
     30 /**
     31  * Abstract {@link Hasher} that handles converting primitives to bytes using a scratch {@code
     32  * ByteBuffer} and streams all bytes to a sink to compute the hash.
     33  *
     34  * @author Colin Decker
     35  */
     36 abstract class AbstractByteHasher extends AbstractHasher {
     37 
     38   private final ByteBuffer scratch = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
     39 
     40   /**
     41    * Updates this hasher with the given byte.
     42    */
     43   protected abstract void update(byte b);
     44 
     45   /**
     46    * Updates this hasher with the given bytes.
     47    */
     48   protected void update(byte[] b) {
     49     update(b, 0, b.length);
     50   }
     51 
     52   /**
     53    * Updates this hasher with {@code len} bytes starting at {@code off} in the given buffer.
     54    */
     55   protected void update(byte[] b, int off, int len) {
     56     for (int i = off; i < off + len; i++) {
     57       update(b[i]);
     58     }
     59   }
     60 
     61   @Override
     62   public Hasher putByte(byte b) {
     63     update(b);
     64     return this;
     65   }
     66 
     67   @Override
     68   public Hasher putBytes(byte[] bytes) {
     69     checkNotNull(bytes);
     70     update(bytes);
     71     return this;
     72   }
     73 
     74   @Override
     75   public Hasher putBytes(byte[] bytes, int off, int len) {
     76     checkPositionIndexes(off, off + len, bytes.length);
     77     update(bytes, off, len);
     78     return this;
     79   }
     80 
     81   /**
     82    * Updates the sink with the given number of bytes from the buffer.
     83    */
     84   private Hasher update(int bytes) {
     85     try {
     86       update(scratch.array(), 0, bytes);
     87     } finally {
     88       scratch.clear();
     89     }
     90     return this;
     91   }
     92 
     93   @Override
     94   public Hasher putShort(short s) {
     95     scratch.putShort(s);
     96     return update(Shorts.BYTES);
     97   }
     98 
     99   @Override
    100   public Hasher putInt(int i) {
    101     scratch.putInt(i);
    102     return update(Ints.BYTES);
    103   }
    104 
    105   @Override
    106   public Hasher putLong(long l) {
    107     scratch.putLong(l);
    108     return update(Longs.BYTES);
    109   }
    110 
    111   @Override
    112   public Hasher putChar(char c) {
    113     scratch.putChar(c);
    114     return update(Chars.BYTES);
    115   }
    116 
    117   @Override
    118   public <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
    119     funnel.funnel(instance, this);
    120     return this;
    121   }
    122 }
    123