-
Notifications
You must be signed in to change notification settings - Fork 0
/
xxh32.lua
172 lines (152 loc) · 3.57 KB
/
xxh32.lua
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
local prime1, prime2, prime3, prime4, prime5 = 0x9E3779B1, 0x85EBCA77, 0xC2B2AE3D, 0x27D4EB2F, 0x165667B1
local mask32 = 0xFFFFFFFF
local function rotl32(x, r)
x = x & mask32
return (((x) << (r)) | ((x) >> (32 - (r)))) & mask32
end
local function round(acc, input)
acc = acc + (input * prime2)
acc = acc & mask32
acc = rotl32(acc, 13)
acc = acc * prime1
acc = acc & mask32
return acc
end
local function avalanche(hash)
hash = hash & mask32
hash = hash ~ (hash >> 15)
hash = hash * prime2
hash = hash & mask32
hash = hash ~ (hash >> 13)
hash = hash * prime3
hash = hash & mask32
hash = hash ~ (hash >> 16)
return hash
end
local function xxh32_finalize(hash, str)
local len = #str & 15
local pos, bits = 1, 0
while len >= 4 do
bits, pos = string.unpack("I", str, pos)
hash = hash + (bits * prime3)
hash = hash & mask32
hash = rotl32(hash, 17) * prime4
len = len - 4
end
while len > 0 do
hash = hash + (str:byte(pos) * prime5)
hash = hash & mask32
hash = rotl32(hash, 11) * prime1
pos = pos + 1
len = len - 1
end
return avalanche(hash)
end
local function xxh32_endian_align(str, seed)
seed = seed or 0
local len = #str
local h32 = 0
local bits, pos = 0, 1
if len >= 16 then
local v1 = seed + prime1 + prime2
local v2 = seed + prime2
local v3 = seed
local v4 = seed - prime1
v1 = v1 & mask32
v2 = v2 & mask32
v3 = v3 & mask32
v4 = v4 & mask32
local limit = len - 15
repeat
bits, pos = string.unpack("<I", str, pos)
v1 = round(v1, bits)
bits, pos = string.unpack("<I", str, pos)
v2 = round(v2, bits)
bits, pos = string.unpack("<I", str, pos)
v3 = round(v3, bits)
bits, pos = string.unpack("<I", str, pos)
v4 = round(v4, bits)
--print(str:sub(pos))
until #str - pos + 1 < 16
h32 = rotl32(v1, 1) + rotl32(v2, 7) + rotl32(v3, 12) + rotl32(v4, 18)
else
h32 = seed + prime5
end
h32 = h32 + len
h32 = h32 & mask32
return xxh32_finalize(h32, str:sub(pos))
end
local state = {}
local function mask(st)
st.v1 = st.v1 & mask32
st.v2 = st.v2 & mask32
st.v3 = st.v3 & mask32
st.v4 = st.v4 & mask32
end
function state:reset(seed)
seed = seed or 0
self.v1 = seed + prime1 + prime2
self.v2 = seed + prime2
self.v3 = seed + 0
self.v4 = seed - prime1
mask(self)
end
function state:update(input)
if #input == 0 then return end
if #input + #self.buffer < 16 then
self.size = self.size + #input
self.buffer = self.buffer .. input
return
end
self.size = self.size + #input
input = self.buffer .. input
local data_len = #input - (#input & 15)
self.buffer = input:sub(data_len+1)
local data = input:sub(1, data_len)
local bits, pos = 0, 1
repeat
bits, pos = string.unpack("<I", input, pos)
self.v1 = round(self.v1, bits)
bits, pos = string.unpack("<I", input, pos)
self.v2 = round(self.v2, bits)
bits, pos = string.unpack("<I", input, pos)
self.v3 = round(self.v3, bits)
bits, pos = string.unpack("<I", input, pos)
self.v4 = round(self.v4, bits)
until #data - pos + 1 < 16
end
function state:digest(input)
if input then
self:update(input)
end
local h32 = 0
if self.size >= 16 then
h32 = rotl32(self.v1, 1) + rotl32(self.v2, 7) +
rotl32(self.v3, 12) + rotl32(self.v4, 18)
else
h32 = self.v3 + prime5
h32 = h32 & mask32
end
h32 = h32 + self.size
h32 = h32 & mask32
return xxh32_finalize(h32, self.buffer)
end
local function create_state(seed)
local s = {
v1 = 0,
v2 = 0,
v3 = 0,
v4 = 0,
buffer = "",
size = 0
}
setmetatable(s, {__index=state})
s:reset(seed)
return s
end
return {
state = create_state,
sum = function(str, seed)
return xxh32_endian_align(str, seed or 0)
end
}