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    
015    package com.google.common.hash;
016    
017    import static com.google.common.base.Preconditions.checkArgument;
018    
019    import com.google.common.annotations.Beta;
020    
021    import 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
031    public 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        
050        @Override
051        public int bits() {
052          return 32;
053        }
054    
055        
056        @Override
057        public byte[] asBytes() {
058          return new byte[] {
059              (byte) hash,
060              (byte) (hash >> 8),
061              (byte) (hash >> 16),
062              (byte) (hash >> 24)};
063        }
064        
065        
066        @Override
067        public int asInt() {
068          return hash;
069        }
070    
071        
072        @Override
073        public long asLong() {
074          throw new IllegalStateException("this HashCode only has 32 bits; cannot create a long");
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        
096        @Override
097        public int bits() {
098          return 64;
099        }
100    
101        
102        @Override
103        public byte[] asBytes() {
104          return new byte[] {
105              (byte) hash,
106              (byte) (hash >> 8),
107              (byte) (hash >> 16),
108              (byte) (hash >> 24),
109              (byte) (hash >> 32),
110              (byte) (hash >> 40),
111              (byte) (hash >> 48),
112              (byte) (hash >> 56)};
113        }
114    
115        
116        @Override
117        public int asInt() {
118          return (int) hash;
119        }
120    
121        
122        @Override
123        public long asLong() {
124          return hash;
125        }
126        
127        private static final long serialVersionUID = 0;
128      }
129      
130      /**
131       * Creates a {@code HashCode} from a byte array. The array is defensively copied to preserve
132       * the immutability contract of {@code HashCode}. The array must be at least of length 4.
133       */
134      public static HashCode fromBytes(byte[] bytes) {
135        checkArgument(bytes.length >= 4, "A HashCode must contain at least 4 bytes.");
136        return fromBytesNoCopy(bytes.clone());
137      }
138    
139      /**
140       * Creates a {@code HashCode} from a byte array. The array is <i>not</i> copied defensively, 
141       * so it must be handed-off so as to preserve the immutability contract of {@code HashCode}.
142       * The array must be at least of length 4 (not checked).
143       */
144      static HashCode fromBytesNoCopy(byte[] bytes) {
145        return new BytesHashCode(bytes);
146      }
147      
148      private static final class BytesHashCode extends HashCode implements Serializable {
149        final byte[] bytes;
150        
151        BytesHashCode(byte[] bytes) {
152          this.bytes = bytes;
153        }
154    
155        
156        @Override
157        public int bits() {
158          return bytes.length * 8;
159        }
160    
161        
162        @Override
163        public byte[] asBytes() {
164          return bytes.clone();
165        }
166    
167        
168        @Override
169        public int asInt() {
170          return (bytes[0] & 0xFF)
171              | ((bytes[1] & 0xFF) << 8)
172              | ((bytes[2] & 0xFF) << 16)
173              | ((bytes[3] & 0xFF) << 24);
174        }
175    
176        
177        @Override
178        public long asLong() {
179          if (bytes.length < 8) {
180            // Checking this to throw the correct type of exception
181            throw new IllegalStateException("Not enough bytes");
182          }
183          return (bytes[0] & 0xFFL)
184              | ((bytes[1] & 0xFFL) << 8)
185              | ((bytes[2] & 0xFFL) << 16)
186              | ((bytes[3] & 0xFFL) << 24)
187              | ((bytes[4] & 0xFFL) << 32)
188              | ((bytes[5] & 0xFFL) << 40)
189              | ((bytes[6] & 0xFFL) << 48)
190              | ((bytes[7] & 0xFFL) << 56);
191        }
192        
193        private static final long serialVersionUID = 0;
194      }
195    }