1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package org.waarp.compress.zstdunsafe;
35
36 import static java.lang.Long.*;
37
38
39 final class XxHash64 {
40 private static final long PRIME64_1 = 0x9E3779B185EBCA87L;
41 private static final long PRIME64_2 = 0xC2B2AE3D27D4EB4FL;
42 private static final long PRIME64_3 = 0x165667B19E3779F9L;
43 private static final long PRIME64_4 = 0x85EBCA77C2b2AE63L;
44 private static final long PRIME64_5 = 0x27D4EB2F165667C5L;
45
46 private XxHash64() {
47 }
48
49 public static long hash(final long seed, final Object base,
50 final long address, final int length) {
51 long hash;
52 if (length >= 32) {
53 hash = updateBody(seed, base, address, length);
54 } else {
55 hash = seed + PRIME64_5;
56 }
57
58 hash += length;
59
60
61
62 final int index = length & 0xFFFFFFE0;
63
64 return updateTail(hash, base, address, index, length);
65 }
66
67 private static long updateTail(long hash, final Object base,
68 final long address, int index,
69 final int length) {
70 while (index <= length - 8) {
71 hash = updateTail(hash, UnsafeUtil.UNSAFE.getLong(base, address + index));
72 index += 8;
73 }
74
75 if (index <= length - 4) {
76 hash = updateTail(hash, UnsafeUtil.UNSAFE.getInt(base, address + index));
77 index += 4;
78 }
79
80 while (index < length) {
81 hash = updateTail(hash, UnsafeUtil.UNSAFE.getByte(base, address + index));
82 index++;
83 }
84
85 hash = finalShuffle(hash);
86
87 return hash;
88 }
89
90 private static long updateBody(final long seed, final Object base,
91 long address, final int length) {
92 long v1 = seed + PRIME64_1 + PRIME64_2;
93 long v2 = seed + PRIME64_2;
94 long v3 = seed;
95 long v4 = seed - PRIME64_1;
96
97 int remaining = length;
98 while (remaining >= 32) {
99 v1 = mix(v1, UnsafeUtil.UNSAFE.getLong(base, address));
100 v2 = mix(v2, UnsafeUtil.UNSAFE.getLong(base, address + 8));
101 v3 = mix(v3, UnsafeUtil.UNSAFE.getLong(base, address + 16));
102 v4 = mix(v4, UnsafeUtil.UNSAFE.getLong(base, address + 24));
103
104 address += 32;
105 remaining -= 32;
106 }
107
108 long hash = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) +
109 rotateLeft(v4, 18);
110
111 hash = update(hash, v1);
112 hash = update(hash, v2);
113 hash = update(hash, v3);
114 hash = update(hash, v4);
115
116 return hash;
117 }
118
119 private static long mix(final long current, final long value) {
120 return rotateLeft(current + value * PRIME64_2, 31) * PRIME64_1;
121 }
122
123 private static long update(final long hash, final long value) {
124 final long temp = hash ^ mix(0, value);
125 return temp * PRIME64_1 + PRIME64_4;
126 }
127
128 private static long updateTail(final long hash, final long value) {
129 final long temp = hash ^ mix(0, value);
130 return rotateLeft(temp, 27) * PRIME64_1 + PRIME64_4;
131 }
132
133 private static long updateTail(final long hash, final int value) {
134 final long unsigned = value & 0xFFFFFFFFL;
135 final long temp = hash ^ (unsigned * PRIME64_1);
136 return rotateLeft(temp, 23) * PRIME64_2 + PRIME64_3;
137 }
138
139 private static long updateTail(final long hash, final byte value) {
140 final int unsigned = value & 0xFF;
141 final long temp = hash ^ (unsigned * PRIME64_5);
142 return rotateLeft(temp, 11) * PRIME64_1;
143 }
144
145 private static long finalShuffle(long hash) {
146 hash ^= hash >>> 33;
147 hash *= PRIME64_2;
148 hash ^= hash >>> 29;
149 hash *= PRIME64_3;
150 hash ^= hash >>> 32;
151 return hash;
152 }
153 }