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 */ update(byte b)43 protected abstract void update(byte b); 44 45 /** 46 * Updates this hasher with the given bytes. 47 */ update(byte[] b)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 */ update(byte[] b, int off, int len)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 putByte(byte b)62 public Hasher putByte(byte b) { 63 update(b); 64 return this; 65 } 66 67 @Override putBytes(byte[] bytes)68 public Hasher putBytes(byte[] bytes) { 69 checkNotNull(bytes); 70 update(bytes); 71 return this; 72 } 73 74 @Override putBytes(byte[] bytes, int off, int len)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 */ update(int bytes)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 putShort(short s)94 public Hasher putShort(short s) { 95 scratch.putShort(s); 96 return update(Shorts.BYTES); 97 } 98 99 @Override putInt(int i)100 public Hasher putInt(int i) { 101 scratch.putInt(i); 102 return update(Ints.BYTES); 103 } 104 105 @Override putLong(long l)106 public Hasher putLong(long l) { 107 scratch.putLong(l); 108 return update(Longs.BYTES); 109 } 110 111 @Override putChar(char c)112 public Hasher putChar(char c) { 113 scratch.putChar(c); 114 return update(Chars.BYTES); 115 } 116 117 @Override putObject(T instance, Funnel<? super T> funnel)118 public <T> Hasher putObject(T instance, Funnel<? super T> funnel) { 119 funnel.funnel(instance, this); 120 return this; 121 } 122 } 123