gonum.org/v1/gonum@v0.14.0/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 max(a, b uint8) uint8 { 40 if a > b { 41 return a 42 } 43 return b 44 } 45 46 func min(a, b uint8) uint8 { 47 if a < b { 48 return a 49 } 50 return b 51 } 52 53 func typeNameOf(v interface{}) string { 54 t := reflect.TypeOf(v) 55 var prefix string 56 if t.Kind() == reflect.Ptr { 57 t = t.Elem() 58 prefix = "*" 59 } 60 if t.PkgPath() == "" { 61 return prefix + t.Name() 62 } 63 return prefix + t.PkgPath() + "." + t.Name() 64 } 65 66 // hashes holds registered hashes. 67 var hashes sync.Map // map[string]userType 68 69 type userType struct { 70 fn reflect.Value // Holds a func() hash.Hash{32,64}. 71 typ reflect.Type // Type of the returned hash implementation. 72 } 73 74 // RegisterHash registers a function that returns a new hash.Hash32 or hash.Hash64 75 // to the name of the type implementing the interface. The value of fn must be a 76 // func() hash.Hash32 or func() hash.Hash64, otherwise RegisterHash will panic. 77 // RegisterHash will panic if there is not a unique mapping from the name to the 78 // returned type. 79 func RegisterHash(fn interface{}) { 80 const invalidType = "card: must register func() hash.Hash32 or func() hash.Hash64" 81 82 rf := reflect.ValueOf(fn) 83 rt := rf.Type() 84 if rf.Kind() != reflect.Func { 85 panic(invalidType) 86 } 87 if rt.NumIn() != 0 { 88 panic(invalidType) 89 } 90 if rt.NumOut() != 1 { 91 panic(invalidType) 92 } 93 h := rf.Call(nil)[0].Interface() 94 var name string 95 var h32 hash.Hash32 96 var h64 hash.Hash64 97 switch rf.Type().Out(0) { 98 case reflect.TypeOf(&h32).Elem(), reflect.TypeOf(&h64).Elem(): 99 name = typeNameOf(h) 100 default: 101 panic(invalidType) 102 } 103 user := userType{fn: rf, typ: reflect.TypeOf(h)} 104 ut, dup := hashes.LoadOrStore(name, user) 105 stored := ut.(userType) 106 if dup && stored.typ != user.typ { 107 panic(fmt.Sprintf("card: registering duplicate types for %q: %s != %s", name, stored.typ, user.typ)) 108 } 109 }