1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.codec.digest;
19
20 import static java.lang.Integer.rotateLeft;
21
22 import java.util.zip.Checksum;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 public class XXHash32 implements Checksum {
39
40 private static final int BUF_SIZE = 16;
41 private static final int ROTATE_BITS = 13;
42
43 private static final int PRIME1 = (int) 2654435761L;
44 private static final int PRIME2 = (int) 2246822519L;
45 private static final int PRIME3 = (int) 3266489917L;
46 private static final int PRIME4 = 668265263;
47 private static final int PRIME5 = 374761393;
48
49
50
51
52
53
54
55
56 private static int getInt(final byte[] buffer, final int idx) {
57 return buffer[idx ] & 0xff |
58 (buffer[idx + 1] & 0xff) << 8 |
59 (buffer[idx + 2] & 0xff) << 16 |
60 (buffer[idx + 3] & 0xff) << 24;
61 }
62 private final byte[] oneByte = new byte[1];
63 private final int[] state = new int[4];
64
65
66 private final byte[] buffer = new byte[BUF_SIZE];
67
68 private final int seed;
69 private int totalLen;
70
71 private int pos;
72
73
74 private boolean stateUpdated;
75
76
77
78
79 public XXHash32() {
80 this(0);
81 }
82
83
84
85
86
87
88 public XXHash32(final int seed) {
89 this.seed = seed;
90 initializeState();
91 }
92
93 @Override
94 public long getValue() {
95 int hash;
96 if (stateUpdated) {
97
98 hash =
99 rotateLeft(state[0], 1) +
100 rotateLeft(state[1], 7) +
101 rotateLeft(state[2], 12) +
102 rotateLeft(state[3], 18);
103 } else {
104
105 hash = state[2] + PRIME5;
106 }
107 hash += totalLen;
108 int idx = 0;
109 final int limit = pos - 4;
110 for (; idx <= limit; idx += 4) {
111 hash = rotateLeft(hash + getInt(buffer, idx) * PRIME3, 17) * PRIME4;
112 }
113 while (idx < pos) {
114 hash = rotateLeft(hash + (buffer[idx++] & 0xff) * PRIME5, 11) * PRIME1;
115 }
116 hash ^= hash >>> 15;
117 hash *= PRIME2;
118 hash ^= hash >>> 13;
119 hash *= PRIME3;
120 hash ^= hash >>> 16;
121 return hash & 0xffffffffL;
122 }
123
124 private void initializeState() {
125 state[0] = seed + PRIME1 + PRIME2;
126 state[1] = seed + PRIME2;
127 state[2] = seed;
128 state[3] = seed - PRIME1;
129 }
130
131 private void process(final byte[] b, final int offset) {
132
133 int s0 = state[0];
134 int s1 = state[1];
135 int s2 = state[2];
136 int s3 = state[3];
137 s0 = rotateLeft(s0 + getInt(b, offset) * PRIME2, ROTATE_BITS) * PRIME1;
138 s1 = rotateLeft(s1 + getInt(b, offset + 4) * PRIME2, ROTATE_BITS) * PRIME1;
139 s2 = rotateLeft(s2 + getInt(b, offset + 8) * PRIME2, ROTATE_BITS) * PRIME1;
140 s3 = rotateLeft(s3 + getInt(b, offset + 12) * PRIME2, ROTATE_BITS) * PRIME1;
141 state[0] = s0;
142 state[1] = s1;
143 state[2] = s2;
144 state[3] = s3;
145 stateUpdated = true;
146 }
147
148 @Override
149 public void reset() {
150 initializeState();
151 totalLen = 0;
152 pos = 0;
153 stateUpdated = false;
154 }
155
156 @Override
157 public void update(final byte[] b, int off, final int len) {
158 if (len <= 0) {
159 return;
160 }
161 totalLen += len;
162 final int end = off + len;
163
164
165
166 if (pos + len - BUF_SIZE < 0) {
167 System.arraycopy(b, off, buffer, pos, len);
168 pos += len;
169 return;
170 }
171
172 if (pos > 0) {
173 final int size = BUF_SIZE - pos;
174 System.arraycopy(b, off, buffer, pos, size);
175 process(buffer, 0);
176 off += size;
177 }
178 final int limit = end - BUF_SIZE;
179 while (off <= limit) {
180 process(b, off);
181 off += BUF_SIZE;
182 }
183
184 if (off < end) {
185 pos = end - off;
186 System.arraycopy(b, off, buffer, 0, pos);
187 } else {
188 pos = 0;
189 }
190 }
191
192 @Override
193 public void update(final int b) {
194 oneByte[0] = (byte) (b & 0xff);
195 update(oneByte, 0, 1);
196 }
197 }