1/*
2 * Copyright (C) 2012 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
15package com.google.common.hash;
16
17import static com.google.common.base.Preconditions.checkArgument;
18import static com.google.common.base.Preconditions.checkNotNull;
19
20import com.google.common.base.Supplier;
21
22import java.io.Serializable;
23import java.util.zip.Checksum;
24
25/**
26 * {@link HashFunction} adapter for {@link Checksum} instances.
27 *
28 * @author Colin Decker
29 */
30final class ChecksumHashFunction extends AbstractStreamingHashFunction implements Serializable {
31
32  private final Supplier<? extends Checksum> checksumSupplier;
33  private final int bits;
34  private final String toString;
35
36  ChecksumHashFunction(Supplier<? extends Checksum> checksumSupplier, int bits, String toString) {
37    this.checksumSupplier = checkNotNull(checksumSupplier);
38    checkArgument(bits == 32 || bits == 64, "bits (%s) must be either 32 or 64", bits);
39    this.bits = bits;
40    this.toString = checkNotNull(toString);
41  }
42
43  @Override
44  public int bits() {
45    return bits;
46  }
47
48  @Override
49  public Hasher newHasher() {
50    return new ChecksumHasher(checksumSupplier.get());
51  }
52
53  @Override
54  public String toString() {
55    return toString;
56  }
57
58  /**
59   * Hasher that updates a checksum.
60   */
61  private final class ChecksumHasher extends AbstractByteHasher {
62
63    private final Checksum checksum;
64
65    private ChecksumHasher(Checksum checksum) {
66      this.checksum = checkNotNull(checksum);
67    }
68
69    @Override
70    protected void update(byte b) {
71      checksum.update(b);
72    }
73
74    @Override
75    protected void update(byte[] bytes, int off, int len) {
76      checksum.update(bytes, off, len);
77    }
78
79    @Override
80    public HashCode hash() {
81      long value = checksum.getValue();
82      if (bits == 32) {
83        /*
84         * The long returned from a 32-bit Checksum will have all 0s for its second word, so the
85         * cast won't lose any information and is necessary to return a HashCode of the correct
86         * size.
87         */
88        return HashCode.fromInt((int) value);
89      } else {
90        return HashCode.fromLong(value);
91      }
92    }
93  }
94
95  private static final long serialVersionUID = 0L;
96}
97