001/* 002 * Copyright (C) 2011 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.hash; 016 017import static com.google.common.base.Preconditions.checkArgument; 018import static com.google.common.base.Preconditions.checkNotNull; 019import static com.google.common.base.Preconditions.checkState; 020 021import com.google.common.annotations.Beta; 022import com.google.common.primitives.UnsignedInts; 023 024import java.io.Serializable; 025 026/** 027 * Static factories for creating {@link HashCode} instances; most users should never have to use 028 * this. All returned instances are {@link Serializable}. 029 * 030 * @author Dimitris Andreou 031 * @since 12.0 032 */ 033@Beta 034public final class HashCodes { 035 private HashCodes() {} 036 037 /** 038 * Creates a 32-bit {@code HashCode}, of which the bytes will form the passed int, interpreted 039 * in little endian order. 040 */ 041 public static HashCode fromInt(int hash) { 042 return new IntHashCode(hash); 043 } 044 045 private static final class IntHashCode extends HashCode implements Serializable { 046 final int hash; 047 048 IntHashCode(int hash) { 049 this.hash = hash; 050 } 051 052 @Override public int bits() { 053 return 32; 054 } 055 056 @Override public byte[] asBytes() { 057 return new byte[] { 058 (byte) hash, 059 (byte) (hash >> 8), 060 (byte) (hash >> 16), 061 (byte) (hash >> 24)}; 062 } 063 064 @Override public int asInt() { 065 return hash; 066 } 067 068 @Override public long asLong() { 069 throw new IllegalStateException("this HashCode only has 32 bits; cannot create a long"); 070 } 071 072 @Override 073 public long padToLong() { 074 return UnsignedInts.toLong(hash); 075 } 076 077 private static final long serialVersionUID = 0; 078 } 079 080 /** 081 * Creates a 64-bit {@code HashCode}, of which the bytes will form the passed long, interpreted 082 * in little endian order. 083 */ 084 public static HashCode fromLong(long hash) { 085 return new LongHashCode(hash); 086 } 087 088 private static final class LongHashCode extends HashCode implements Serializable { 089 final long hash; 090 091 LongHashCode(long hash) { 092 this.hash = hash; 093 } 094 095 @Override public int bits() { 096 return 64; 097 } 098 099 @Override public byte[] asBytes() { 100 return new byte[] { 101 (byte) hash, 102 (byte) (hash >> 8), 103 (byte) (hash >> 16), 104 (byte) (hash >> 24), 105 (byte) (hash >> 32), 106 (byte) (hash >> 40), 107 (byte) (hash >> 48), 108 (byte) (hash >> 56)}; 109 } 110 111 @Override public int asInt() { 112 return (int) hash; 113 } 114 115 @Override public long asLong() { 116 return hash; 117 } 118 119 @Override 120 public long padToLong() { 121 return hash; 122 } 123 124 private static final long serialVersionUID = 0; 125 } 126 127 /** 128 * Creates a {@code HashCode} from a byte array. The array is defensively copied to preserve 129 * the immutability contract of {@code HashCode}. The array cannot be empty. 130 */ 131 public static HashCode fromBytes(byte[] bytes) { 132 checkArgument(bytes.length >= 1, "A HashCode must contain at least 1 byte."); 133 return fromBytesNoCopy(bytes.clone()); 134 } 135 136 /** 137 * Creates a {@code HashCode} from a byte array. The array is <i>not</i> copied defensively, 138 * so it must be handed-off so as to preserve the immutability contract of {@code HashCode}. 139 */ 140 static HashCode fromBytesNoCopy(byte[] bytes) { 141 return new BytesHashCode(bytes); 142 } 143 144 private static final class BytesHashCode extends HashCode implements Serializable { 145 final byte[] bytes; 146 147 BytesHashCode(byte[] bytes) { 148 this.bytes = checkNotNull(bytes); 149 } 150 151 @Override public int bits() { 152 return bytes.length * 8; 153 } 154 155 @Override public byte[] asBytes() { 156 return bytes.clone(); 157 } 158 159 @Override public int asInt() { 160 checkState(bytes.length >= 4, 161 "HashCode#asInt() requires >= 4 bytes (it only has %s bytes).", bytes.length); 162 return (bytes[0] & 0xFF) 163 | ((bytes[1] & 0xFF) << 8) 164 | ((bytes[2] & 0xFF) << 16) 165 | ((bytes[3] & 0xFF) << 24); 166 } 167 168 @Override public long asLong() { 169 checkState(bytes.length >= 8, 170 "HashCode#asLong() requires >= 8 bytes (it only has %s bytes).", bytes.length); 171 return (bytes[0] & 0xFFL) 172 | ((bytes[1] & 0xFFL) << 8) 173 | ((bytes[2] & 0xFFL) << 16) 174 | ((bytes[3] & 0xFFL) << 24) 175 | ((bytes[4] & 0xFFL) << 32) 176 | ((bytes[5] & 0xFFL) << 40) 177 | ((bytes[6] & 0xFFL) << 48) 178 | ((bytes[7] & 0xFFL) << 56); 179 } 180 181 @Override 182 public long padToLong() { 183 return (bytes.length < 8) ? UnsignedInts.toLong(asInt()) : asLong(); 184 } 185 186 @Override 187 public int hashCode() { 188 if (bytes.length >= 4) { 189 return asInt(); 190 } else { 191 int val = (bytes[0] & 0xFF); 192 for (int i = 1; i < bytes.length; i++) { 193 val |= ((bytes[i] & 0xFF) << (i * 8)); 194 } 195 return val; 196 } 197 } 198 199 private static final long serialVersionUID = 0; 200 } 201}