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