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;
018
019import com.google.common.annotations.Beta;
020
021import java.io.Serializable;
022
023/**
024 * Static factories for creating {@link HashCode} instances; most users should never have to use
025 * this. All returned instances are {@link Serializable}.
026 *
027 * @author Dimitris Andreou
028 * @since 12.0
029 */
030@Beta
031public final class HashCodes {
032  private HashCodes() {}
033
034  /**
035   * Creates a 32-bit {@code HashCode}, of which the bytes will form the passed int, interpreted 
036   * in little endian order.
037   */
038  public static HashCode fromInt(int hash) {
039    return new IntHashCode(hash);
040  }
041  
042  private static final class IntHashCode extends HashCode implements Serializable {
043    final int hash;
044    
045    IntHashCode(int hash) {
046      this.hash = hash;
047    }
048
049    @Override public int bits() {
050      return 32;
051    }
052
053    @Override public byte[] asBytes() {
054      return new byte[] {
055          (byte) hash,
056          (byte) (hash >> 8),
057          (byte) (hash >> 16),
058          (byte) (hash >> 24)};
059    }
060    
061    @Override public int asInt() {
062      return hash;
063    }
064
065    @Override public long asLong() {
066      throw new IllegalStateException("this HashCode only has 32 bits; cannot create a long");
067    }
068    
069    private static final long serialVersionUID = 0;
070  }
071  
072  /**
073   * Creates a 64-bit {@code HashCode}, of which the bytes will form the passed long, interpreted 
074   * in little endian order.
075   */
076  public static HashCode fromLong(long hash) {
077    return new LongHashCode(hash);
078  }
079  
080  private static final class LongHashCode extends HashCode implements Serializable {
081    final long hash;
082    
083    LongHashCode(long hash) {
084      this.hash = hash;
085    }
086
087    @Override public int bits() {
088      return 64;
089    }
090
091    @Override public byte[] asBytes() {
092      return new byte[] {
093          (byte) hash,
094          (byte) (hash >> 8),
095          (byte) (hash >> 16),
096          (byte) (hash >> 24),
097          (byte) (hash >> 32),
098          (byte) (hash >> 40),
099          (byte) (hash >> 48),
100          (byte) (hash >> 56)};
101    }
102
103    @Override public int asInt() {
104      return (int) hash;
105    }
106
107    @Override public long asLong() {
108      return hash;
109    }
110    
111    private static final long serialVersionUID = 0;
112  }
113  
114  /**
115   * Creates a {@code HashCode} from a byte array. The array is defensively copied to preserve
116   * the immutability contract of {@code HashCode}. The array must be at least of length 4.
117   */
118  public static HashCode fromBytes(byte[] bytes) {
119    checkArgument(bytes.length >= 4, "A HashCode must contain at least 4 bytes.");
120    return fromBytesNoCopy(bytes.clone());
121  }
122
123  /**
124   * Creates a {@code HashCode} from a byte array. The array is <i>not</i> copied defensively, 
125   * so it must be handed-off so as to preserve the immutability contract of {@code HashCode}.
126   * The array must be at least of length 4 (not checked).
127   */
128  static HashCode fromBytesNoCopy(byte[] bytes) {
129    return new BytesHashCode(bytes);
130  }
131  
132  private static final class BytesHashCode extends HashCode implements Serializable {
133    final byte[] bytes;
134    
135    BytesHashCode(byte[] bytes) {
136      this.bytes = bytes;
137    }
138
139    @Override public int bits() {
140      return bytes.length * 8;
141    }
142
143    @Override public byte[] asBytes() {
144      return bytes.clone();
145    }
146
147    @Override public int asInt() {
148      return (bytes[0] & 0xFF)
149          | ((bytes[1] & 0xFF) << 8)
150          | ((bytes[2] & 0xFF) << 16)
151          | ((bytes[3] & 0xFF) << 24);
152    }
153
154    @Override public long asLong() {
155      if (bytes.length < 8) {
156        // Checking this to throw the correct type of exception
157        throw new IllegalStateException("Not enough bytes");
158      }
159      return (bytes[0] & 0xFFL)
160          | ((bytes[1] & 0xFFL) << 8)
161          | ((bytes[2] & 0xFFL) << 16)
162          | ((bytes[3] & 0xFFL) << 24)
163          | ((bytes[4] & 0xFFL) << 32)
164          | ((bytes[5] & 0xFFL) << 40)
165          | ((bytes[6] & 0xFFL) << 48)
166          | ((bytes[7] & 0xFFL) << 56);
167    }
168    
169    private static final long serialVersionUID = 0;
170  }
171}