-
Notifications
You must be signed in to change notification settings - Fork 6
/
config.go
123 lines (110 loc) · 2.25 KB
/
config.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package cuckoo
// ConfigOption ...
//
// Composed Filter function type used for configuring a Filter
type ConfigOption func(*Filter)
// Cuckoo Filter notation
// e target false positive rate
// f fingerprint length in bits
// α load factor (0 ≤ α ≤ 1)
// b number of entries per bucket
// m number of buckets
// n number of items
// C average bits per item
const (
// Entries per bucket (b)
defaultBucketEntries uint = 24
// Bucket total (m) defaults to approx. 4 million
defaultBucketTotal uint = 1 << 22
// Length of fingreprint (f) set to log(n/b) ~6 bits
defaultFingerprintLength uint = 6
// Default attempts to find empty slot on insert
defaultKicks uint = 500
)
// BucketEntries ...
//
// Number of entries per bucket denoted as b
//
// Example:
//
// New(BucketEntries(uint(42)))
func BucketEntries(entries uint) ConfigOption {
return func(f *Filter) {
f.bucketEntries = entries
}
}
// BucketTotal ...
//
// Number of buckets in the Filter denoted as m
//
// Example:
//
// New(BucketTotal(uint(42)))
func BucketTotal(total uint) ConfigOption {
return func(f *Filter) {
f.bucketTotal = total
}
}
// FingerprintLength ...
//
// Length of the item fingerprint denoted as f
//
// Example:
//
// New(FingerprintLength(uint(4)))
func FingerprintLength(length uint) ConfigOption {
return func(f *Filter) {
if length > uint(16) {
length = uint(16)
}
f.fingerprintLength = length
}
}
// Kicks ...
//
// Maximum number of kicks to attempt when bucket collisions occur
//
// Example:
//
// New(Kicks(uint(200)))
func Kicks(kicks uint) ConfigOption {
return func(f *Filter) {
f.kicks = kicks
}
}
func capacity() ConfigOption {
return func(f *Filter) {
f.capacity = nextPowerOf2(uint64(f.bucketTotal)) / f.bucketEntries
if f.capacity <= 0 {
f.capacity = 1
}
}
}
func (f *Filter) configureDefaults() {
if f.bucketTotal <= 0 {
BucketTotal(defaultBucketTotal)(f)
}
if f.bucketEntries <= 0 {
BucketEntries(defaultBucketEntries)(f)
}
if f.fingerprintLength <= 0 {
FingerprintLength(defaultFingerprintLength)(f)
}
if f.kicks <= 0 {
Kicks(defaultKicks)(f)
}
if f.capacity < 1 {
capacity()(f)
}
}
func nextPowerOf2(n uint64) uint {
n--
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
n |= n >> 32
n++
return uint(n)
}