-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathchd.go
131 lines (105 loc) · 2.49 KB
/
chd.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
124
125
126
127
128
129
130
131
// Package chd implements the compress, hash, and displace (CHD) minimal perfect
// hash algorithm. It provides a map builder that manages adding of items and
// map creation.
//
// See http://cmph.sourceforge.net/papers/esa09.pdf for more details.
package chd
import (
"bytes"
"encoding/gob"
"fmt"
"io"
)
// Map represents a map that uses
// CHD minimal perfect hash algorithm.
type Map struct {
seed [2]uint64
length int
tableSize int
hashes CompactArray
}
// NewMap returns an empty map.
// Call Map.Read to populate it.
func NewMap() *Map {
return &Map{}
}
// Get returns the index of a given key. This will
// always return a value in the range [0, Map.Cap())
// even if the key is not found. It is up to the user
// to validate the returned index.
func (m *Map) Get(key []byte) int {
if m.length == 0 {
return 0
}
h1, h2, h3, _ := spookyHash(key, m.seed[0], m.seed[1])
hashes := m.hashes
hlen := uint64(hashes.Len())
hidx := uint64(hashes.Get(int(h1 % hlen)))
tableSize := uint64(m.tableSize)
h2 %= tableSize
h3 %= tableSize
d0 := hidx / tableSize
d1 := hidx % tableSize
idx := int((h2 + (d0 * h3) + d1) % tableSize)
return idx
}
// Write serializes the map.
func (m *Map) Write(w io.Writer) error {
return gob.NewEncoder(w).Encode(m)
}
// Read deserializes a map.
func (m *Map) Read(r io.Reader) error {
return gob.NewDecoder(r).Decode(m)
}
// Len returns the total number of keys.
func (m *Map) Len() int {
return m.length
}
// Cap returns the total number of
// required bins to store the keys.
func (m *Map) Cap() int {
return m.tableSize
}
// Size returns the size in bytes.
func (m *Map) Size() int {
return m.hashes.Size()
}
// GobEncode transforms a map into gob streams.
func (m *Map) GobEncode() ([]byte, error) {
buf := &bytes.Buffer{}
enc := gob.NewEncoder(buf)
err := checkErr(
enc.Encode(m.seed),
enc.Encode(m.length),
enc.Encode(m.tableSize),
enc.Encode(m.hashes),
)
if err != nil {
err = fmt.Errorf("chd: encode failed (%v)", err)
}
return buf.Bytes(), err
}
// GobDecode decodes a map from gob streams.
func (m *Map) GobDecode(data []byte) error {
buf := bytes.NewReader(data)
dec := gob.NewDecoder(buf)
m.hashes = newCompactArray()
err := checkErr(
dec.Decode(&m.seed),
dec.Decode(&m.length),
dec.Decode(&m.tableSize),
dec.Decode(m.hashes),
)
if err != nil {
err = fmt.Errorf("chd: decode failed (%v)", err)
}
return err
}
func checkErr(err ...error) error {
for _, e := range err {
if e != nil {
return e
}
}
return nil
}