1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.hash; 16 17 import static com.google.common.base.Preconditions.checkArgument; 18 import static com.google.common.base.Preconditions.checkNotNull; 19 20 import com.google.errorprone.annotations.Immutable; 21 import java.nio.ByteBuffer; 22 import java.nio.charset.Charset; 23 import org.checkerframework.checker.nullness.qual.Nullable; 24 25 /** 26 * An abstract composition of multiple hash functions. {@linkplain #newHasher()} delegates to the 27 * {@code Hasher} objects of the delegate hash functions, and in the end, they are used by 28 * {@linkplain #makeHash(Hasher[])} that constructs the final {@code HashCode}. 29 * 30 * @author Dimitris Andreou 31 */ 32 @Immutable 33 @ElementTypesAreNonnullByDefault 34 abstract class AbstractCompositeHashFunction extends AbstractHashFunction { 35 36 @SuppressWarnings("Immutable") // array not modified after creation 37 final HashFunction[] functions; 38 AbstractCompositeHashFunction(HashFunction... functions)39 AbstractCompositeHashFunction(HashFunction... functions) { 40 for (HashFunction function : functions) { 41 checkNotNull(function); 42 } 43 this.functions = functions; 44 } 45 46 /** 47 * Constructs a {@code HashCode} from the {@code Hasher} objects of the functions. Each of them 48 * has consumed the entire input and they are ready to output a {@code HashCode}. The order of the 49 * hashers are the same order as the functions given to the constructor. 50 */ 51 // this could be cleaner if it passed HashCode[], but that would create yet another array... makeHash(Hasher[] hashers)52 /* protected */ abstract HashCode makeHash(Hasher[] hashers); 53 54 @Override newHasher()55 public Hasher newHasher() { 56 Hasher[] hashers = new Hasher[functions.length]; 57 for (int i = 0; i < hashers.length; i++) { 58 hashers[i] = functions[i].newHasher(); 59 } 60 return fromHashers(hashers); 61 } 62 63 @Override newHasher(int expectedInputSize)64 public Hasher newHasher(int expectedInputSize) { 65 checkArgument(expectedInputSize >= 0); 66 Hasher[] hashers = new Hasher[functions.length]; 67 for (int i = 0; i < hashers.length; i++) { 68 hashers[i] = functions[i].newHasher(expectedInputSize); 69 } 70 return fromHashers(hashers); 71 } 72 fromHashers(final Hasher[] hashers)73 private Hasher fromHashers(final Hasher[] hashers) { 74 return new Hasher() { 75 @Override 76 public Hasher putByte(byte b) { 77 for (Hasher hasher : hashers) { 78 hasher.putByte(b); 79 } 80 return this; 81 } 82 83 @Override 84 public Hasher putBytes(byte[] bytes) { 85 for (Hasher hasher : hashers) { 86 hasher.putBytes(bytes); 87 } 88 return this; 89 } 90 91 @Override 92 public Hasher putBytes(byte[] bytes, int off, int len) { 93 for (Hasher hasher : hashers) { 94 hasher.putBytes(bytes, off, len); 95 } 96 return this; 97 } 98 99 @Override 100 public Hasher putBytes(ByteBuffer bytes) { 101 int pos = bytes.position(); 102 for (Hasher hasher : hashers) { 103 Java8Compatibility.position(bytes, pos); 104 hasher.putBytes(bytes); 105 } 106 return this; 107 } 108 109 @Override 110 public Hasher putShort(short s) { 111 for (Hasher hasher : hashers) { 112 hasher.putShort(s); 113 } 114 return this; 115 } 116 117 @Override 118 public Hasher putInt(int i) { 119 for (Hasher hasher : hashers) { 120 hasher.putInt(i); 121 } 122 return this; 123 } 124 125 @Override 126 public Hasher putLong(long l) { 127 for (Hasher hasher : hashers) { 128 hasher.putLong(l); 129 } 130 return this; 131 } 132 133 @Override 134 public Hasher putFloat(float f) { 135 for (Hasher hasher : hashers) { 136 hasher.putFloat(f); 137 } 138 return this; 139 } 140 141 @Override 142 public Hasher putDouble(double d) { 143 for (Hasher hasher : hashers) { 144 hasher.putDouble(d); 145 } 146 return this; 147 } 148 149 @Override 150 public Hasher putBoolean(boolean b) { 151 for (Hasher hasher : hashers) { 152 hasher.putBoolean(b); 153 } 154 return this; 155 } 156 157 @Override 158 public Hasher putChar(char c) { 159 for (Hasher hasher : hashers) { 160 hasher.putChar(c); 161 } 162 return this; 163 } 164 165 @Override 166 public Hasher putUnencodedChars(CharSequence chars) { 167 for (Hasher hasher : hashers) { 168 hasher.putUnencodedChars(chars); 169 } 170 return this; 171 } 172 173 @Override 174 public Hasher putString(CharSequence chars, Charset charset) { 175 for (Hasher hasher : hashers) { 176 hasher.putString(chars, charset); 177 } 178 return this; 179 } 180 181 @Override 182 public <T extends @Nullable Object> Hasher putObject( 183 @ParametricNullness T instance, Funnel<? super T> funnel) { 184 for (Hasher hasher : hashers) { 185 hasher.putObject(instance, funnel); 186 } 187 return this; 188 } 189 190 @Override 191 public HashCode hash() { 192 return makeHash(hashers); 193 } 194 }; 195 } 196 197 private static final long serialVersionUID = 0L; 198 } 199