gonum.org/v1/gonum@v0.15.1-0.20240517103525-f853624cb1bb/stat/card/card.go (about) 1 // Copyright ©2019 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:generate ./generate_64bit.sh 6 7 package card 8 9 import ( 10 "fmt" 11 "hash" 12 "math" 13 "reflect" 14 "sync" 15 ) 16 17 const ( 18 w32 = 32 19 w64 = 64 20 ) 21 22 func alpha(m uint64) float64 { 23 if m < 128 { 24 return alphaValues[m] 25 } 26 return 0.7213 / (1 + 1.079/float64(m)) 27 } 28 29 var alphaValues = [...]float64{ 30 16: 0.673, 31 32: 0.697, 32 64: 0.709, 33 } 34 35 func linearCounting(m, v float64) float64 { 36 return m * (math.Log(m) - math.Log(v)) 37 } 38 39 func typeNameOf(v interface{}) string { 40 t := reflect.TypeOf(v) 41 var prefix string 42 if t.Kind() == reflect.Ptr { 43 t = t.Elem() 44 prefix = "*" 45 } 46 if t.PkgPath() == "" { 47 return prefix + t.Name() 48 } 49 return prefix + t.PkgPath() + "." + t.Name() 50 } 51 52 // hashes holds registered hashes. 53 var hashes sync.Map // map[string]userType 54 55 type userType struct { 56 fn reflect.Value // Holds a func() hash.Hash{32,64}. 57 typ reflect.Type // Type of the returned hash implementation. 58 } 59 60 // RegisterHash registers a function that returns a new hash.Hash32 or hash.Hash64 61 // to the name of the type implementing the interface. The value of fn must be a 62 // func() hash.Hash32 or func() hash.Hash64, otherwise RegisterHash will panic. 63 // RegisterHash will panic if there is not a unique mapping from the name to the 64 // returned type. 65 func RegisterHash(fn interface{}) { 66 const invalidType = "card: must register func() hash.Hash32 or func() hash.Hash64" 67 68 rf := reflect.ValueOf(fn) 69 rt := rf.Type() 70 if rf.Kind() != reflect.Func { 71 panic(invalidType) 72 } 73 if rt.NumIn() != 0 { 74 panic(invalidType) 75 } 76 if rt.NumOut() != 1 { 77 panic(invalidType) 78 } 79 h := rf.Call(nil)[0].Interface() 80 var name string 81 var h32 hash.Hash32 82 var h64 hash.Hash64 83 switch rf.Type().Out(0) { 84 case reflect.TypeOf(&h32).Elem(), reflect.TypeOf(&h64).Elem(): 85 name = typeNameOf(h) 86 default: 87 panic(invalidType) 88 } 89 user := userType{fn: rf, typ: reflect.TypeOf(h)} 90 ut, dup := hashes.LoadOrStore(name, user) 91 stored := ut.(userType) 92 if dup && stored.typ != user.typ { 93 panic(fmt.Sprintf("card: registering duplicate types for %q: %s != %s", name, stored.typ, user.typ)) 94 } 95 }