Skip to content

Commit 2b8fa34

Browse files
committed
fix handler bugs, simplify structure
1 parent 2136500 commit 2b8fa34

File tree

1 file changed

+97
-212
lines changed

1 file changed

+97
-212
lines changed

store.go

Lines changed: 97 additions & 212 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package routing
22

33
import (
4-
"fmt"
5-
"math"
64
"regexp"
75
"strings"
86
)
@@ -21,8 +19,7 @@ type node struct {
2119
order int // the order at which the data was added. used to be pick the first one when matching multiple
2220
minOrder int // minimum order among all the child nodes and this node
2321

24-
children []*node // child static nodes, indexed by the first byte of each child key
25-
paramChildren []*node // child param nodes
22+
children []*node // child static nodes, indexed by the first byte of each child key
2623

2724
regex *regexp.Regexp // regular expression for a param node containing regular expression key
2825
paramIdx int // the parameter index, meaningful only for param node
@@ -33,257 +30,145 @@ type node struct {
3330
func newStore() *store {
3431
return &store{
3532
root: &node{
36-
static: true,
37-
children: make([]*node, 256),
38-
paramChildren: make([]*node, 0),
39-
paramIdx: -1,
40-
params: []string{},
33+
static: true,
34+
children: make([]*node, 256),
35+
paramIdx: -1,
36+
params: []string{},
4137
},
4238
}
4339
}
4440

4541
func (s *store) Add(key string, data interface{}) int {
4642
s.count++
47-
return s.root.add(key, data, s.count)
43+
return s.root.add(key, data)
4844
}
4945

50-
func (s *store) Get(path string, pvalues []string) (data interface{}, pnames []string) {
51-
data, pnames, _ = s.root.get(path, pvalues)
46+
func (s *store) Get(path string) (data interface{}) {
47+
data = s.root.get(path)
5248
return
5349
}
5450

55-
// Add adds a new node to the store with the given key and data
56-
func (n *node) add(key string, data interface{}, order int) int {
57-
matched := 0
51+
func (s *store) Count() int {
52+
return s.count
53+
}
5854

59-
// find the common prefix
60-
for ; matched < len(key) && matched < len(n.key); matched++ {
61-
if key[matched] != n.key[matched] {
62-
break
63-
}
55+
func (n *node) add(key string, data interface{}) int {
56+
if n.static {
57+
return n.addStatic(key, data)
6458
}
59+
return n.addParam(key, data)
60+
}
6561

66-
if matched == len(n.key) {
67-
if matched == len(key) {
68-
// the node key is the same as the key: make the current node as data node
69-
// if the node is already a data node, ignore the new data since we only care the first matched node
70-
if n.data == nil {
71-
n.data = data
72-
n.order = order
73-
}
74-
return n.paramIdx + 1
75-
}
76-
77-
// the node key is a prefix of the key: create a child node
78-
newKey := key[matched:]
62+
func (n *node) addStatic(key string, data interface{}) int {
63+
if len(key) == 0 {
64+
n.data = data
65+
return n.paramIdx
66+
}
7967

80-
// try adding to a static child
81-
if child := n.children[newKey[0]]; child != nil {
82-
if pn := child.add(newKey, data, order); pn >= 0 {
83-
return pn
84-
}
85-
}
86-
// try adding to a param child
87-
for _, child := range n.paramChildren {
88-
if pn := child.add(newKey, data, order); pn >= 0 {
89-
return pn
90-
}
68+
c := key[0]
69+
if n.children[c] == nil {
70+
n.children[c] = &node{
71+
static: true,
72+
children: make([]*node, 256),
73+
paramIdx: -1,
74+
params: append(n.params, n.key),
9175
}
92-
93-
return n.addChild(newKey, data, order)
9476
}
9577

96-
if matched == 0 || !n.static {
97-
// no common prefix, or partial common prefix with a non-static node: should skip this node
98-
return -1
99-
}
78+
return n.children[c].addStatic(key[1:], data)
79+
}
10080

101-
// the node key shares a partial prefix with the key: split the node key
102-
n1 := &node{
103-
static: true,
104-
key: n.key[matched:],
105-
data: n.data,
106-
order: n.order,
107-
minOrder: n.minOrder,
108-
paramChildren: n.paramChildren,
109-
children: n.children,
110-
paramIdx: n.paramIdx,
111-
params: n.params,
81+
func (n *node) addParam(key string, data interface{}) int {
82+
if len(key) == 0 {
83+
n.data = data
84+
return n.paramIdx
11285
}
11386

114-
n.key = key[0:matched]
115-
n.data = nil
116-
n.paramChildren = make([]*node, 0)
117-
n.children = make([]*node, 256)
118-
n.children[n1.key[0]] = n1
119-
120-
return n.add(key, data, order)
121-
}
122-
123-
// addChild creates static and param nodes to store the given data
124-
func (n *node) addChild(key string, data interface{}, order int) int {
125-
// find the first occurrence of a param token
12687
if key[0] == '/' {
12788
key = key[1:]
12889
}
129-
p0 := strings.Index(key, ":")
130-
if p0 == -1 {
131-
// no param tokens found: create a static node
132-
child := &node{
133-
static: true,
134-
key: key,
135-
minOrder: order,
136-
children: make([]*node, 256),
137-
paramChildren: make([]*node, 0),
138-
paramIdx: n.paramIdx,
139-
params: n.params,
140-
data: data,
141-
order: order,
142-
}
143-
n.children[key[0]] = child
144-
if n.data == nil {
145-
// if the node is already a data node, ignore the new data since we only care about the first matched node
146-
n.data = data
147-
n.order = order
148-
return n.paramIdx + 1
149-
}
150-
return child.paramIdx + 1
151-
}
152-
// param token found: create a static node for characters before the param token
153-
child := &node{
154-
static: true,
155-
key: key[:p0],
156-
minOrder: order,
157-
children: make([]*node, 256),
158-
paramChildren: make([]*node, 0),
159-
paramIdx: n.paramIdx,
160-
params: n.params,
161-
}
162-
n.children[key[0]] = child
163-
n = child
164-
key = key[p0:]
16590

166-
// add param node for the current param token
167-
p1 := strings.Index(key, "/")
168-
if p1 == -1 {
169-
// the param token is at the end of the key
170-
p1 = len(key)
171-
}
172-
pname := key[1:p1]
173-
pattern, err := regexp.Compile("[^/]+")
174-
if err != nil {
175-
// invalid param regex
176-
return -1
91+
idx := strings.IndexByte(key, '/')
92+
if idx == -1 {
93+
idx = len(key)
17794
}
178-
child = &node{
179-
static: false,
180-
key: pname,
181-
minOrder: order,
182-
children: make([]*node, 256),
183-
paramChildren: make([]*node, 0),
184-
paramIdx: n.paramIdx + len(n.paramChildren) + 1,
185-
params: append(n.params, pname),
186-
regex: pattern,
187-
}
188-
n.paramChildren = append(n.paramChildren, child)
18995

190-
if p1 == len(key) {
191-
// the param token is at the end of the key
192-
child.data = data
193-
child.order = order
194-
return child.paramIdx + 1
195-
}
96+
var child *node
97+
pathPart := key[:idx]
19698

197-
// process the rest of the key recursively
198-
n = child
199-
key = key[p1:]
200-
return n.addChild(key, data, order)
201-
}
99+
// Check if a child node with the path part exists
100+
for _, c := range n.children {
101+
if c.static && c.key == pathPart {
102+
child = c
103+
break
104+
}
105+
}
202106

203-
func (n *node) get(key string, pvalues []string) (data interface{}, pnames []string, order int) {
204-
order = math.MaxInt32
205-
for len(key) > 0 {
206-
if n.static {
207-
// check if the node key is a prefix of the given key
208-
// a slightly optimized version of strings.HasPrefix
209-
nkl := len(n.key)
210-
if nkl > len(key) || n.key != key[:nkl] {
211-
return
107+
// If no child node exists, create a new one
108+
if child == nil {
109+
if pathPart[0] == ':' { // parameterized segment
110+
child = &node{
111+
static: false,
112+
children: make([]*node, 1),
113+
paramIdx: n.paramIdx + 1,
114+
params: append(n.params, pathPart[1:]),
212115
}
213-
key = key[nkl:]
214-
} else if n.regex != nil {
215-
// param node with regular expression
216-
match := n.regex.FindStringIndex(key)
217-
if match == nil || match[0] != 0 {
218-
return
219-
}
220-
if n.paramIdx >= len(pvalues) {
221-
pvalues = append(pvalues, make([]string, n.paramIdx-len(pvalues)+1)...)
222-
}
223-
pvalues[n.paramIdx] = key[0:match[1]]
224-
key = key[match[1]:]
225-
} else {
226-
// param node matching non-"/" characters
227-
i := strings.IndexByte(key, '/')
228-
if i == -1 {
229-
if n.paramIdx >= len(pvalues) {
230-
pvalues = append(pvalues, make([]string, n.paramIdx-len(pvalues)+1)...)
231-
}
232-
pvalues[n.paramIdx] = key
233-
key = ""
234-
} else {
235-
if n.paramIdx >= len(pvalues) {
236-
pvalues = append(pvalues, make([]string, n.paramIdx-len(pvalues)+1)...)
237-
}
238-
pvalues[n.paramIdx] = key[:i]
239-
key = key[i:]
116+
} else { // static segment
117+
child = &node{
118+
static: true,
119+
key: pathPart,
120+
children: make([]*node, 256),
240121
}
241122
}
123+
n.children = append(n.children, child)
124+
}
242125

243-
// find a static child that can match the rest of the key
244-
if child := n.children[key[0]]; child != nil {
245-
if len(n.paramChildren) == 0 {
246-
// use iteration instead of recursion when there are no param children
247-
n = child
248-
continue
249-
}
250-
data, pnames, order = child.get(key, pvalues)
251-
}
126+
// Recurse into the child node with the remaining part of the key
127+
return child.addParam(key[idx:], data)
128+
}
252129

253-
break
130+
func (n *node) get(path string) (data interface{}) {
131+
if n.static {
132+
return n.getStatic(path)
254133
}
134+
return n.getParam(path)
135+
}
255136

256-
// capture data from this node, if any
257-
if n.data != nil && (len(key) == 0 || len(n.paramChildren) == 0 && n.static) {
258-
if n.order < order {
259-
data, pnames, order = n.data, n.params, n.order
260-
}
137+
func (n *node) getStatic(path string) (data interface{}) {
138+
if len(path) == 0 {
139+
return n.data
261140
}
262-
// try matching param children
263-
for _, child := range n.paramChildren {
264-
if child.minOrder >= order {
265-
continue
266-
}
267-
tvalues := make([]string, len(pvalues))
268-
copy(tvalues, pvalues)
269-
if d, p, s := child.get(key, tvalues); d != nil && s < order {
270-
data, pnames, order = d, p, s
271-
copy(pvalues[child.paramIdx:], tvalues[child.paramIdx:])
272-
}
141+
142+
c := path[0]
143+
if n.children[c] == nil {
144+
return nil
273145
}
274146

275-
return
147+
return n.children[c].getStatic(path[1:])
148+
}
149+
150+
func (n *node) getParam(path string) (data interface{}) {
151+
if len(path) == 0 {
152+
return n.data
153+
}
154+
155+
if n.children[0] == nil {
156+
return nil
157+
}
158+
159+
return n.children[0].getParam(path)
276160
}
277161

278-
func (n *node) print(level int) string {
279-
r := fmt.Sprintf("%v{key: %v, regex: %v, data: %v, order: %v, minOrder: %v, paramIdx: %v, params: %v}\n", strings.Repeat(" ", level<<2), n.key, n.regex, n.data, n.order, n.minOrder, n.paramIdx, n.params)
162+
func (n *node) String() string {
163+
return n.string("")
164+
}
165+
166+
func (n *node) string(indent string) string {
167+
s := indent + n.key + "\n"
280168
for _, child := range n.children {
281169
if child != nil {
282-
r += child.print(level + 1)
170+
s += child.string(indent + " ")
283171
}
284172
}
285-
for _, child := range n.paramChildren {
286-
r += child.print(level + 1)
287-
}
288-
return r
173+
return s
289174
}

0 commit comments

Comments
 (0)