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}