-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtrie.go
78 lines (59 loc) · 1.64 KB
/
trie.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
package canid
import (
"net"
)
// Trie for storing fast lookups of information by prefix.
// Not yet tested or integrated with canid.
type Trie struct {
sub [2]*Trie
data interface{}
}
// Return the prefix and data associated with a given IP address in the trie
func (t *Trie) Find(addr net.IP) (pfx net.IPNet, data interface{}, ok bool) {
addrmasks := [8]byte{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}
netmask := make([]byte, len(addr))
current := t
// and iterate
for pfxlen := 0; pfxlen < (len(addr) * 8); pfxlen++ {
// return data if the current trie node is a leaf
if current.data != nil {
cnetmask := net.IPMask(netmask)
return net.IPNet{addr.Mask(cnetmask), cnetmask}, current.data, true
}
// otherwise determine whether to go right or left
var branch int
if addr[pfxlen/8]&addrmasks[pfxlen%8] == 0 {
branch = 0
} else {
branch = 1
}
current = current.sub[branch]
// stop searching if nil
if current == nil {
break
}
// and move to the next bit
netmask[pfxlen/8] |= addrmasks[pfxlen%8]
}
return net.IPNet{}, nil, false
}
// Add a prefix to the trie and associate some data with it
func (t *Trie) Add(pfx net.IPNet, data interface{}) {
addrmasks := [8]byte{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}
current := t
subidx := 0
// first search to the bottom of the trie, creating nodes as necessary
for i := 0; pfx.Mask[i/8]&addrmasks[i%8] > 0; i++ {
if pfx.IP[i/8]&addrmasks[i%8] == 0 {
subidx = 0
} else {
subidx = 1
}
if current.sub[subidx] == nil {
current.sub[subidx] = new(Trie)
}
current = current.sub[subidx]
}
/* now add data */
current.data = data
}