Implement Hash for *big.Int and *big.Rat.

This commit is contained in:
Qi Xiao 2021-06-27 17:01:12 +01:00
parent 4afab8804b
commit a12e1be189
2 changed files with 21 additions and 1 deletions

View File

@ -2,6 +2,7 @@ package vals
import (
"math"
"math/big"
"reflect"
"src.elv.sh/pkg/persistent/hash"
@ -24,7 +25,16 @@ func Hash(v interface{}) uint32 {
return 1
}
return 0
// TODO: Add support for the other num types: int, *big.Int, *big.Rat.
case int:
return hash.UIntPtr(uintptr(v))
case *big.Int:
h := hash.DJBCombine(hash.DJBInit, uint32(v.Sign()))
for _, word := range v.Bits() {
h = hash.DJBCombine(h, hash.UIntPtr(uintptr(word)))
}
return h
case *big.Rat:
return hash.DJB(Hash(v.Num()), Hash(v.Denom()))
case float64:
return hash.UInt64(math.Float64bits(v))
case string:

View File

@ -2,8 +2,10 @@ package vals
import (
"math"
"math/big"
"os"
"testing"
"unsafe"
"src.elv.sh/pkg/persistent/hash"
. "src.elv.sh/pkg/tt"
@ -16,9 +18,17 @@ func (hasher) Hash() uint32 { return 42 }
type nonHasher struct{}
func TestHash(t *testing.T) {
z := big.NewInt(5)
z.Lsh(z, 8*uint(unsafe.Sizeof(int(0))))
z.Add(z, big.NewInt(9))
// z = 5 << wordSize + 9
Test(t, Fn("Hash", Hash), Table{
Args(false).Rets(uint32(0)),
Args(true).Rets(uint32(1)),
Args(1).Rets(uint32(1)),
Args(z).Rets(hash.DJB(1, 9, 5)),
Args(big.NewRat(3, 2)).Rets(hash.DJB(Hash(big.NewInt(3)), Hash(big.NewInt(2)))),
Args(1.0).Rets(hash.UInt64(math.Float64bits(1.0))),
Args("foo").Rets(hash.String("foo")),
Args(os.Stdin).Rets(hash.UIntPtr(os.Stdin.Fd())),