Skip to content

Commit c0ecfe9

Browse files
authored
Follow-up to hashing BigInts; expand testing (#58714)
fixes #58711 closes #58712
1 parent a970e16 commit c0ecfe9

File tree

3 files changed

+47
-26
lines changed

3 files changed

+47
-26
lines changed

base/gmp.jl

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -853,12 +853,16 @@ if Limb === UInt64 === UInt
853853
using .Base: HASH_SECRET, hash_bytes, hash_finalizer
854854

855855
function hash_integer(n::BigInt, h::UInt)
856+
iszero(n) && return hash_integer(0, h)
856857
GC.@preserve n begin
857858
s = n.size
858859
h ⊻= (s < 0)
860+
861+
us = abs(s)
862+
leading_zero_bytes = div(leading_zeros(unsafe_load(n.d, us)), 8)
859863
hash_bytes(
860864
Ptr{UInt8}(n.d),
861-
8 * abs(s),
865+
8 * us - leading_zero_bytes,
862866
h,
863867
HASH_SECRET
864868
)
@@ -895,16 +899,14 @@ if Limb === UInt64 === UInt
895899
h = hash_integer(pow, h)
896900

897901
h ⊻= (sz < 0)
902+
leading_zero_bytes = div(leading_zeros(unsafe_load(x.d, asz)), 8)
898903
trailing_zero_bytes = div(pow, 8)
899-
GC.@preserve x begin
900-
h = hash_bytes(
901-
Ptr{UInt8}(x.d) + 8 * trailing_zero_bytes,
902-
8 * (asz - trailing_zero_bytes),
903-
h,
904-
HASH_SECRET
905-
)
906-
end
907-
return h
904+
return hash_bytes(
905+
Ptr{UInt8}(x.d) + trailing_zero_bytes,
906+
8 * asz - (leading_zero_bytes + trailing_zero_bytes),
907+
h,
908+
HASH_SECRET
909+
)
908910
end
909911
end
910912
end

base/hashing.jl

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,30 @@ function _hash_integer(
7878
seed ⊻= (x < 0)
7979
u = abs(x)
8080

81-
# always left-pad to multiple of 8 bytes
82-
buflen = UInt(cld(top_set_bit(u), 64) * 8)
81+
# always left-pad to full byte
82+
buflen = UInt(max(cld(top_set_bit(u), 8), 1))
8383
seed = seed (hash_mix(seed secret[1], secret[2]) buflen)
8484

8585
a = zero(UInt64)
8686
b = zero(UInt64)
8787

8888
if buflen 16
89-
a = (UInt64(u % UInt32) << 32) |
90-
UInt64((u >>> ((buflen - 4) * 8)) % UInt32)
89+
if buflen 4
90+
a = (UInt64(u % UInt32) << 32) |
91+
UInt64((u >>> ((buflen - 4) * 8)) % UInt32)
9192

92-
delta = (buflen & 24) >>> (buflen >>> 3)
93+
delta = (buflen & 24) >>> (buflen >>> 3)
9394

94-
b = (UInt64((u >>> (8 * delta)) % UInt32) << 32) |
95-
UInt64((u >>> (8 * (buflen - 4 - delta))) % UInt32)
95+
b = (UInt64((u >>> (8 * delta)) % UInt32) << 32) |
96+
UInt64((u >>> (8 * (buflen - 4 - delta))) % UInt32)
97+
else # buflen > 0
98+
b0 = u % UInt8
99+
b1 = (u >>> (8 * div(buflen, 2))) % UInt8
100+
b2 = (u >>> (8 * (buflen - 1))) % UInt8
101+
a = (UInt64(b0) << 56) |
102+
(UInt64(b1) << 32) |
103+
UInt64(b2)
104+
end
96105
else
97106
a = (u >>> 8(buflen - 16)) % UInt
98107
b = (u >>> 8(buflen - 8)) % UInt
@@ -112,9 +121,9 @@ function _hash_integer(
112121
seed = hash_mix(l0 secret[1], l1 seed)
113122
see1 = hash_mix(l2 secret[2], l3 see1)
114123
see2 = hash_mix(l4 secret[3], l5 see2)
124+
i -= 48
115125
end
116126
seed = seed see1 see2
117-
i -= 48
118127
end
119128
if i > 16
120129
l0 = u % UInt; u >>>= 64

test/gmp.jl

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -811,14 +811,24 @@ end
811811

812812
@testset "hashing" begin
813813
for i in 1:10:100
814-
for shift in 0:3
815-
bint = big(11)^i << shift
816-
bfloat = float(bint)
817-
@test (hash(bint) == hash(bfloat)) == (bint == bfloat)
818-
@test hash(bint, Base.HASH_SEED) ==
819-
@invoke(hash(bint::Real, Base.HASH_SEED))
820-
@test Base.hash_integer(bint, Base.HASH_SEED) ==
821-
@invoke(Base.hash_integer(bint::Integer, Base.HASH_SEED))
814+
for shift in vcat(0:8, 9:8:81)
815+
for sgn in (1, -1)
816+
bint = sgn * (big(11)^i << shift)
817+
bfloat = float(bint)
818+
@test (hash(bint) == hash(bfloat)) == (bint == bfloat)
819+
@test hash(bint, Base.HASH_SEED) ==
820+
@invoke(hash(bint::Real, Base.HASH_SEED))
821+
@test Base.hash_integer(bint, Base.HASH_SEED) ==
822+
@invoke(Base.hash_integer(bint::Integer, Base.HASH_SEED))
823+
end
822824
end
823825
end
826+
827+
bint = big(0)
828+
bfloat = float(bint)
829+
@test (hash(bint) == hash(bfloat)) == (bint == bfloat)
830+
@test hash(bint, Base.HASH_SEED) ==
831+
@invoke(hash(bint::Real, Base.HASH_SEED))
832+
@test Base.hash_integer(bint, Base.HASH_SEED) ==
833+
@invoke(Base.hash_integer(bint::Integer, Base.HASH_SEED))
824834
end

0 commit comments

Comments
 (0)