trout
2015-12-13
Parent:bf38b050b6c4
trout/trie.go
Publish under MIT license. Add a license so this package can officially be used by any project, basically.
1 package trout
3 import (
4 "net/http"
5 "sort"
6 "sync"
7 )
9 type trie struct {
10 branch *branch
11 sync.RWMutex
12 }
14 func (t *trie) match(input []string) ([]int, bool) {
15 if t.branch == nil {
16 t.branch = &branch{}
17 }
18 b := t.branch
19 path := []int{}
20 offset := 0
21 num := len(input)
22 for i := 0; i < num; i++ {
23 // if we're on a nil branch, we're at the end of our line
24 if b == nil {
25 return path, false
26 }
27 offset = pickNextBranch(b, offset, input[i])
28 if offset == -1 {
29 if len(path) == 0 {
30 // can't find it, bail
31 return path, false
32 }
33 // no match, backup
34 path, offset = backup(path)
35 offset = offset + 1 // we want the next index from the previously matched one
36 b = b.parent // we need to be picking a branch from our parent, again
37 i = i - 2 // back up to the choice before the one that got us here
38 } else {
39 path = append(path, offset)
40 b = b.children[offset]
41 offset = 0
42 }
43 }
44 return path, true
45 }
47 type branch struct {
48 parent *branch
49 children []*branch
50 key string
51 isParam bool
52 methods map[string]http.Handler
53 }
55 func (b *branch) Less(i, j int) bool {
56 if b.children[i].key == b.children[j].key {
57 return b.children[j].isParam && !b.children[i].isParam
58 }
59 return b.children[i].key < b.children[j].key
60 }
62 func (b *branch) Len() int {
63 return len(b.children)
64 }
66 func (b *branch) Swap(i, j int) {
67 b.children[i], b.children[j] = b.children[j], b.children[i]
68 }
70 func (b *branch) addChild(key string, param bool) *branch {
71 child := &branch{key: key, parent: b, isParam: param}
72 if b.children == nil {
73 b.children = []*branch{child}
74 return child
75 }
76 b.children = append(b.children, child)
77 sort.Sort(b)
78 return child
79 }
81 func (b *branch) check(input string) bool {
82 if b.isParam && b.key != "" {
83 return true
84 }
85 if b.key == input {
86 return true
87 }
88 return false
89 }
91 func (b *branch) setHandler(method string, handler http.Handler) {
92 if b.methods == nil {
93 b.methods = map[string]http.Handler{}
94 }
95 b.methods[method] = handler
96 }
98 func pickNextBranch(b *branch, offset int, input string) int {
99 count := len(b.children)
100 for i := offset; i < count; i++ {
101 if b.children[i].check(input) {
102 return i
103 }
104 }
105 return -1
106 }
108 func backup(path []int) ([]int, int) {
109 last := len(path) - 1
110 pos := path[last]
111 path = path[:last]
112 return path, pos
113 }