@@ -5,6 +5,7 @@ const HASH_SECRET = tuple(
5
5
0x2d358dccaa6c78a5 ,
6
6
0x8bb84b93962eacc9 ,
7
7
0x4b33a62ed433d4a3 ,
8
+ 0xaaaaaaaaaaaaaaaa ,
8
9
)
9
10
10
11
"""
@@ -73,74 +74,76 @@ hash_integer(x::Integer, h::UInt) = _hash_integer(x, UInt64(h)) % UInt
73
74
function _hash_integer (
74
75
x:: Integer ,
75
76
seed:: UInt64 = HASH_SEED,
76
- secret:: NTuple{3 , UInt64} = HASH_SECRET
77
+ secret:: NTuple{4 , UInt64} = HASH_SECRET
77
78
)
78
79
seed ⊻= (x < 0 )
79
- u = abs (x)
80
+ u0 = abs (x) # n.b.: this hashes typemin(IntN) correctly even if abs fails
81
+ u = u0
80
82
81
83
# always left-pad to full byte
82
84
buflen = UInt (max (cld (top_set_bit (u), 8 ), 1 ))
83
- seed = seed ⊻ ( hash_mix (seed ⊻ secret[1 ], secret[2 ]) ⊻ buflen )
85
+ seed = seed ⊻ hash_mix (seed ⊻ secret[3 ], secret[2 ])
84
86
85
87
a = zero (UInt64)
86
88
b = zero (UInt64)
89
+ i = buflen
87
90
88
91
if buflen ≤ 16
89
92
if buflen ≥ 4
90
- a = (UInt64 (u % UInt32) << 32 ) |
91
- UInt64 ((u >>> ((buflen - 4 ) * 8 )) % UInt32)
92
-
93
- delta = (buflen & 24 ) >>> (buflen >>> 3 )
94
-
95
- b = (UInt64 ((u >>> (8 * delta)) % UInt32) << 32 ) |
96
- UInt64 ((u >>> (8 * (buflen - 4 - delta))) % UInt32)
93
+ seed ⊻= buflen
94
+ if buflen ≥ 8
95
+ a = UInt64 (u % UInt64)
96
+ b = UInt64 ((u >>> (8 * (buflen - 8 ))) % UInt64)
97
+ else
98
+ a = UInt64 (u % UInt32)
99
+ b = UInt64 ((u >>> (8 * (buflen - 4 ))) % UInt32)
100
+ end
97
101
else # buflen > 0
98
102
b0 = u % UInt8
99
103
b1 = (u >>> (8 * div (buflen, 2 ))) % UInt8
100
104
b2 = (u >>> (8 * (buflen - 1 ))) % UInt8
101
- a = (UInt64 (b0) << 56 ) |
102
- (UInt64 (b1) << 32 ) |
103
- UInt64 (b2)
105
+ a = (UInt64 (b0) << 45 ) | UInt64 (b2)
106
+ b = UInt64 (b1)
104
107
end
105
108
else
106
- a = (u >>> 8 (buflen - 16 )) % UInt
107
- b = (u >>> 8 (buflen - 8 )) % UInt
108
-
109
- i = buflen
110
109
if i > 48
111
110
see1 = seed
112
111
see2 = seed
113
- while i ≥ 48
114
- l0 = u % UInt ; u >>>= 64
115
- l1 = u % UInt ; u >>>= 64
116
- l2 = u % UInt ; u >>>= 64
117
- l3 = u % UInt ; u >>>= 64
118
- l4 = u % UInt ; u >>>= 64
119
- l5 = u % UInt ; u >>>= 64
112
+ while i > 48
113
+ l0 = u % UInt64 ; u >>>= 64
114
+ l1 = u % UInt64 ; u >>>= 64
115
+ l2 = u % UInt64 ; u >>>= 64
116
+ l3 = u % UInt64 ; u >>>= 64
117
+ l4 = u % UInt64 ; u >>>= 64
118
+ l5 = u % UInt64 ; u >>>= 64
120
119
121
120
seed = hash_mix (l0 ⊻ secret[1 ], l1 ⊻ seed)
122
121
see1 = hash_mix (l2 ⊻ secret[2 ], l3 ⊻ see1)
123
122
see2 = hash_mix (l4 ⊻ secret[3 ], l5 ⊻ see2)
124
123
i -= 48
125
124
end
126
- seed = seed ⊻ see1 ⊻ see2
125
+ seed ⊻= see1
126
+ seed ⊻= see2
127
127
end
128
128
if i > 16
129
- l0 = u % UInt ; u >>>= 64
130
- l1 = u % UInt ; u >>>= 64
131
- seed = hash_mix (l0 ⊻ secret[3 ], l1 ⊻ seed ⊻ secret[ 2 ] )
129
+ l0 = u % UInt64 ; u >>>= 64
130
+ l1 = u % UInt64 ; u >>>= 64
131
+ seed = hash_mix (l0 ⊻ secret[3 ], l1 ⊻ seed)
132
132
if i > 32
133
- l2 = u % UInt ; u >>>= 64
134
- l3 = u % UInt ; u >>>= 64
133
+ l2 = u % UInt64 ; u >>>= 64
134
+ l3 = u % UInt64 ; u >>>= 64
135
135
seed = hash_mix (l2 ⊻ secret[3 ], l3 ⊻ seed)
136
136
end
137
137
end
138
+
139
+ a = (u0 >>> 8 (buflen - 16 )) % UInt64 ⊻ i
140
+ b = (u0 >>> 8 (buflen - 8 )) % UInt64
138
141
end
139
142
140
143
a = a ⊻ secret[2 ]
141
144
b = b ⊻ seed
142
145
b, a = mul_parts (a, b)
143
- return hash_mix (a ⊻ secret[1 ] ⊻ buflen , b ⊻ secret[2 ])
146
+ return hash_mix (a ⊻ secret[4 ] , b ⊻ secret[2 ] ⊻ i )
144
147
end
145
148
146
149
@@ -266,43 +269,40 @@ hash(x::Symbol) = objectid(x)
266
269
load_le (:: Type{T} , ptr:: Ptr{UInt8} , i) where {T <: Union{UInt32, UInt64} } =
267
270
unsafe_load (convert (Ptr{T}, ptr + i - 1 ))
268
271
269
- function read_small (ptr:: Ptr{UInt8} , n:: Int )
270
- return (UInt64 (unsafe_load (ptr)) << 56 ) |
271
- (UInt64 (unsafe_load (ptr, div (n, 2 ) + 1 )) << 32 ) |
272
- UInt64 (unsafe_load (ptr, n))
273
- end
274
-
275
272
@assume_effects :terminates_globally function hash_bytes (
276
273
ptr:: Ptr{UInt8} ,
277
274
n:: Int ,
278
275
seed:: UInt64 ,
279
- secret:: NTuple{3 , UInt64}
276
+ secret:: NTuple{4 , UInt64}
280
277
)
281
278
# Adapted with gratitude from [rapidhash](https://github.com/Nicoshev/rapidhash)
282
279
buflen = UInt64 (n)
283
- seed = seed ⊻ ( hash_mix (seed ⊻ secret[1 ], secret[2 ]) ⊻ buflen )
280
+ seed = seed ⊻ hash_mix (seed ⊻ secret[3 ], secret[2 ])
284
281
285
282
a = zero (UInt64)
286
283
b = zero (UInt64)
284
+ i = buflen
287
285
288
286
if buflen ≤ 16
289
287
if buflen ≥ 4
290
- a = (UInt64 (load_le (UInt32, ptr, 1 )) << 32 ) |
291
- UInt64 (load_le (UInt32, ptr, n - 3 ))
292
-
293
- delta = (buflen & 24 ) >>> (buflen >>> 3 )
294
- b = (UInt64 (load_le (UInt32, ptr, delta + 1 )) << 32 ) |
295
- UInt64 (load_le (UInt32, ptr, n - 3 - delta))
288
+ seed ⊻= buflen
289
+ if buflen ≥ 8
290
+ a = load_le (UInt64, ptr, 1 )
291
+ b = load_le (UInt64, ptr, n - 7 )
292
+ else
293
+ a = UInt64 (load_le (UInt32, ptr, 1 ))
294
+ b = UInt64 (load_le (UInt32, ptr, n - 3 ))
295
+ end
296
296
elseif buflen > 0
297
- a = read_small (ptr, n)
297
+ a = (UInt64 (unsafe_load (ptr)) << 45 ) | UInt64 (unsafe_load (ptr, n))
298
+ b = UInt64 (unsafe_load (ptr, div (n, 2 ) + 1 ))
298
299
end
299
300
else
300
301
pos = 1
301
- i = buflen
302
302
if i > 48
303
303
see1 = seed
304
304
see2 = seed
305
- while i ≥ 48
305
+ while i > 48
306
306
seed = hash_mix (
307
307
load_le (UInt64, ptr, pos) ⊻ secret[1 ],
308
308
load_le (UInt64, ptr, pos + 8 ) ⊻ seed
@@ -318,12 +318,13 @@ end
318
318
pos += 48
319
319
i -= 48
320
320
end
321
- seed = seed ⊻ see1 ⊻ see2
321
+ seed ⊻= see1
322
+ seed ⊻= see2
322
323
end
323
324
if i > 16
324
325
seed = hash_mix (
325
326
load_le (UInt64, ptr, pos) ⊻ secret[3 ],
326
- load_le (UInt64, ptr, pos + 8 ) ⊻ seed ⊻ secret[ 2 ]
327
+ load_le (UInt64, ptr, pos + 8 ) ⊻ seed
327
328
)
328
329
if i > 32
329
330
seed = hash_mix (
@@ -333,14 +334,14 @@ end
333
334
end
334
335
end
335
336
336
- a = load_le (UInt64, ptr, n - 15 )
337
+ a = load_le (UInt64, ptr, n - 15 ) ⊻ i
337
338
b = load_le (UInt64, ptr, n - 7 )
338
339
end
339
340
340
341
a = a ⊻ secret[2 ]
341
342
b = b ⊻ seed
342
343
b, a = mul_parts (a, b)
343
- return hash_mix (a ⊻ secret[1 ] ⊻ buflen , b ⊻ secret[2 ])
344
+ return hash_mix (a ⊻ secret[4 ] , b ⊻ secret[2 ] ⊻ i )
344
345
end
345
346
346
347
@assume_effects :total hash (data:: String , h:: UInt ) =
0 commit comments